summaryrefslogtreecommitdiffstats
path: root/drivers/isdn
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /drivers/isdn
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'drivers/isdn')
-rw-r--r--drivers/isdn/.cvsignore2
-rw-r--r--drivers/isdn/Config.in32
-rw-r--r--drivers/isdn/Makefile14
-rw-r--r--drivers/isdn/act2000/.cvsignore2
-rw-r--r--drivers/isdn/avmb1/.cvsignore2
-rw-r--r--drivers/isdn/avmb1/Makefile58
-rw-r--r--drivers/isdn/avmb1/avmcard.h559
-rw-r--r--drivers/isdn/avmb1/b1.c693
-rw-r--r--drivers/isdn/avmb1/b1isa.c243
-rw-r--r--drivers/isdn/avmb1/b1pci.c283
-rw-r--r--drivers/isdn/avmb1/b1pcmcia.c272
-rw-r--r--drivers/isdn/avmb1/capi.c151
-rw-r--r--drivers/isdn/avmb1/capidev.h36
-rw-r--r--drivers/isdn/avmb1/capidrv.c430
-rw-r--r--drivers/isdn/avmb1/capilli.h110
-rw-r--r--drivers/isdn/avmb1/capiutil.c26
-rw-r--r--drivers/isdn/avmb1/kcapi.c1553
-rw-r--r--drivers/isdn/avmb1/t1isa.c550
-rw-r--r--drivers/isdn/divert/Makefile21
-rw-r--r--drivers/isdn/divert/divert_init.c110
-rw-r--r--drivers/isdn/divert/divert_procfs.c456
-rw-r--r--drivers/isdn/divert/isdn_divert.c911
-rw-r--r--drivers/isdn/divert/isdn_divert.h164
-rw-r--r--drivers/isdn/eicon/eicon.h164
-rw-r--r--drivers/isdn/eicon/eicon_dsp.h119
-rw-r--r--drivers/isdn/eicon/eicon_idi.c648
-rw-r--r--drivers/isdn/eicon/eicon_idi.h31
-rw-r--r--drivers/isdn/eicon/eicon_io.c258
-rw-r--r--drivers/isdn/eicon/eicon_isa.c19
-rw-r--r--drivers/isdn/eicon/eicon_mod.c474
-rw-r--r--drivers/isdn/eicon/eicon_pci.c37
-rw-r--r--drivers/isdn/hisax/.cvsignore2
-rw-r--r--drivers/isdn/hisax/Makefile60
-rw-r--r--drivers/isdn/hisax/amd7930.c12
-rw-r--r--drivers/isdn/hisax/arcofi.c150
-rw-r--r--drivers/isdn/hisax/arcofi.h19
-rw-r--r--drivers/isdn/hisax/asuscom.c54
-rw-r--r--drivers/isdn/hisax/avm_a1.c40
-rw-r--r--drivers/isdn/hisax/avm_a1p.c49
-rw-r--r--drivers/isdn/hisax/avm_pci.c87
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c410
-rw-r--r--drivers/isdn/hisax/bkm_a8.c536
-rw-r--r--drivers/isdn/hisax/bkm_ax.h133
-rw-r--r--drivers/isdn/hisax/callc.c1408
-rw-r--r--drivers/isdn/hisax/cert.c6
-rw-r--r--drivers/isdn/hisax/config.c568
-rw-r--r--drivers/isdn/hisax/diva.c674
-rw-r--r--drivers/isdn/hisax/elsa.c311
-rw-r--r--drivers/isdn/hisax/elsa_ser.c12
-rw-r--r--drivers/isdn/hisax/gazel.c758
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c38
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c18
-rw-r--r--drivers/isdn/hisax/hfc_pci.c1744
-rw-r--r--drivers/isdn/hisax/hfc_pci.h263
-rw-r--r--drivers/isdn/hisax/hfcscard.c206
-rw-r--r--drivers/isdn/hisax/hisax.h426
-rw-r--r--drivers/isdn/hisax/hscx.c19
-rw-r--r--drivers/isdn/hisax/hscx_irq.c11
-rw-r--r--drivers/isdn/hisax/isac.c270
-rw-r--r--drivers/isdn/hisax/isar.c359
-rw-r--r--drivers/isdn/hisax/isar.h159
-rw-r--r--drivers/isdn/hisax/isdnl1.c39
-rw-r--r--drivers/isdn/hisax/isdnl2.c1427
-rw-r--r--drivers/isdn/hisax/isdnl3.c161
-rw-r--r--drivers/isdn/hisax/isdnl3.h20
-rw-r--r--drivers/isdn/hisax/isurf.c270
-rw-r--r--drivers/isdn/hisax/ix1_micro.c40
-rw-r--r--drivers/isdn/hisax/jade.c326
-rw-r--r--drivers/isdn/hisax/jade.h137
-rw-r--r--drivers/isdn/hisax/jade_irq.c247
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c130
-rw-r--r--drivers/isdn/hisax/l3dss1.c2356
-rw-r--r--drivers/isdn/hisax/l3dss1.h137
-rw-r--r--drivers/isdn/hisax/lmgr.c7
-rw-r--r--drivers/isdn/hisax/md5sums.asc34
-rw-r--r--drivers/isdn/hisax/mic.c40
-rw-r--r--drivers/isdn/hisax/netjet.c165
-rw-r--r--drivers/isdn/hisax/niccy.c132
-rw-r--r--drivers/isdn/hisax/s0box.c40
-rw-r--r--drivers/isdn/hisax/saphir.c326
-rw-r--r--drivers/isdn/hisax/sedlbauer.c154
-rw-r--r--drivers/isdn/hisax/sportster.c23
-rw-r--r--drivers/isdn/hisax/tei.c39
-rw-r--r--drivers/isdn/hisax/teleint.c33
-rw-r--r--drivers/isdn/hisax/teles0.c44
-rw-r--r--drivers/isdn/hisax/teles3.c67
-rw-r--r--drivers/isdn/hisax/telespci.c98
-rw-r--r--drivers/isdn/icn/.cvsignore2
-rw-r--r--drivers/isdn/icn/icn.c37
-rw-r--r--drivers/isdn/isdn_audio.c106
-rw-r--r--drivers/isdn/isdn_audio.h14
-rw-r--r--drivers/isdn/isdn_budget.c206
-rw-r--r--drivers/isdn/isdn_cards.c16
-rw-r--r--drivers/isdn/isdn_common.c252
-rw-r--r--drivers/isdn/isdn_common.h11
-rw-r--r--drivers/isdn/isdn_concap.c12
-rw-r--r--drivers/isdn/isdn_net.c106
-rw-r--r--drivers/isdn/isdn_net.h14
-rw-r--r--drivers/isdn/isdn_ppp.c101
-rw-r--r--drivers/isdn/isdn_ppp.h12
-rw-r--r--drivers/isdn/isdn_tty.c608
-rw-r--r--drivers/isdn/isdn_tty.h92
-rw-r--r--drivers/isdn/isdn_ttyfax.c1206
-rw-r--r--drivers/isdn/isdn_ttyfax.h33
-rw-r--r--drivers/isdn/isdn_x25iface.c12
-rw-r--r--drivers/isdn/isdnloop/.cvsignore2
-rw-r--r--drivers/isdn/pcbit/.cvsignore2
-rw-r--r--drivers/isdn/pcbit/drv.c2
-rw-r--r--drivers/isdn/pcbit/module.c19
-rw-r--r--drivers/isdn/pcbit/pcbit.h6
-rw-r--r--drivers/isdn/sc/.cvsignore2
-rw-r--r--drivers/isdn/teles/.cvsignore2
112 files changed, 22438 insertions, 4159 deletions
diff --git a/drivers/isdn/.cvsignore b/drivers/isdn/.cvsignore
deleted file mode 100644
index 857dd22e9..000000000
--- a/drivers/isdn/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.depend
-.*.flags
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index 52e3acbdb..ec27982bb 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -9,6 +9,10 @@ if [ "$CONFIG_INET" != "n" ]; then
fi
fi
bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
+if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
+ bool 'Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
+fi
+bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION
if [ "$CONFIG_X25" != "n" ]; then
bool 'X.25 PLP on top of ISDN (EXPERIMENTAL)' CONFIG_ISDN_X25
fi
@@ -26,7 +30,6 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
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 Teles PCI' CONFIG_HISAX_TELESPCI
bool 'HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX
bool 'HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
@@ -37,24 +40,39 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
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/fax' CONFIG_HISAX_SEDLBAUER
+ bool 'HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS
+ bool 'HiSax Support for Sedlbauer cards' 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
+ bool 'HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF
+ bool 'HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+ bool 'HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T
+ bool 'HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
+ bool 'HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL
+ bool 'HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
- if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
- bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930
- fi
+# bool 'HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+ if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+ bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930
+ fi
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
- dep_tristate 'Eicon.Diehl active card support (EXPERIMENTAL)' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
fi
-dep_tristate 'AVM-B1 with CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
+dep_tristate 'Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
+if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
+ bool 'Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+fi
+dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
+ bool 'AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
+ bool 'AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
+ bool 'AVM T1/T1B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
+ bool 'AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
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 36a1f5bb7..04be19f9c 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 act2000 eicon
+ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon divert
L_OBJS :=
LX_OBJS :=
@@ -24,6 +24,9 @@ ifeq ($(CONFIG_ISDN),y)
endif
ifdef CONFIG_ISDN_AUDIO
L_OBJS += isdn_audio.o
+ ifdef CONFIG_ISDN_TTY_FAX
+ L_OBJS += isdn_ttyfax.o
+ endif
endif
else
ifeq ($(CONFIG_ISDN),m)
@@ -41,10 +44,19 @@ else
endif
ifdef CONFIG_ISDN_AUDIO
O_OBJS += isdn_audio.o
+ ifdef CONFIG_ISDN_TTY_FAX
+ O_OBJS += isdn_ttyfax.o
+ endif
endif
endif
endif
+ifeq ($(CONFIG_ISDN_DIVERSION),y)
+ ifeq ($(CONFIG_MODULES),y)
+ MOD_SUB_DIRS += divert
+ endif
+endif
+
ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
L_OBJS += hisax/hisax.o
SUB_DIRS += hisax
diff --git a/drivers/isdn/act2000/.cvsignore b/drivers/isdn/act2000/.cvsignore
deleted file mode 100644
index 857dd22e9..000000000
--- a/drivers/isdn/act2000/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.depend
-.*.flags
diff --git a/drivers/isdn/avmb1/.cvsignore b/drivers/isdn/avmb1/.cvsignore
deleted file mode 100644
index 857dd22e9..000000000
--- a/drivers/isdn/avmb1/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.depend
-.*.flags
diff --git a/drivers/isdn/avmb1/Makefile b/drivers/isdn/avmb1/Makefile
index cce4af131..9f73ea2e3 100644
--- a/drivers/isdn/avmb1/Makefile
+++ b/drivers/isdn/avmb1/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile,v 1.4 1997/03/30 17:10:40 calle Exp $
+# $Id: Makefile,v 1.6 1999/07/20 06:41:44 calle Exp $
#
# Makefile for the CAPI and AVM-B1 device drivers.
#
@@ -11,6 +11,26 @@
# parent makes..
#
# $Log: Makefile,v $
+# Revision 1.6 1999/07/20 06:41:44 calle
+# Bugfix: After the redesign of the AVM B1 driver, the driver didn't even
+# compile, if not selected as modules.
+#
+# Revision 1.5 1999/07/01 15:26:20 calle
+# complete new version (I love it):
+# + new hardware independed "capi_driver" interface that will make it easy to:
+# - support other controllers with CAPI-2.0 (i.e. USB Controller)
+# - write a CAPI-2.0 for the passive cards
+# - support serial link CAPI-2.0 boxes.
+# + wrote "capi_driver" for all supported cards.
+# + "capi_driver" (supported cards) now have to be configured with
+# make menuconfig, in the past all supported cards where included
+# at once.
+# + new and better informations in /proc/capi/
+# + new ioctl to switch trace of capi messages per controller
+# using "avmcapictrl trace [contr] on|off|...."
+# + complete testcircle with all supported cards and also the
+# PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+#
# Revision 1.4 1997/03/30 17:10:40 calle
# added support for AVM-B1-PCI card.
#
@@ -56,20 +76,38 @@ L_TARGET := # used for .a targets (from L and LX objects)
ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
O_TARGET += avmb1.o
- O_OBJS += capi.o b1lli.o
- OX_OBJS += capiutil.o b1capi.o capidrv.o
- ifdef CONFIG_PCI
- OX_OBJS += b1pci.o
+ OX_OBJS += kcapi.o
+ O_OBJS += capi.o
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
+ O_OBJS += b1isa.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
+ O_OBJS += b1pci.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
+ O_OBJS += t1isa.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+ OX_OBJS += b1pcmcia.o
endif
+ OX_OBJS += capiutil.o capidrv.o b1.o
else
ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
O_TARGET += kernelcapi.o
- O_OBJS += b1lli.o
- OX_OBJS += b1capi.o
+ OX_OBJS += kcapi.o
M_OBJS += capi.o kernelcapi.o
- MX_OBJS += capiutil.o capidrv.o
- ifdef CONFIG_PCI
- MX_OBJS += b1pci.o
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
+ M_OBJS += b1isa.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
+ M_OBJS += b1pci.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
+ M_OBJS += t1isa.o
+ endif
+ MX_OBJS += capiutil.o capidrv.o b1.o
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+ MX_OBJS += b1pcmcia.o
endif
endif
endif
diff --git a/drivers/isdn/avmb1/avmcard.h b/drivers/isdn/avmb1/avmcard.h
new file mode 100644
index 000000000..e94c5637c
--- /dev/null
+++ b/drivers/isdn/avmb1/avmcard.h
@@ -0,0 +1,559 @@
+/*
+ * $Id: avmcard.h,v 1.4 1999/08/04 10:10:08 calle Exp $
+ *
+ * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: avmcard.h,v $
+ * Revision 1.4 1999/08/04 10:10:08 calle
+ * Bugfix: corrected /proc functions, added structure for new AVM cards.
+ *
+ * Revision 1.3 1999/07/23 08:41:47 calle
+ * prepared for new AVM cards.
+ *
+ * Revision 1.2 1999/07/05 15:09:45 calle
+ * - renamed "appl_release" to "appl_released".
+ * - version und profile data now cleared on controller reset
+ * - extended /proc interface, to allow driver and controller specific
+ * informations to include by driver hackers.
+ *
+ * Revision 1.1 1999/07/01 15:26:22 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ */
+
+#ifndef _AVMCARD_H_
+#define _AVMCARD_H_
+
+#define AVMB1_PORTLEN 0x1f
+#define AVM_MAXVERSION 8
+#define AVM_NAPPS 30
+#define AVM_NCCI_PER_CHANNEL 4
+
+/*
+ * Versions
+ */
+
+#define VER_DRIVER 0
+#define VER_CARDTYPE 1
+#define VER_HWID 2
+#define VER_SERIAL 3
+#define VER_OPTION 4
+#define VER_PROTO 5
+#define VER_PROFILE 6
+#define VER_CAPI 7
+
+enum avmcardtype {
+ avm_b1isa,
+ avm_b1pci,
+ avm_b1pcmcia,
+ avm_m1,
+ avm_m2,
+ avm_t1isa,
+ avm_t1pci,
+ avm_c4
+};
+
+typedef struct avmcard_dmainfo {
+ __u32 recvlen;
+ __u8 recvbuf[128+2048];
+ struct sk_buff_head send_queue;
+ __u8 sendbuf[128+2048];
+} avmcard_dmainfo;
+
+typedef struct avmcard {
+ char name[32];
+ unsigned int port;
+ unsigned irq;
+ unsigned long membase;
+ enum avmcardtype cardtype;
+ int cardnr; /* for t1isa */
+
+ int versionlen;
+ char versionbuf[1024];
+ char *version[AVM_MAXVERSION];
+
+ char cardname[32];
+
+ char infobuf[128]; /* for function procinfo */
+ char msgbuf[128]; /* capimsg msg part */
+ char databuf[2048]; /* capimsg data part */
+
+ int interrupt;
+
+ void *mbase;
+ __u32 csr;
+ avmcard_dmainfo *dma;
+
+ struct capi_ctr *ctrl;
+} avmcard;
+
+extern int b1_irq_table[16];
+
+/*
+ * LLI Messages to the ISDN-ControllerISDN Controller
+ */
+
+#define SEND_POLL 0x72 /*
+ * after load <- RECEIVE_POLL
+ */
+#define SEND_INIT 0x11 /*
+ * first message <- RECEIVE_INIT
+ * int32 NumApplications int32
+ * NumNCCIs int32 BoardNumber
+ */
+#define SEND_REGISTER 0x12 /*
+ * register an application int32
+ * ApplIDId int32 NumMessages
+ * int32 NumB3Connections int32
+ * NumB3Blocks int32 B3Size
+ *
+ * AnzB3Connection != 0 &&
+ * AnzB3Blocks >= 1 && B3Size >= 1
+ */
+#define SEND_RELEASE 0x14 /*
+ * deregister an application int32
+ * ApplID
+ */
+#define SEND_MESSAGE 0x15 /*
+ * send capi-message int32 length
+ * capi-data ...
+ */
+#define SEND_DATA_B3_REQ 0x13 /*
+ * send capi-data-message int32
+ * MsgLength capi-data ... int32
+ * B3Length data ....
+ */
+
+#define SEND_CONFIG 0x21 /*
+ */
+
+#define SEND_POLLACK 0x73 /* T1 Watchdog */
+
+/*
+ * LLI Messages from the ISDN-ControllerISDN Controller
+ */
+
+#define RECEIVE_POLL 0x32 /*
+ * <- after SEND_POLL
+ */
+#define RECEIVE_INIT 0x27 /*
+ * <- after SEND_INIT int32 length
+ * byte total length b1struct board
+ * driver revision b1struct card
+ * type b1struct reserved b1struct
+ * serial number b1struct driver
+ * capability b1struct d-channel
+ * protocol b1struct CAPI-2.0
+ * profile b1struct capi version
+ */
+#define RECEIVE_MESSAGE 0x21 /*
+ * <- after SEND_MESSAGE int32
+ * AppllID int32 Length capi-data
+ * ....
+ */
+#define RECEIVE_DATA_B3_IND 0x22 /*
+ * received data int32 AppllID
+ * int32 Length capi-data ...
+ * int32 B3Length data ...
+ */
+#define RECEIVE_START 0x23 /*
+ * Handshake
+ */
+#define RECEIVE_STOP 0x24 /*
+ * Handshake
+ */
+#define RECEIVE_NEW_NCCI 0x25 /*
+ * int32 AppllID int32 NCCI int32
+ * WindowSize
+ */
+#define RECEIVE_FREE_NCCI 0x26 /*
+ * int32 AppllID int32 NCCI
+ */
+#define RECEIVE_RELEASE 0x26 /*
+ * int32 AppllID int32 0xffffffff
+ */
+#define RECEIVE_TASK_READY 0x31 /*
+ * int32 tasknr
+ * int32 Length Taskname ...
+ */
+#define RECEIVE_DEBUGMSG 0x71 /*
+ * int32 Length message
+ *
+ */
+#define RECEIVE_POLLDWORD 0x75 /* t1pci in dword mode */
+
+#define WRITE_REGISTER 0x00
+#define READ_REGISTER 0x01
+
+/*
+ * port offsets
+ */
+
+#define B1_READ 0x00
+#define B1_WRITE 0x01
+#define B1_INSTAT 0x02
+#define B1_OUTSTAT 0x03
+#define B1_RESET 0x10
+#define B1_ANALYSE 0x04
+
+
+#define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l)
+#define B1_STAT1(cardtype) (0x80E00000l)
+
+/* ---------------------------------------------------------------- */
+
+static inline unsigned char b1outp(unsigned int base,
+ unsigned short offset,
+ unsigned char value)
+{
+ outb(value, base + offset);
+ return inb(base + B1_ANALYSE);
+}
+
+
+static inline int b1_rx_full(unsigned int base)
+{
+ return inb(base + B1_INSTAT) & 0x1;
+}
+
+static inline unsigned char b1_get_byte(unsigned int base)
+{
+ unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
+ while (!b1_rx_full(base) && time_before(jiffies, stop));
+ if (b1_rx_full(base))
+ return inb(base + B1_READ);
+ printk(KERN_CRIT "b1lli(0x%x): rx not full after 1 second\n", base);
+ return 0;
+}
+
+static inline unsigned int b1_get_word(unsigned int 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 int base)
+{
+ return inb(base + B1_OUTSTAT) & 0x1;
+}
+
+static inline void b1_put_byte(unsigned int base, unsigned char val)
+{
+ while (!b1_tx_empty(base));
+ b1outp(base, B1_WRITE, val);
+}
+
+static inline int b1_save_put_byte(unsigned int base, unsigned char val)
+{
+ unsigned long stop = jiffies + 2 * HZ;
+ while (!b1_tx_empty(base) && time_before(jiffies,stop));
+ if (!b1_tx_empty(base)) return -1;
+ b1outp(base, B1_WRITE, val);
+ return 0;
+}
+
+static inline void b1_put_word(unsigned int 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 int 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 int base,
+ unsigned char *dp, unsigned int len)
+{
+ unsigned i = len;
+ b1_put_word(base, i);
+ while (i-- > 0)
+ b1_put_byte(base, *dp++);
+}
+
+static void b1_wr_reg(unsigned int 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 int base,
+ unsigned int reg)
+{
+ b1_put_byte(base, READ_REGISTER);
+ b1_put_word(base, reg);
+ return b1_get_word(base);
+
+}
+
+static inline void b1_reset(unsigned int base)
+{
+ b1outp(base, B1_RESET, 0);
+ udelay(55 * 2 * 1000); /* 2 TIC's */
+
+ b1outp(base, B1_RESET, 1);
+ udelay(55 * 2 * 1000); /* 2 TIC's */
+
+ b1outp(base, B1_RESET, 0);
+ udelay(55 * 2 * 1000); /* 2 TIC's */
+}
+
+static inline unsigned char b1_disable_irq(unsigned int base)
+{
+ return b1outp(base, B1_INSTAT, 0x00);
+}
+
+/* ---------------------------------------------------------------- */
+
+static inline void b1_set_test_bit(unsigned int base,
+ enum avmcardtype cardtype,
+ int onoff)
+{
+ b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20);
+}
+
+static inline int b1_get_test_bit(unsigned int base,
+ enum avmcardtype cardtype)
+{
+ return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0;
+}
+
+/* ---------------------------------------------------------------- */
+
+#define T1_FASTLINK 0x00
+#define T1_SLOWLINK 0x08
+
+#define T1_READ B1_READ
+#define T1_WRITE B1_WRITE
+#define T1_INSTAT B1_INSTAT
+#define T1_OUTSTAT B1_OUTSTAT
+#define T1_IRQENABLE 0x05
+#define T1_FIFOSTAT 0x06
+#define T1_RESETLINK 0x10
+#define T1_ANALYSE 0x11
+#define T1_IRQMASTER 0x12
+#define T1_IDENT 0x17
+#define T1_RESETBOARD 0x1f
+
+#define T1F_IREADY 0x01
+#define T1F_IHALF 0x02
+#define T1F_IFULL 0x04
+#define T1F_IEMPTY 0x08
+#define T1F_IFLAGS 0xF0
+
+#define T1F_OREADY 0x10
+#define T1F_OHALF 0x20
+#define T1F_OEMPTY 0x40
+#define T1F_OFULL 0x80
+#define T1F_OFLAGS 0xF0
+
+/* there are HEMA cards with 1k and 4k FIFO out */
+#define FIFO_OUTBSIZE 256
+#define FIFO_INPBSIZE 512
+
+#define HEMA_VERSION_ID 0
+#define HEMA_PAL_ID 0
+
+static inline void t1outp(unsigned int base,
+ unsigned short offset,
+ unsigned char value)
+{
+ outb(value, base + offset);
+}
+
+static inline unsigned char t1inp(unsigned int base,
+ unsigned short offset)
+{
+ return inb(base + offset);
+}
+
+static inline int t1_isfastlink(unsigned int base)
+{
+ return (inb(base + T1_IDENT) & ~0x82) == 1;
+}
+
+static inline unsigned char t1_fifostatus(unsigned int base)
+{
+ return inb(base + T1_FIFOSTAT);
+}
+
+static inline unsigned int t1_get_slice(unsigned int base,
+ unsigned char *dp)
+{
+ unsigned int len, i;
+#ifdef FASTLINK_DEBUG
+ unsigned wcnt = 0, bcnt = 0;
+#endif
+
+ len = i = b1_get_word(base);
+ if (t1_isfastlink(base)) {
+ int status;
+ while (i > 0) {
+ status = t1_fifostatus(base) & (T1F_IREADY|T1F_IHALF);
+ if (i >= FIFO_INPBSIZE) status |= T1F_IFULL;
+
+ switch (status) {
+ case T1F_IREADY|T1F_IHALF|T1F_IFULL:
+ insb(base+B1_READ, dp, FIFO_INPBSIZE);
+ dp += FIFO_INPBSIZE;
+ i -= FIFO_INPBSIZE;
+#ifdef FASTLINK_DEBUG
+ wcnt += FIFO_INPBSIZE;
+#endif
+ break;
+ case T1F_IREADY|T1F_IHALF:
+ insb(base+B1_READ,dp, i);
+#ifdef FASTLINK_DEBUG
+ wcnt += i;
+#endif
+ dp += i;
+ i = 0;
+ if (i == 0)
+ break;
+ /* fall through */
+ default:
+ *dp++ = b1_get_byte(base);
+ i--;
+#ifdef FASTLINK_DEBUG
+ bcnt++;
+#endif
+ break;
+ }
+ }
+#ifdef FASTLINK_DEBUG
+ if (wcnt)
+ printk(KERN_DEBUG "b1lli(0x%x): get_slice l=%d w=%d b=%d\n",
+ base, len, wcnt, bcnt);
+#endif
+ } else {
+ while (i-- > 0)
+ *dp++ = b1_get_byte(base);
+ }
+ return len;
+}
+
+static inline void t1_put_slice(unsigned int base,
+ unsigned char *dp, unsigned int len)
+{
+ unsigned i = len;
+ b1_put_word(base, i);
+ if (t1_isfastlink(base)) {
+ int status;
+ while (i > 0) {
+ status = t1_fifostatus(base) & (T1F_OREADY|T1F_OHALF);
+ if (i >= FIFO_OUTBSIZE) status |= T1F_OEMPTY;
+ switch (status) {
+ case T1F_OREADY|T1F_OHALF|T1F_OEMPTY:
+ outsb(base+B1_WRITE, dp, FIFO_OUTBSIZE);
+ dp += FIFO_OUTBSIZE;
+ i -= FIFO_OUTBSIZE;
+ break;
+ case T1F_OREADY|T1F_OHALF:
+ outsb(base+B1_WRITE, dp, i);
+ dp += i;
+ i = 0;
+ break;
+ default:
+ b1_put_byte(base, *dp++);
+ i--;
+ break;
+ }
+ }
+ } else {
+ while (i-- > 0)
+ b1_put_byte(base, *dp++);
+ }
+}
+
+static inline void t1_disable_irq(unsigned int base)
+{
+ t1outp(base, T1_IRQMASTER, 0x00);
+}
+
+static inline void t1_reset(unsigned int base)
+{
+ /* reset T1 Controller */
+ b1_reset(base);
+ /* disable irq on HEMA */
+ t1outp(base, B1_INSTAT, 0x00);
+ t1outp(base, B1_OUTSTAT, 0x00);
+ t1outp(base, T1_IRQMASTER, 0x00);
+ /* reset HEMA board configuration */
+ t1outp(base, T1_RESETBOARD, 0xf);
+}
+
+static inline void b1_setinterrupt(unsigned int base, unsigned irq,
+ enum avmcardtype cardtype)
+{
+ switch (cardtype) {
+ case avm_t1isa:
+ t1outp(base, B1_INSTAT, 0x00);
+ t1outp(base, B1_INSTAT, 0x02);
+ t1outp(base, T1_IRQMASTER, 0x08);
+ break;
+ case avm_b1isa:
+ b1outp(base, B1_INSTAT, 0x00);
+ b1outp(base, B1_RESET, b1_irq_table[irq]);
+ b1outp(base, B1_INSTAT, 0x02);
+ break;
+ default:
+ case avm_m1:
+ case avm_m2:
+ case avm_b1pci:
+ b1outp(base, B1_INSTAT, 0x00);
+ b1outp(base, B1_RESET, 0xf0);
+ b1outp(base, B1_INSTAT, 0x02);
+ break;
+ case avm_c4:
+ case avm_t1pci:
+ b1outp(base, B1_RESET, 0xf0);
+ break;
+ }
+}
+
+int b1_detect(unsigned int base, enum avmcardtype cardtype);
+int b1_load_t4file(unsigned int base, capiloaddatapart * t4file);
+int b1_load_config(unsigned int base, capiloaddatapart * config);
+int b1_loaded(unsigned int base);
+int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
+void b1_reset_ctr(struct capi_ctr *ctrl);
+void b1_register_appl(struct capi_ctr *ctrl, __u16 appl,
+ capi_register_params *rp);
+void b1_release_appl(struct capi_ctr *ctrl, __u16 appl);
+void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
+void b1_parse_version(avmcard *card);
+void b1_handle_interrupt(avmcard * card);
+
+int b1ctl_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctrl);
+
+
+#endif /* _AVMCARD_H_ */
diff --git a/drivers/isdn/avmb1/b1.c b/drivers/isdn/avmb1/b1.c
new file mode 100644
index 000000000..c4dffdacb
--- /dev/null
+++ b/drivers/isdn/avmb1/b1.c
@@ -0,0 +1,693 @@
+/*
+ * $Id: b1.c,v 1.8 1999/08/22 20:26:22 calle Exp $
+ *
+ * Common module for AVM B1 cards.
+ *
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1.c,v $
+ * Revision 1.8 1999/08/22 20:26:22 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.7 1999/08/04 10:10:09 calle
+ * Bugfix: corrected /proc functions, added structure for new AVM cards.
+ *
+ * Revision 1.6 1999/07/23 08:51:04 calle
+ * small fix and typo in checkin before.
+ *
+ * Revision 1.5 1999/07/23 08:41:48 calle
+ * prepared for new AVM cards.
+ *
+ * Revision 1.4 1999/07/09 15:05:38 keil
+ * compat.h is now isdn_compat.h
+ *
+ * Revision 1.3 1999/07/06 07:41:59 calle
+ * - changes in /proc interface
+ * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
+ *
+ * Revision 1.2 1999/07/05 15:09:47 calle
+ * - renamed "appl_release" to "appl_released".
+ * - version und profile data now cleared on controller reset
+ * - extended /proc interface, to allow driver and controller specific
+ * informations to include by driver hackers.
+ *
+ * Revision 1.1 1999/07/01 15:26:23 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/capi.h>
+#include <asm/io.h>
+#include <linux/isdn_compat.h>
+#include "capilli.h"
+#include "avmcard.h"
+#include "capicmd.h"
+#include "capiutil.h"
+
+static char *revision = "$Revision: 1.8 $";
+
+/* ------------------------------------------------------------- */
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+/* ------------------------------------------------------------- */
+
+int b1_irq_table[16] =
+{0,
+ 0,
+ 0,
+ 192, /* irq 3 */
+ 32, /* irq 4 */
+ 160, /* irq 5 */
+ 96, /* irq 6 */
+ 224, /* irq 7 */
+ 0,
+ 64, /* irq 9 */
+ 80, /* irq 10 */
+ 208, /* irq 11 */
+ 48, /* irq 12 */
+ 0,
+ 0,
+ 112, /* irq 15 */
+};
+
+/* ------------------------------------------------------------- */
+
+int b1_detect(unsigned int base, enum avmcardtype cardtype)
+{
+ int onoff, i;
+
+ /*
+ * 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); */
+ if ((inb(base + B1_INSTAT) & 0xfe) != 0x2
+ /* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */)
+ return 2;
+ /*
+ * Statusregister 0000 000x
+ */
+ b1outp(base, B1_INSTAT, 0x0); /* disable irq */
+ b1outp(base, B1_OUTSTAT, 0x0);
+ 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;
+ }
+
+ if (cardtype == avm_m1)
+ return 0;
+
+ if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01)
+ return 5;
+
+ return 0;
+}
+
+int b1_load_t4file(unsigned int base, capiloaddatapart * t4file)
+{
+ unsigned char buf[256];
+ unsigned char *dp;
+ int i, left, retval;
+
+ dp = t4file->data;
+ left = t4file->len;
+ while (left > sizeof(buf)) {
+ if (t4file->user) {
+ retval = copy_from_user(buf, dp, sizeof(buf));
+ if (retval)
+ return -EFAULT;
+ } else {
+ memcpy(buf, dp, sizeof(buf));
+ }
+ for (i = 0; i < sizeof(buf); i++)
+ if (b1_save_put_byte(base, buf[i]) < 0) {
+ printk(KERN_ERR "b1_load_t4file: corrupted t4 file ?\n");
+ return -EIO;
+ }
+ left -= sizeof(buf);
+ dp += sizeof(buf);
+ }
+ if (left) {
+ if (t4file->user) {
+ retval = copy_from_user(buf, dp, left);
+ if (retval)
+ return -EFAULT;
+ } else {
+ memcpy(buf, dp, left);
+ }
+ for (i = 0; i < left; i++)
+ if (b1_save_put_byte(base, buf[i]) < 0) {
+ printk(KERN_ERR "b1_load_t4file: corrupted t4 file ?\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+int b1_load_config(unsigned int base, capiloaddatapart * config)
+{
+ 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)) {
+ if (config->user) {
+ retval = copy_from_user(buf, dp, sizeof(buf));
+ if (retval)
+ return -EFAULT;
+ } else {
+ memcpy(buf, dp, 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++]);
+ }
+ }
+ left -= sizeof(buf);
+ dp += sizeof(buf);
+ }
+ if (left) {
+ if (config->user) {
+ retval = copy_from_user(buf, dp, left);
+ if (retval)
+ return -EFAULT;
+ } else {
+ memcpy(buf, dp, 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);
+ }
+ }
+ }
+ return 0;
+}
+
+int b1_loaded(unsigned int base)
+{
+ unsigned long stop;
+ unsigned char ans;
+ unsigned long tout = 2;
+
+ for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+ if (b1_tx_empty(base))
+ break;
+ }
+ if (!b1_tx_empty(base)) {
+ printk(KERN_ERR "b1_loaded: tx err, corrupted t4 file ?\n");
+ return 0;
+ }
+ b1_put_byte(base, SEND_POLL);
+ for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+ if (b1_rx_full(base)) {
+ if ((ans = b1_get_byte(base)) == RECEIVE_POLL) {
+ return 1;
+ }
+ printk(KERN_ERR "b1_loaded: got 0x%x, firmware not running\n", ans);
+ return 0;
+ }
+ }
+ printk(KERN_ERR "b1_loaded: firmware not running\n");
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+ unsigned long flags;
+ int retval;
+
+ b1_reset(port);
+
+ if ((retval = b1_load_t4file(port, &data->firmware))) {
+ b1_reset(port);
+ printk(KERN_ERR "%s: failed to load t4file!!\n",
+ card->name);
+ return retval;
+ }
+
+ b1_disable_irq(port);
+
+ if (data->configuration.len > 0 && data->configuration.data) {
+ if ((retval = b1_load_config(port, &data->configuration))) {
+ b1_reset(port);
+ printk(KERN_ERR "%s: failed to load config!!\n",
+ card->name);
+ return retval;
+ }
+ }
+
+ if (!b1_loaded(port)) {
+ printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
+ return -EIO;
+ }
+
+ save_flags(flags);
+ cli();
+ b1_setinterrupt(port, card->irq, card->cardtype);
+ b1_put_byte(port, SEND_INIT);
+ b1_put_word(port, AVM_NAPPS);
+ b1_put_word(port, AVM_NCCI_PER_CHANNEL*2);
+ b1_put_word(port, ctrl->cnr - 1);
+ restore_flags(flags);
+
+ return 0;
+}
+
+void b1_reset_ctr(struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+
+ b1_reset(port);
+ b1_reset(port);
+
+ memset(card->version, 0, sizeof(card->version));
+ ctrl->reseted(ctrl);
+}
+
+void b1_register_appl(struct capi_ctr *ctrl,
+ __u16 appl,
+ capi_register_params *rp)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+ unsigned long flags;
+ int nconn, want = rp->level3cnt;
+
+ if (want > 0) nconn = want;
+ else nconn = ctrl->profile.nbchannel * -want;
+ if (nconn == 0) nconn = ctrl->profile.nbchannel;
+
+ save_flags(flags);
+ cli();
+ b1_put_byte(port, SEND_REGISTER);
+ b1_put_word(port, appl);
+ b1_put_word(port, 1024 * (nconn+1));
+ b1_put_word(port, nconn);
+ b1_put_word(port, rp->datablkcnt);
+ b1_put_word(port, rp->datablklen);
+ restore_flags(flags);
+
+ ctrl->appl_registered(ctrl, appl);
+}
+
+void b1_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ b1_put_byte(port, SEND_RELEASE);
+ b1_put_word(port, appl);
+ restore_flags(flags);
+}
+
+void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+ unsigned long flags;
+ __u16 len = CAPIMSG_LEN(skb->data);
+ __u8 cmd = CAPIMSG_COMMAND(skb->data);
+ __u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+ save_flags(flags);
+ cli();
+ if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+ __u16 dlen = CAPIMSG_DATALEN(skb->data);
+ b1_put_byte(port, SEND_DATA_B3_REQ);
+ b1_put_slice(port, skb->data, len);
+ b1_put_slice(port, skb->data + len, dlen);
+ } else {
+ b1_put_byte(port, SEND_MESSAGE);
+ b1_put_slice(port, skb->data, len);
+ }
+ restore_flags(flags);
+ dev_kfree_skb(skb);
+}
+
+/* ------------------------------------------------------------- */
+
+void b1_parse_version(avmcard *card)
+{
+ struct capi_ctr *ctrl = card->ctrl;
+ capi_profile *profp;
+ __u8 *dversion;
+ __u8 flag;
+ int i, j;
+
+ for (j = 0; j < AVM_MAXVERSION; j++)
+ card->version[j] = "\0\0" + 1;
+ for (i = 0, j = 0;
+ j < AVM_MAXVERSION && i < card->versionlen;
+ j++, i += card->versionbuf[i] + 1)
+ card->version[j] = &card->versionbuf[i + 1];
+
+ strncpy(ctrl->serial, card->version[VER_SERIAL], CAPI_SERIAL_LEN);
+ memcpy(&ctrl->profile, card->version[VER_PROFILE],sizeof(capi_profile));
+ strncpy(ctrl->manu, "AVM GmbH", CAPI_MANUFACTURER_LEN);
+ dversion = card->version[VER_DRIVER];
+ ctrl->version.majorversion = 2;
+ ctrl->version.minorversion = 0;
+ ctrl->version.majormanuversion = (((dversion[0] - '0') & 0xf) << 4);
+ ctrl->version.majormanuversion |= ((dversion[2] - '0') & 0xf);
+ ctrl->version.minormanuversion = (dversion[3] - '0') << 4;
+ ctrl->version.minormanuversion |=
+ (dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf);
+
+ profp = &ctrl->profile;
+
+ flag = ((__u8 *)(profp->manu))[1];
+ switch (flag) {
+ case 0: if (card->version[VER_CARDTYPE])
+ strcpy(card->cardname, card->version[VER_CARDTYPE]);
+ else strcpy(card->cardname, "B1");
+ break;
+ case 3: strcpy(card->cardname,"PCMCIA B"); break;
+ case 4: strcpy(card->cardname,"PCMCIA M1"); break;
+ case 5: strcpy(card->cardname,"PCMCIA M2"); break;
+ case 6: strcpy(card->cardname,"B1 V3.0"); break;
+ case 7: strcpy(card->cardname,"B1 PCI"); break;
+ default: sprintf(card->cardname, "AVM?%u", (unsigned int)flag); break;
+ }
+ printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n",
+ card->name, ctrl->cnr, card->cardname);
+
+ flag = ((__u8 *)(profp->manu))[3];
+ if (flag)
+ printk(KERN_NOTICE "b1capi: card %d Protocol:%s%s%s%s%s%s%s\n",
+ ctrl->cnr,
+ (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 "%s: card %d Linetype:%s%s%s%s\n",
+ card->name,
+ ctrl->cnr,
+ (flag & 0x01) ? " point to point" : "",
+ (flag & 0x02) ? " point to multipoint" : "",
+ (flag & 0x08) ? " leased line without D-channel" : "",
+ (flag & 0x04) ? " leased line with D-channel" : ""
+ );
+}
+
+/* ------------------------------------------------------------- */
+
+void b1_handle_interrupt(avmcard * card)
+{
+ struct capi_ctr *ctrl = card->ctrl;
+ unsigned char b1cmd;
+ struct sk_buff *skb;
+
+ unsigned ApplId;
+ unsigned MsgLen;
+ unsigned DataB3Len;
+ unsigned NCCI;
+ unsigned WindowSize;
+
+ if (!b1_rx_full(card->port))
+ return;
+
+ b1cmd = b1_get_byte(card->port);
+
+ switch (b1cmd) {
+
+ case RECEIVE_DATA_B3_IND:
+
+ ApplId = (unsigned) b1_get_word(card->port);
+ MsgLen = b1_get_slice(card->port, card->msgbuf);
+ DataB3Len = b1_get_slice(card->port, card->databuf);
+
+ if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) {
+ printk(KERN_ERR "%s: incoming packet dropped\n",
+ card->name);
+ } else {
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+ CAPIMSG_SETDATA(skb->data, skb->data + MsgLen);
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_MESSAGE:
+
+ ApplId = (unsigned) b1_get_word(card->port);
+ MsgLen = b1_get_slice(card->port, card->msgbuf);
+ if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
+ printk(KERN_ERR "%s: incoming packet dropped\n",
+ card->name);
+ } else {
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_NEW_NCCI:
+
+ ApplId = b1_get_word(card->port);
+ NCCI = b1_get_word(card->port);
+ WindowSize = b1_get_word(card->port);
+
+ ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
+
+ break;
+
+ case RECEIVE_FREE_NCCI:
+
+ ApplId = b1_get_word(card->port);
+ NCCI = b1_get_word(card->port);
+
+ if (NCCI != 0xffffffff)
+ ctrl->free_ncci(ctrl, ApplId, NCCI);
+ else ctrl->appl_released(ctrl, ApplId);
+ break;
+
+ case RECEIVE_START:
+ /* b1_put_byte(card->port, SEND_POLLACK); */
+ ctrl->resume_output(ctrl);
+ break;
+
+ case RECEIVE_STOP:
+ ctrl->suspend_output(ctrl);
+ break;
+
+ case RECEIVE_INIT:
+
+ card->versionlen = b1_get_slice(card->port, card->versionbuf);
+ b1_parse_version(card);
+ printk(KERN_INFO "%s: %s-card (%s) now active\n",
+ card->name,
+ card->version[VER_CARDTYPE],
+ card->version[VER_DRIVER]);
+ ctrl->ready(ctrl);
+ break;
+
+ case RECEIVE_TASK_READY:
+ ApplId = (unsigned) b1_get_word(card->port);
+ MsgLen = b1_get_slice(card->port, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
+ card->name, ApplId, card->msgbuf);
+ break;
+
+ case RECEIVE_DEBUGMSG:
+ MsgLen = b1_get_slice(card->port, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
+ break;
+
+ case 0xff:
+ printk(KERN_ERR "%s: card removed ?\n", card->name);
+ return;
+ default:
+ printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
+ card->name, b1cmd);
+ return;
+ }
+}
+
+/* ------------------------------------------------------------- */
+int b1ctl_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ __u8 flag;
+ int len = 0;
+ char *s;
+
+ len += sprintf(page+len, "%-16s %s\n", "name", card->name);
+ len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
+ len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+ switch (card->cardtype) {
+ case avm_b1isa: s = "B1 ISA"; break;
+ case avm_b1pci: s = "B1 PCI"; break;
+ case avm_b1pcmcia: s = "B1 PCMCIA"; break;
+ case avm_m1: s = "M1"; break;
+ case avm_m2: s = "M2"; break;
+ case avm_t1isa: s = "T1 ISA (HEMA)"; break;
+ case avm_t1pci: s = "T1 PCI"; break;
+ case avm_c4: s = "C4"; break;
+ default: s = "???"; break;
+ }
+ len += sprintf(page+len, "%-16s %s\n", "type", s);
+ if (card->cardtype == avm_t1isa)
+ len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr);
+ if ((s = card->version[VER_DRIVER]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+ if ((s = card->version[VER_CARDTYPE]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+ if ((s = card->version[VER_SERIAL]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+
+ if (card->cardtype != avm_m1) {
+ flag = ((__u8 *)(ctrl->profile.manu))[3];
+ if (flag)
+ len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+ "protocol",
+ (flag & 0x01) ? " DSS1" : "",
+ (flag & 0x02) ? " CT1" : "",
+ (flag & 0x04) ? " VN3" : "",
+ (flag & 0x08) ? " NI1" : "",
+ (flag & 0x10) ? " AUSTEL" : "",
+ (flag & 0x20) ? " ESS" : "",
+ (flag & 0x40) ? " 1TR6" : ""
+ );
+ }
+ if (card->cardtype != avm_m1) {
+ flag = ((__u8 *)(ctrl->profile.manu))[5];
+ if (flag)
+ len += sprintf(page+len, "%-16s%s%s%s%s\n",
+ "linetype",
+ (flag & 0x01) ? " point to point" : "",
+ (flag & 0x02) ? " point to multipoint" : "",
+ (flag & 0x08) ? " leased line without D-channel" : "",
+ (flag & 0x04) ? " leased line with D-channel" : ""
+ );
+ }
+ len += sprintf(page+len, "%-16s %s\n", "cardname", card->cardname);
+
+ if (off+count >= len)
+ *eof = 1;
+ if (len < off)
+ return 0;
+ *start = page + off;
+ return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+EXPORT_SYMBOL(b1_irq_table);
+
+EXPORT_SYMBOL(b1_detect);
+EXPORT_SYMBOL(b1_load_t4file);
+EXPORT_SYMBOL(b1_load_config);
+EXPORT_SYMBOL(b1_loaded);
+EXPORT_SYMBOL(b1_load_firmware);
+EXPORT_SYMBOL(b1_reset_ctr);
+EXPORT_SYMBOL(b1_register_appl);
+EXPORT_SYMBOL(b1_release_appl);
+EXPORT_SYMBOL(b1_send_message);
+
+EXPORT_SYMBOL(b1_parse_version);
+EXPORT_SYMBOL(b1_handle_interrupt);
+
+EXPORT_SYMBOL(b1ctl_read_proc);
+
+#ifdef MODULE
+#define b1_init init_module
+void cleanup_module(void);
+#endif
+
+int b1_init(void)
+{
+ char *p;
+ char rev[10];
+
+ if ((p = strchr(revision, ':'))) {
+ strncpy(rev, p + 1, sizeof(rev));
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, "1.0");
+
+ printk(KERN_INFO "b1: revision %s\n", rev);
+
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+}
+#endif
diff --git a/drivers/isdn/avmb1/b1isa.c b/drivers/isdn/avmb1/b1isa.c
new file mode 100644
index 000000000..9ab198432
--- /dev/null
+++ b/drivers/isdn/avmb1/b1isa.c
@@ -0,0 +1,243 @@
+/*
+ * $Id: b1isa.c,v 1.4 1999/08/22 20:26:24 calle Exp $
+ *
+ * Module for AVM B1 ISA-card.
+ *
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1isa.c,v $
+ * Revision 1.4 1999/08/22 20:26:24 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.3 1999/07/09 15:05:40 keil
+ * compat.h is now isdn_compat.h
+ *
+ * Revision 1.2 1999/07/05 15:09:49 calle
+ * - renamed "appl_release" to "appl_released".
+ * - version und profile data now cleared on controller reset
+ * - extended /proc interface, to allow driver and controller specific
+ * informations to include by driver hackers.
+ *
+ * Revision 1.1 1999/07/01 15:26:27 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/capi.h>
+#include <asm/io.h>
+#include <linux/isdn_compat.h>
+#include "capicmd.h"
+#include "capiutil.h"
+#include "capilli.h"
+#include "avmcard.h"
+
+static char *revision = "$Revision: 1.4 $";
+
+/* ------------------------------------------------------------- */
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
+static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+ avmcard *card;
+
+ card = (avmcard *) devptr;
+
+ if (!card) {
+ printk(KERN_WARNING "b1_interrupt: wrong device\n");
+ return;
+ }
+ if (card->interrupt) {
+ printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name);
+ return;
+ }
+
+ card->interrupt = 1;
+
+ b1_handle_interrupt(card);
+
+ card->interrupt = 0;
+}
+/* ------------------------------------------------------------- */
+
+static void b1isa_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+
+ b1_reset(port);
+ b1_reset(port);
+
+ di->detach_ctr(ctrl);
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------- */
+
+static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
+{
+ avmcard *card;
+ int retval;
+
+ card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+ if (!card) {
+ printk(KERN_WARNING "b1isa: no memory.\n");
+ return -ENOMEM;
+ }
+ memset(card, 0, sizeof(avmcard));
+ sprintf(card->name, "b1isa-%x", p->port);
+ card->port = p->port;
+ card->irq = p->irq;
+ card->cardtype = avm_b1isa;
+
+ if (check_region(card->port, AVMB1_PORTLEN)) {
+ printk(KERN_WARNING
+ "b1isa: ports 0x%03x-0x%03x in use.\n",
+ card->port, card->port + AVMB1_PORTLEN);
+ kfree(card);
+ return -EBUSY;
+ }
+ if (b1_irq_table[card->irq & 0xf] == 0) {
+ printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq);
+ kfree(card);
+ return -EINVAL;
+ }
+ if ( card->port != 0x150 && card->port != 0x250
+ && card->port != 0x300 && card->port != 0x340) {
+ printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port);
+ kfree(card);
+ return -EINVAL;
+ }
+ b1_reset(card->port);
+ if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
+ printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n",
+ card->port, retval);
+ kfree(card);
+ return -EIO;
+ }
+ b1_reset(card->port);
+
+ request_region(p->port, AVMB1_PORTLEN, card->name);
+
+ retval = request_irq(card->irq, b1isa_interrupt, 0, card->name, card);
+ if (retval) {
+ printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ card->ctrl = di->attach_ctr(driver, card->name, card);
+ if (!card->ctrl) {
+ printk(KERN_ERR "b1isa: attach controller failed.\n");
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static char *b1isa_procinfo(struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ if (!card)
+ return "";
+ sprintf(card->infobuf, "%s %s 0x%x %d",
+ card->cardname[0] ? card->cardname : "-",
+ card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
+ card->port, card->irq
+ );
+ return card->infobuf;
+}
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver b1isa_driver = {
+ "b1isa",
+ "0.0",
+ b1_load_firmware,
+ b1_reset_ctr,
+ b1isa_remove_ctr,
+ b1_register_appl,
+ b1_release_appl,
+ b1_send_message,
+
+ b1isa_procinfo,
+ b1ctl_read_proc,
+ 0, /* use standard driver_read_proc */
+
+ b1isa_add_card,
+};
+
+#ifdef MODULE
+#define b1isa_init init_module
+void cleanup_module(void);
+#endif
+
+int b1isa_init(void)
+{
+ struct capi_driver *driver = &b1isa_driver;
+ char *p;
+
+ if ((p = strchr(revision, ':'))) {
+ strncpy(driver->revision, p + 1, sizeof(driver->revision));
+ p = strchr(driver->revision, '$');
+ *p = 0;
+ }
+
+ printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
+
+ di = attach_capi_driver(driver);
+
+ if (!di) {
+ printk(KERN_ERR "%s: failed to attach capi_driver\n",
+ driver->name);
+ return -EIO;
+ }
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ detach_capi_driver(&b1isa_driver);
+}
+#endif
diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c
index 112ddbb81..8c0006a78 100644
--- a/drivers/isdn/avmb1/b1pci.c
+++ b/drivers/isdn/avmb1/b1pci.c
@@ -1,59 +1,65 @@
/*
- * $Id: b1pci.c,v 1.9 1999/04/15 19:49:32 calle Exp $
+ * $Id: b1pci.c,v 1.16 1999/08/11 21:01:07 keil Exp $
*
* Module for AVM B1 PCI-card.
*
- * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1pci.c,v $
- * Revision 1.9 1999/04/15 19:49:32 calle
- * fix fuer die B1-PCI. Jetzt geht z.B. auch IRQ 17 ...
+ * Revision 1.16 1999/08/11 21:01:07 keil
+ * new PCI codefix
*
- * Revision 1.8 1998/06/17 19:51:16 he
- * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
- * brute force fix to avoid Ugh's in isdn_tty_write()
- * cleaned up some dead code
+ * Revision 1.15 1999/08/10 16:02:27 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
*
- * Revision 1.7 1998/03/29 16:06:02 calle
- * changes from 2.0 tree merged.
+ * Revision 1.14 1999/07/09 15:05:41 keil
+ * compat.h is now isdn_compat.h
*
- * Revision 1.2.2.2 1998/01/23 16:49:30 calle
- * added functions for pcmcia cards,
- * avmb1_addcard returns now the controller number.
+ * Revision 1.13 1999/07/05 15:09:50 calle
+ * - renamed "appl_release" to "appl_released".
+ * - version und profile data now cleared on controller reset
+ * - extended /proc interface, to allow driver and controller specific
+ * informations to include by driver hackers.
*
- * Revision 1.6 1998/02/25 09:15:36 fritz
- * apply Martin's pci driver patch to isdn drivers (vgerCVS)
+ * Revision 1.12 1999/07/01 15:26:29 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
*
- * 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.
- * changed info messages for B1-PCI
- *
- * Revision 1.1 1997/03/30 17:10:42 calle
- * added support for AVM-B1-PCI card.
*
*/
#include <linux/config.h>
-#include <linux/string.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/pci.h>
#include <linux/skbuff.h>
-#include "compat.h"
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
#include <linux/capi.h>
-#include <linux/b1lli.h>
+#include <asm/io.h>
+#include <linux/isdn_compat.h>
+#include "capicmd.h"
+#include "capiutil.h"
+#include "capilli.h"
+#include "avmcard.h"
+
+static char *revision = "$Revision: 1.16 $";
+
+/* ------------------------------------------------------------- */
#ifndef PCI_VENDOR_ID_AVM
#define PCI_VENDOR_ID_AVM 0x1244
@@ -63,65 +69,213 @@
#define PCI_DEVICE_ID_AVM_B1 0x700
#endif
-static char *revision = "$Revision: 1.9 $";
-
/* ------------------------------------------------------------- */
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
/* ------------------------------------------------------------- */
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
+static void b1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+ avmcard *card;
+
+ card = (avmcard *) devptr;
+
+ if (!card) {
+ printk(KERN_WARNING "b1_interrupt: wrong device\n");
+ return;
+ }
+ if (card->interrupt) {
+ printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name);
+ return;
+ }
+
+ card->interrupt = 1;
+
+ b1_handle_interrupt(card);
+
+ card->interrupt = 0;
+}
+/* ------------------------------------------------------------- */
+
+static void b1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+
+ b1_reset(port);
+ b1_reset(port);
+
+ di->detach_ctr(ctrl);
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ ctrl->driverdata = 0;
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
+}
+
/* ------------------------------------------------------------- */
-/* -------- Init & Cleanup ------------------------------------- */
+
+static char *b1pci_procinfo(struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ if (!card)
+ return "";
+ sprintf(card->infobuf, "%s %s 0x%x %d",
+ card->cardname[0] ? card->cardname : "-",
+ card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
+ card->port, card->irq
+ );
+ return card->infobuf;
+}
+
/* ------------------------------------------------------------- */
-/*
- * init / exit functions
- */
+static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
+{
+ avmcard *card;
+ int retval;
+
+ card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+ if (!card) {
+ printk(KERN_WARNING "b1pci: no memory.\n");
+ return -ENOMEM;
+ }
+ memset(card, 0, sizeof(avmcard));
+ sprintf(card->name, "b1pci-%x", p->port);
+ card->port = p->port;
+ card->irq = p->irq;
+ card->cardtype = avm_b1pci;
+
+ if (check_region(card->port, AVMB1_PORTLEN)) {
+ printk(KERN_WARNING
+ "b1pci: ports 0x%03x-0x%03x in use.\n",
+ card->port, card->port + AVMB1_PORTLEN);
+ kfree(card);
+ return -EBUSY;
+ }
+ b1_reset(card->port);
+ if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
+ printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
+ card->port, retval);
+ kfree(card);
+ return -EIO;
+ }
+ b1_reset(card->port);
+
+ request_region(p->port, AVMB1_PORTLEN, card->name);
+
+ retval = request_irq(card->irq, b1pci_interrupt, 0, card->name, card);
+ if (retval) {
+ printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ card->ctrl = di->attach_ctr(driver, card->name, card);
+ if (!card->ctrl) {
+ printk(KERN_ERR "b1pci: attach controller failed.\n");
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver b1pci_driver = {
+ "b1pci",
+ "0.0",
+ b1_load_firmware,
+ b1_reset_ctr,
+ b1pci_remove_ctr,
+ b1_register_appl,
+ b1_release_appl,
+ b1_send_message,
+
+ b1pci_procinfo,
+ b1ctl_read_proc,
+ 0, /* use standard driver_read_proc */
+
+ 0, /* no add_card function */
+};
#ifdef MODULE
#define b1pci_init init_module
+void cleanup_module(void);
#endif
+static int ncards = 0;
+
int b1pci_init(void)
{
- char *p;
- char rev[10];
- int rc;
+ struct capi_driver *driver = &b1pci_driver;
struct pci_dev *dev = NULL;
+ char *p;
+ int retval;
if ((p = strchr(revision, ':'))) {
- strcpy(rev, p + 1);
- p = strchr(rev, '$');
+ strncpy(driver->revision, p + 1, sizeof(driver->revision));
+ p = strchr(driver->revision, '$');
*p = 0;
- } else
- strcpy(rev, " ??? ");
+ }
+
+ printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
+ di = attach_capi_driver(driver);
+
+ if (!di) {
+ printk(KERN_ERR "%s: failed to attach capi_driver\n",
+ driver->name);
+ return -EIO;
+ }
#ifdef CONFIG_PCI
if (!pci_present()) {
- printk(KERN_ERR "b1pci: no PCI bus present\n");
+ printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
+ detach_capi_driver(driver);
return -EIO;
}
- printk(KERN_INFO "b1pci: revision %s\n", rev);
-
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;
+ struct capicardparams param;
+
+ param.port = get_pcibase(dev, 1) & PCI_BASE_ADDRESS_IO_MASK;
+ param.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, AVM_CARDTYPE_B1PCI)) != 0) {
+ "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
+ driver->name, param.port, param.irq);
+ retval = b1pci_add_card(driver, &param);
+ if (retval != 0) {
printk(KERN_ERR
- "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n",
- ioaddr, irq);
- return rc;
+ "%s: no AVM-B1 at i/o %#x, irq %d detected\n",
+ driver->name, param.port, param.irq);
+#ifdef MODULE
+ cleanup_module();
+#endif
+ return retval;
}
- if ((rc = avmb1_addcard(ioaddr, irq, AVM_CARDTYPE_B1PCI)) < 0)
- return rc;
+ ncards++;
}
- return 0;
+ if (ncards) {
+ printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n",
+ driver->name, ncards);
+ return 0;
+ }
+ printk(KERN_ERR "%s: NO B1-PCI card detected\n", driver->name);
+ return -ESRCH;
#else
printk(KERN_ERR "b1pci: kernel not compiled with PCI.\n");
return -EIO;
@@ -131,5 +285,6 @@ int b1pci_init(void)
#ifdef MODULE
void cleanup_module(void)
{
+ detach_capi_driver(&b1pci_driver);
}
#endif
diff --git a/drivers/isdn/avmb1/b1pcmcia.c b/drivers/isdn/avmb1/b1pcmcia.c
new file mode 100644
index 000000000..d6acda9d9
--- /dev/null
+++ b/drivers/isdn/avmb1/b1pcmcia.c
@@ -0,0 +1,272 @@
+/*
+ * $Id: b1pcmcia.c,v 1.4 1999/08/22 20:26:26 calle Exp $
+ *
+ * Module for AVM B1/M1/M2 PCMCIA-card.
+ *
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1pcmcia.c,v $
+ * Revision 1.4 1999/08/22 20:26:26 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.3 1999/07/09 15:05:41 keil
+ * compat.h is now isdn_compat.h
+ *
+ * Revision 1.2 1999/07/05 15:09:51 calle
+ * - renamed "appl_release" to "appl_released".
+ * - version und profile data now cleared on controller reset
+ * - extended /proc interface, to allow driver and controller specific
+ * informations to include by driver hackers.
+ *
+ * Revision 1.1 1999/07/01 15:26:30 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <linux/capi.h>
+#include <linux/b1pcmcia.h>
+#include <linux/isdn_compat.h>
+#include "capicmd.h"
+#include "capiutil.h"
+#include "capilli.h"
+#include "avmcard.h"
+
+static char *revision = "$Revision: 1.4 $";
+
+/* ------------------------------------------------------------- */
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
+static void b1pcmcia_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+ avmcard *card;
+
+ card = (avmcard *) devptr;
+
+ if (!card) {
+ printk(KERN_WARNING "b1_interrupt: wrong device\n");
+ return;
+ }
+ if (card->interrupt) {
+ printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name);
+ return;
+ }
+
+ card->interrupt = 1;
+
+ b1_handle_interrupt(card);
+
+ card->interrupt = 0;
+}
+/* ------------------------------------------------------------- */
+
+static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+
+ b1_reset(port);
+ b1_reset(port);
+
+ di->detach_ctr(ctrl);
+ free_irq(card->irq, card);
+ /* io addrsses managent by CardServices
+ * release_region(card->port, AVMB1_PORTLEN);
+ */
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------- */
+
+static int b1pcmcia_add_card(struct capi_driver *driver,
+ unsigned int port,
+ unsigned irq,
+ enum avmcardtype cardtype)
+{
+ avmcard *card;
+ int retval;
+
+ card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+ if (!card) {
+ printk(KERN_WARNING "b1pcmcia: no memory.\n");
+ return -ENOMEM;
+ }
+ memset(card, 0, sizeof(avmcard));
+ switch (cardtype) {
+ case avm_m1: sprintf(card->name, "m1-%x", port); break;
+ case avm_m2: sprintf(card->name, "m2-%x", port); break;
+ default: sprintf(card->name, "b1pcmcia-%x", port); break;
+ }
+ card->port = port;
+ card->irq = irq;
+ card->cardtype = cardtype;
+
+ b1_reset(card->port);
+ if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
+ printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n",
+ card->port, retval);
+ kfree(card);
+ return -EIO;
+ }
+ b1_reset(card->port);
+
+ retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card);
+ if (retval) {
+ printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n", card->irq);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ card->ctrl = di->attach_ctr(driver, card->name, card);
+ if (!card->ctrl) {
+ printk(KERN_ERR "b1pcmcia: attach controller failed.\n");
+ free_irq(card->irq, card);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ MOD_INC_USE_COUNT;
+ return card->ctrl->cnr;
+}
+
+/* ------------------------------------------------------------- */
+
+static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ if (!card)
+ return "";
+ sprintf(card->infobuf, "%s %s 0x%x %d",
+ card->cardname[0] ? card->cardname : "-",
+ card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
+ card->port, card->irq
+ );
+ return card->infobuf;
+}
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver b1pcmcia_driver = {
+ "b1pcmcia",
+ "0.0",
+ b1_load_firmware,
+ b1_reset_ctr,
+ b1pcmcia_remove_ctr,
+ b1_register_appl,
+ b1_release_appl,
+ b1_send_message,
+
+ b1pcmcia_procinfo,
+ b1ctl_read_proc,
+ 0, /* use standard driver_read_proc */
+
+ 0,
+};
+
+/* ------------------------------------------------------------- */
+
+int b1pcmcia_addcard_b1(unsigned int port, unsigned irq)
+{
+ return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_b1pcmcia);
+}
+
+int b1pcmcia_addcard_m1(unsigned int port, unsigned irq)
+{
+ return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m1);
+}
+
+int b1pcmcia_addcard_m2(unsigned int port, unsigned irq)
+{
+ return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m2);
+}
+
+int b1pcmcia_delcard(unsigned int port, unsigned irq)
+{
+ struct capi_ctr *ctrl;
+ avmcard *card;
+
+ for (ctrl = b1pcmcia_driver.controller; ctrl; ctrl = ctrl->next) {
+ card = (avmcard *)(ctrl->driverdata);
+ if (card->port == port && card->irq == irq) {
+ b1pcmcia_remove_ctr(ctrl);
+ return 0;
+ }
+ }
+ return -ESRCH;
+}
+
+EXPORT_SYMBOL(b1pcmcia_addcard_b1);
+EXPORT_SYMBOL(b1pcmcia_addcard_m1);
+EXPORT_SYMBOL(b1pcmcia_addcard_m2);
+EXPORT_SYMBOL(b1pcmcia_delcard);
+
+/* ------------------------------------------------------------- */
+
+#ifdef MODULE
+#define b1pcmcia_init init_module
+void cleanup_module(void);
+#endif
+
+int b1pcmcia_init(void)
+{
+ struct capi_driver *driver = &b1pcmcia_driver;
+ char *p;
+
+ if ((p = strchr(revision, ':'))) {
+ strncpy(driver->revision, p + 1, sizeof(driver->revision));
+ p = strchr(driver->revision, '$');
+ *p = 0;
+ }
+
+ printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
+
+ di = attach_capi_driver(driver);
+
+ if (!di) {
+ printk(KERN_ERR "%s: failed to attach capi_driver\n",
+ driver->name);
+ return -EIO;
+ }
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ detach_capi_driver(&b1pcmcia_driver);
+}
+#endif
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index 69ed317f3..c8cab6919 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -1,11 +1,43 @@
/*
- * $Id: capi.c,v 1.13 1998/08/28 04:32:25 calle Exp $
+ * $Id: capi.c,v 1.19 1999/07/09 15:05:42 keil Exp $
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capi.c,v $
+ * Revision 1.19 1999/07/09 15:05:42 keil
+ * compat.h is now isdn_compat.h
+ *
+ * Revision 1.18 1999/07/06 07:42:01 calle
+ * - changes in /proc interface
+ * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
+ *
+ * Revision 1.17 1999/07/01 15:26:30 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ * Revision 1.16 1999/07/01 08:22:57 keil
+ * compatibility macros now in <linux/isdn_compat.h>
+ *
+ * Revision 1.15 1999/06/21 15:24:11 calle
+ * extend information in /proc.
+ *
+ * Revision 1.14 1999/06/10 16:51:03 calle
+ * Bugfix: open/release of control device was not handled correct.
+ *
* Revision 1.13 1998/08/28 04:32:25 calle
* Added patch send by Michael.Mueller4@post.rwth-aachen.de, to get AVM B1
* driver running with 2.1.118.
@@ -80,11 +112,12 @@
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
-#include "compat.h"
+#include <linux/isdn_compat.h>
#include "capiutil.h"
#include "capicmd.h"
#include "capidev.h"
@@ -178,7 +211,10 @@ static ssize_t capi_read(struct file *file, char *buf,
}
copied = skb->len;
-
+ if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
+ && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND)
+ cdev->nrecvdatapkt++;
+ else cdev->nrecvctlpkt++;
kfree_skb(skb);
return copied;
@@ -207,7 +243,7 @@ static ssize_t capi_write(struct file *file, const char *buf,
skb = alloc_skb(count, GFP_USER);
if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
- dev_kfree_skb(skb);
+ kfree_skb(skb);
return retval;
}
cmd = CAPIMSG_COMMAND(skb->data);
@@ -216,11 +252,11 @@ static ssize_t capi_write(struct file *file, const char *buf,
if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {
__u16 dlen = CAPIMSG_DATALEN(skb->data);
if (mlen + dlen != count) {
- dev_kfree_skb(skb);
+ kfree_skb(skb);
return -EINVAL;
}
} else if (mlen != count) {
- dev_kfree_skb(skb);
+ kfree_skb(skb);
return -EINVAL;
}
CAPIMSG_SETAPPID(skb->data, cdev->applid);
@@ -228,9 +264,12 @@ static ssize_t capi_write(struct file *file, const char *buf,
cdev->errcode = (*capifuncs->capi_put_message) (cdev->applid, skb);
if (cdev->errcode) {
- dev_kfree_skb(skb);
+ kfree_skb(skb);
return -EIO;
}
+ if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ)
+ cdev->nsentdatapkt++;
+ else cdev->nsentctlpkt++;
return count;
}
@@ -426,16 +465,13 @@ static int capi_open(struct inode *inode, struct file *file)
capidevs[minor].is_open = 1;
skb_queue_head_init(&capidevs[minor].recv_queue);
MOD_INC_USE_COUNT;
+ capidevs[minor].nopen++;
} else {
-
- if (!capidevs[minor].is_open) {
- capidevs[minor].is_open = 1;
- MOD_INC_USE_COUNT;
- }
+ capidevs[minor].is_open++;
+ MOD_INC_USE_COUNT;
}
-
return 0;
}
@@ -460,10 +496,13 @@ capi_release(struct inode *inode, struct file *file)
cdev->is_registered = 0;
cdev->applid = 0;
- while ((skb = skb_dequeue(&cdev->recv_queue)) != 0)
+ while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) {
kfree_skb(skb);
+ }
+ cdev->is_open = 0;
+ } else {
+ cdev->is_open--;
}
- cdev->is_open = 0;
MOD_DEC_USE_COUNT;
return 0;
@@ -487,7 +526,82 @@ static struct file_operations capi_fops =
NULL, /* capi_fasync */
};
+/* -------- /proc functions ----------------------------------- */
+/*
+ * /proc/capi/capi20:
+ * minor opencount nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
+ */
+static int proc_capidev_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capidev *cp;
+ int i;
+ int len = 0;
+ off_t begin = 0;
+
+ for (i=0; i < CAPI_MAXMINOR; i++) {
+ cp = &capidevs[i+1];
+ if (cp->nopen == 0) continue;
+ len += sprintf(page+len, "%d %lu %lu %lu %lu %lu\n",
+ i+1,
+ cp->nopen,
+ cp->nrecvctlpkt,
+ cp->nrecvdatapkt,
+ cp->nsentctlpkt,
+ cp->nsentdatapkt);
+ if (len+begin > off+count)
+ goto endloop;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+endloop:
+ if (i >= CAPI_MAXMINOR)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+static struct procfsentries {
+ char *name;
+ mode_t mode;
+ int (*read_proc)(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+ struct proc_dir_entry *procent;
+} procfsentries[] = {
+ /* { "capi", S_IFDIR, 0 }, */
+ { "capi/capi20", 0 , proc_capidev_read_proc },
+};
+
+static void proc_init(void)
+{
+ int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+ int i;
+
+ for (i=0; i < nelem; i++) {
+ struct procfsentries *p = procfsentries + i;
+ p->procent = create_proc_entry(p->name, p->mode, 0);
+ if (p->procent) p->procent->read_proc = p->read_proc;
+ }
+}
+
+static void proc_exit(void)
+{
+ int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+ int i;
+
+ for (i=nelem-1; i >= 0; i--) {
+ struct procfsentries *p = procfsentries + i;
+ if (p->procent) {
+ remove_proc_entry(p->name, 0);
+ p->procent = 0;
+ }
+ }
+}
/* -------- init function and module interface ---------------------- */
#ifdef MODULE
@@ -501,12 +615,12 @@ static struct capi_interface_user cuser = {
int capi_init(void)
{
-#if LINUX_VERSION_CODE >= 131841
+#ifdef COMPAT_HAS_NEW_WAITQ
int j;
#endif
memset(capidevs, 0, sizeof(capidevs));
-#if LINUX_VERSION_CODE >= 131841
+#ifdef COMPAT_HAS_NEW_WAITQ
for ( j = 0; j < CAPI_MAXMINOR+1; j++ ) {
init_waitqueue_head(&capidevs[j].recv_wait);
}
@@ -522,13 +636,14 @@ int capi_init(void)
unregister_chrdev(capi_major, "capi20");
return -EIO;
}
-
+ (void)proc_init();
return 0;
}
#ifdef MODULE
void cleanup_module(void)
{
+ (void)proc_exit();
unregister_chrdev(capi_major, "capi20");
(void) detach_capi_interface(&cuser);
}
diff --git a/drivers/isdn/avmb1/capidev.h b/drivers/isdn/avmb1/capidev.h
index bd57255b6..c66554a29 100644
--- a/drivers/isdn/avmb1/capidev.h
+++ b/drivers/isdn/avmb1/capidev.h
@@ -1,11 +1,33 @@
/*
- * $Id: capidev.h,v 1.1 1997/03/04 21:50:30 calle Exp $
+ * $Id: capidev.h,v 1.4 1999/07/01 15:26:32 calle Exp $
*
* CAPI 2.0 Interface for Linux
*
* (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capidev.h,v $
+ * Revision 1.4 1999/07/01 15:26:32 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ * Revision 1.3 1999/07/01 08:22:58 keil
+ * compatibility macros now in <linux/isdn_compat.h>
+ *
+ * Revision 1.2 1999/06/21 15:24:13 calle
+ * extend information in /proc.
+ *
* Revision 1.1 1997/03/04 21:50:30 calle
* Frirst version in isdn4linux
*
@@ -22,12 +44,18 @@ struct capidev {
int is_registered;
__u16 applid;
struct sk_buff_head recv_queue;
-#if LINUX_VERSION_CODE < 131841
- struct wait_queue *recv_wait;
-#else
+#ifdef COMPAT_HAS_NEW_WAITQ
wait_queue_head_t recv_wait;
+#else
+ struct wait_queue *recv_wait;
#endif
__u16 errcode;
+ /* Statistic */
+ unsigned long nopen;
+ unsigned long nrecvctlpkt;
+ unsigned long nrecvdatapkt;
+ unsigned long nsentctlpkt;
+ unsigned long nsentdatapkt;
};
#define CAPI_MAXMINOR CAPI_MAXAPPL
diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c
index 80a2eccdb..fb83e52a6 100644
--- a/drivers/isdn/avmb1/capidrv.c
+++ b/drivers/isdn/avmb1/capidrv.c
@@ -1,11 +1,67 @@
/*
- * $Id: capidrv.c,v 1.13 1998/06/26 15:12:55 fritz Exp $
+ * $Id: capidrv.c,v 1.26 1999/08/06 07:41:16 calle Exp $
*
* ISDN4Linux Driver, using capi20 interface (kernelcapi)
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capidrv.c,v $
+ * Revision 1.26 1999/08/06 07:41:16 calle
+ * Added the "vbox patch". if (si1 == 1) si2 = 0;
+ *
+ * Revision 1.25 1999/08/04 10:10:11 calle
+ * Bugfix: corrected /proc functions, added structure for new AVM cards.
+ *
+ * Revision 1.24 1999/07/20 06:48:02 calle
+ * Bugfix: firmware version check for D2 trace was too restrictiv.
+ *
+ * Revision 1.23 1999/07/09 15:05:44 keil
+ * compat.h is now isdn_compat.h
+ *
+ * Revision 1.22 1999/07/06 07:24:14 calle
+ * Bugfix: call to kfree_skb in capidrv_signal was too early,
+ * thanks to Lars Heete <hel@admin.de>.
+ *
+ * Revision 1.21 1999/07/01 15:26:34 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ * Revision 1.20 1999/07/01 08:22:59 keil
+ * compatibility macros now in <linux/isdn_compat.h>
+ *
+ * Revision 1.19 1999/06/29 16:16:54 calle
+ * Let ISDN_CMD_UNLOAD work with open isdn devices without crash again.
+ * Also right unlocking (ISDN_CMD_UNLOCK) is done now.
+ * isdnlog should check returncode of read(2) calls.
+ *
+ * Revision 1.18 1999/06/21 15:24:15 calle
+ * extend information in /proc.
+ *
+ * Revision 1.17 1999/06/10 16:53:55 calle
+ * Removing of module b1pci will now remove card from lower level.
+ *
+ * Revision 1.16 1999/05/31 11:50:33 calle
+ * Bugfix: In if_sendbuf, skb_push'ed DATA_B3 header was not skb_pull'ed
+ * on failure, result in data block with DATA_B3 header transmitted
+ *
+ * Revision 1.15 1999/05/25 21:26:16 calle
+ * Include CAPI-Channelallocation (leased lines) from the 2.0 tree.
+ *
+ * Revision 1.14 1999/05/22 07:55:06 calle
+ * Added *V110* to AVM B1 driver.
+ *
* Revision 1.13 1998/06/26 15:12:55 fritz
* Added handling of STAT_ICALL with incomplete CPN.
* Added AT&L for ttyI emulator.
@@ -96,15 +152,18 @@
#include <linux/skbuff.h>
#include <linux/isdn.h>
#include <linux/isdnif.h>
+#include <linux/proc_fs.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
+#include <linux/ctype.h>
+#include <asm/segment.h>
-#include "compat.h"
+#include <linux/isdn_compat.h>
#include "capiutil.h"
#include "capicmd.h"
#include "capidrv.h"
-static char *revision = "$Revision: 1.13 $";
+static char *revision = "$Revision: 1.26 $";
int debugmode = 0;
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -160,6 +219,7 @@ struct capidrv_contr {
__u16 msgid; /* to identfy CONNECT_CONF */
int chan;
int state;
+ int leasedline;
struct capidrv_ncci {
struct capidrv_ncci *next;
struct capidrv_plci *plcip;
@@ -194,6 +254,12 @@ struct capidrv_data {
__u16 appid;
int ncontr;
struct capidrv_contr *contr_list;
+
+ /* statistic */
+ unsigned long nrecvctlpkt;
+ unsigned long nrecvdatapkt;
+ unsigned long nsentctlpkt;
+ unsigned long nsentdatapkt;
};
typedef struct capidrv_plci capidrv_plci;
@@ -224,6 +290,12 @@ static inline __u32 b1prot(int l2, int l3)
return 0;
case ISDN_PROTO_L2_TRANS:
return 1;
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
+ return 2;
+ case ISDN_PROTO_L2_FAX:
+ return 4;
}
}
@@ -237,7 +309,12 @@ static inline __u32 b2prot(int l2, int l3)
return 0;
case ISDN_PROTO_L2_HDLC:
case ISDN_PROTO_L2_TRANS:
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
return 1;
+ case ISDN_PROTO_L2_FAX:
+ return 4;
}
}
@@ -249,8 +326,45 @@ static inline __u32 b3prot(int l2, int l3)
case ISDN_PROTO_L2_X75BUI:
case ISDN_PROTO_L2_HDLC:
case ISDN_PROTO_L2_TRANS:
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
default:
return 0;
+ case ISDN_PROTO_L2_FAX:
+ return 4;
+ }
+}
+
+static _cstruct b1config_sync_v110(__u16 rate)
+{
+ /* CAPI-Spec "B1 Configuration" */
+ static unsigned char buf[9];
+ buf[0] = 8; /* len */
+ /* maximum bitrate */
+ buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
+ buf[3] = buf[4] = 0; /* reserved, bits per character */
+ buf[5] = buf[6] = 0; /* reserved, parity */
+ buf[7] = buf[9] = 0; /* reserved, stop bits */
+ return buf;
+}
+
+static _cstruct b1config(int l2, int l3)
+{
+ switch (l2) {
+ case ISDN_PROTO_L2_X75I:
+ case ISDN_PROTO_L2_X75UI:
+ case ISDN_PROTO_L2_X75BUI:
+ case ISDN_PROTO_L2_HDLC:
+ case ISDN_PROTO_L2_TRANS:
+ default:
+ return 0;
+ case ISDN_PROTO_L2_V11096:
+ return b1config_sync_v110(9600);
+ case ISDN_PROTO_L2_V11019:
+ return b1config_sync_v110(19200);
+ case ISDN_PROTO_L2_V11038:
+ return b1config_sync_v110(38400);
}
}
@@ -522,9 +636,10 @@ static void send_message(capidrv_contr * card, _cmsg * cmsg)
size_t len;
capi_cmsg2message(cmsg, cmsg->buf);
len = CAPIMSG_LEN(cmsg->buf);
- skb = dev_alloc_skb(len);
+ skb = alloc_skb(len, GFP_ATOMIC);
memcpy(skb_put(skb, len), cmsg->buf, len);
(*capifuncs->capi_put_message) (global.appid, skb);
+ global.nsentctlpkt++;
}
/* -------- state machine -------------------------------------------- */
@@ -917,6 +1032,13 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
cmd.parm.setup.si2,
cmd.parm.setup.eazmsn);
+ if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
+ printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n",
+ card->contrnr,
+ cmd.parm.setup.si2);
+ cmd.parm.setup.si2 = 0;
+ }
+
switch (card->interface.statcallb(&cmd)) {
case 0:
case 3:
@@ -1353,6 +1475,7 @@ static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
capi_cmd2str(cmsg->Command, cmsg->Subcommand),
cmsg->adr.adrController & 0x7f);
+ kfree_skb(skb);
return;
}
if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
@@ -1377,13 +1500,14 @@ static void capidrv_signal(__u16 applid, __u32 dummy)
while ((*capifuncs->capi_get_message) (global.appid, &skb) == CAPI_NOERROR) {
capi_message2cmsg(&s_cmsg, skb->data);
- if (debugmode > 1)
+ if (debugmode > 2)
printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n",
applid, capi_cmsg2str(&s_cmsg));
if (s_cmsg.Command == CAPI_DATA_B3
&& s_cmsg.Subcommand == CAPI_IND) {
handle_data(&s_cmsg, skb);
+ global.nrecvdatapkt++;
continue;
}
if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
@@ -1392,8 +1516,13 @@ static void capidrv_signal(__u16 applid, __u32 dummy)
handle_plci(&s_cmsg);
else
handle_ncci(&s_cmsg);
-
+ /*
+ * data of skb used in s_cmsg,
+ * free data when s_cmsg is not used again
+ * thanks to Lars Heete <hel@admin.de>
+ */
kfree_skb(skb);
+ global.nrecvctlpkt++;
}
}
@@ -1459,6 +1588,11 @@ static _cmsg cmdcmsg;
static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
{
switch (c->arg) {
+ case 1:
+ debugmode = (int)(*((unsigned int *)c->parm.num));
+ printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
+ card->contrnr, debugmode);
+ return 0;
default:
printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
card->contrnr, c->arg);
@@ -1467,11 +1601,103 @@ static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
return -EINVAL;
}
+/*
+ * Handle leased lines (CAPI-Bundling)
+ */
+
+struct internal_bchannelinfo {
+ unsigned short channelalloc;
+ unsigned short operation;
+ unsigned char cmask[31];
+};
+
+static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
+{
+ unsigned long bmask = 0;
+ int active = !0;
+ char *s;
+ int i;
+
+ if (strncmp(teln, "FV:", 3) != 0)
+ return 1;
+ s = teln + 3;
+ while (*s && *s == ' ') s++;
+ if (!*s) return -2;
+ if (*s == 'p' || *s == 'P') {
+ active = 0;
+ s++;
+ }
+ if (*s == 'a' || *s == 'A') {
+ active = !0;
+ s++;
+ }
+ while (*s) {
+ int digit1 = 0;
+ int digit2 = 0;
+ if (!isdigit(*s)) return -3;
+ while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
+ if (digit1 <= 0 && digit1 > 30) return -4;
+ if (*s == 0 || *s == ',' || *s == ' ') {
+ bmask |= (1 << digit1);
+ digit1 = 0;
+ if (*s) s++;
+ continue;
+ }
+ if (*s != '-') return -5;
+ s++;
+ if (!isdigit(*s)) return -3;
+ while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
+ if (digit2 <= 0 && digit2 > 30) return -4;
+ if (*s == 0 || *s == ',' || *s == ' ') {
+ if (digit1 > digit2)
+ for (i = digit2; i <= digit1 ; i++)
+ bmask |= (1 << i);
+ else
+ for (i = digit1; i <= digit2 ; i++)
+ bmask |= (1 << i);
+ digit1 = digit2 = 0;
+ if (*s) s++;
+ continue;
+ }
+ return -6;
+ }
+ if (activep) *activep = active;
+ if (bmaskp) *bmaskp = bmask;
+ return 0;
+}
+
+static int FVteln2capi20(char *teln, __u8 AdditionalInfo[1+2+2+31])
+{
+ unsigned long bmask;
+ int active;
+ int rc, i;
+
+ rc = decodeFVteln(teln, &bmask, &active);
+ if (rc) return rc;
+ /* Length */
+ AdditionalInfo[0] = 2+2+31;
+ /* Channel: 3 => use channel allocation */
+ AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
+ /* Operation: 0 => DTE mode, 1 => DCE mode */
+ if (active) {
+ AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
+ } else {
+ AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
+ }
+ /* Channel mask array */
+ AdditionalInfo[5] = 0; /* no D-Channel */
+ for (i=1; i <= 30; i++)
+ AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0;
+ return 0;
+}
+
static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
{
isdn_ctrl cmd;
struct capidrv_bchan *bchan;
struct capidrv_plci *plcip;
+ __u8 AdditionalInfo[1+2+2+31];
+ int rc, isleasedline = 0;
if (c->command == ISDN_CMD_IOCTL)
return capidrv_ioctl(c, card);
@@ -1508,15 +1734,25 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
-
- calling[0] = strlen(bchan->mynum) + 2;
- calling[1] = 0;
- calling[2] = 0x80;
- strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
-
- called[0] = strlen(bchan->num) + 1;
- called[1] = 0x80;
- strncpy(called + 2, bchan->num, ISDN_MSNLEN);
+ rc = FVteln2capi20(bchan->num, AdditionalInfo);
+ isleasedline = (rc == 0);
+ if (rc < 0)
+ printk(KERN_ERR "capidrv-%d: WARNING: illegal leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
+
+ if (isleasedline) {
+ calling[0] = 0;
+ called[0] = 0;
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
+ } else {
+ calling[0] = strlen(bchan->mynum) + 2;
+ calling[1] = 0;
+ calling[2] = 0x80;
+ strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
+ called[0] = strlen(bchan->num) + 1;
+ called[1] = 0x80;
+ strncpy(called + 2, bchan->num, ISDN_MSNLEN);
+ }
capi_fill_CONNECT_REQ(&cmdcmsg,
global.appid,
@@ -1530,13 +1766,14 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
b1prot(bchan->l2, bchan->l3), /* B1protocol */
b2prot(bchan->l2, bchan->l3), /* B2protocol */
b3prot(bchan->l2, bchan->l3), /* B3protocol */
- 0, /* B1configuration */
+ b1config(bchan->l2, bchan->l3), /* B1configuration */
0, /* B2configuration */
0, /* B3configuration */
0, /* BC */
0, /* LLC */
0, /* HLC */
- 0, /* BChannelinformation */
+ /* BChannelinformation */
+ isleasedline ? AdditionalInfo : 0,
0, /* Keypadfacility */
0, /* Useruserdata */
0 /* Facilitydataarray */
@@ -1549,6 +1786,7 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
return -1;
}
plcip->msgid = cmdcmsg.Messagenumber;
+ plcip->leasedline = isleasedline;
plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
send_message(card, &cmdcmsg);
return 0;
@@ -1570,7 +1808,7 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
b1prot(bchan->l2, bchan->l3), /* B1protocol */
b2prot(bchan->l2, bchan->l3), /* B2protocol */
b3prot(bchan->l2, bchan->l3), /* B3protocol */
- 0, /* B1configuration */
+ b1config(bchan->l2, bchan->l3), /* B1configuration */
0, /* B2configuration */
0, /* B3configuration */
0, /* ConnectedNumber */
@@ -1752,6 +1990,9 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
card->contrnr, id);
return 0;
}
+ if (debugmode > 1)
+ printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
+ card->contrnr, len, skb, doack);
bchan = &card->bchans[channel % card->nbchan];
nccip = bchan->nccip;
if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
@@ -1774,23 +2015,23 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
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);
+ struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
if (!nskb) {
printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
card->contrnr);
(void)capidrv_del_ack(nccip, datahandle);
return 0;
}
-#if 0
- printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom\n",
- card->contrnr, skb_headroom(skb));
+#if 1
+ printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
+ card->contrnr, skb_headroom(skb), msglen);
#endif
- memcpy(skb_put(nskb, msglen), sendcmsg.buf, msglen);
- memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
+ memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
errcode = (*capifuncs->capi_put_message) (global.appid, nskb);
if (errcode == CAPI_NOERROR) {
dev_kfree_skb(skb);
nccip->datahandle++;
+ global.nsentdatapkt++;
return len;
}
(void)capidrv_del_ack(nccip, datahandle);
@@ -1801,8 +2042,10 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
errcode = (*capifuncs->capi_put_message) (global.appid, skb);
if (errcode == CAPI_NOERROR) {
nccip->datahandle++;
+ global.nsentdatapkt++;
return len;
}
+ skb_pull(skb, msglen);
(void)capidrv_del_ack(nccip, datahandle);
return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
}
@@ -1847,8 +2090,8 @@ static void enable_dchannel_trace(capidrv_contr *card)
return;
}
if (strstr(manufacturer, "AVM") == 0) {
- printk(KERN_ERR "%s: not from AVM, no d-channel trace possible\n",
- card->name);
+ printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
+ card->name, manufacturer);
return;
}
errcode = (*capifuncs->capi_get_version)(contr, &version);
@@ -1862,7 +2105,7 @@ static void enable_dchannel_trace(capidrv_contr *card)
avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
avmversion[2] |= version.minormanuversion & 0x0f;
- if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 6)) {
+ 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++,
@@ -1884,6 +2127,51 @@ static void enable_dchannel_trace(capidrv_contr *card)
send_message(card, &cmdcmsg);
}
+static void disable_dchannel_trace(capidrv_contr *card)
+{
+ __u8 manufacturer[CAPI_MANUFACTURER_LEN];
+ capi_version version;
+ __u16 contr = card->contrnr;
+ __u16 errcode;
+ __u16 avmversion[3];
+
+ errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
+ if (errcode != CAPI_NOERROR) {
+ printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
+ card->name, errcode);
+ return;
+ }
+ if (strstr(manufacturer, "AVM") == 0) {
+ printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
+ card->name, manufacturer);
+ return;
+ }
+ errcode = (*capifuncs->capi_get_version)(contr, &version);
+ if (errcode != CAPI_NOERROR) {
+ printk(KERN_ERR "%s: can't get version (0x%x)\n",
+ card->name, errcode);
+ return;
+ }
+ avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
+ avmversion[1] = (version.majormanuversion << 4) & 0xf0;
+ avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
+ avmversion[2] |= version.minormanuversion & 0x0f;
+
+ if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
+ printk(KERN_INFO "%s: D2 trace disabled\n", card->name);
+ } else {
+ printk(KERN_INFO "%s: D3 trace disabled\n", card->name);
+ }
+ capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
+ card->msgid++,
+ contr,
+ 0x214D5641, /* ManuID */
+ 0, /* Class */
+ 1, /* Function */
+ (_cstruct)"\004\000\000\000\000");
+ send_message(card, &cmdcmsg);
+}
+
static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
{
capidrv_contr *card;
@@ -1920,6 +2208,13 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
ISDN_FEATURE_L2_HDLC |
ISDN_FEATURE_L2_TRANS |
ISDN_FEATURE_L3_TRANS |
+ ISDN_FEATURE_L2_V11096 |
+ ISDN_FEATURE_L2_V11019 |
+ ISDN_FEATURE_L2_V11038 |
+#if 0
+ ISDN_FEATURE_L2_FAX |
+ ISDN_FEATURE_L3_FAX |
+#endif
ISDN_FEATURE_P_UNKNOWN;
card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
@@ -1964,8 +2259,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
printk(KERN_INFO "%s: now up (%d B channels)\n",
card->name, card->nbchan);
- if (card->nbchan == 2) /* no T1 */
- enable_dchannel_trace(card);
+ enable_dchannel_trace(card);
return 0;
}
@@ -1985,6 +2279,15 @@ static int capidrv_delcontr(__u16 contr)
return -1;
}
card = *pp;
+
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
+ card->contrnr, card->myid);
+
+ cmd.command = ISDN_STAT_UNLOAD;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+
*pp = (*pp)->next;
global.ncontr--;
@@ -1998,10 +2301,6 @@ static int capidrv_delcontr(__u16 contr)
}
kfree(card->bchans);
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
-
printk(KERN_INFO "%s: now down.\n", card->name);
kfree(card);
@@ -2012,16 +2311,78 @@ static int capidrv_delcontr(__u16 contr)
static void lower_callback(unsigned int cmd, __u16 contr, void *data)
{
+
switch (cmd) {
case KCI_CONTRUP:
+ printk(KERN_INFO "capidrv: controller %hu up\n", contr);
(void) capidrv_addcontr(contr, (capi_profile *) data);
break;
case KCI_CONTRDOWN:
+ printk(KERN_INFO "capidrv: controller %hu down\n", contr);
(void) capidrv_delcontr(contr);
break;
}
}
+/*
+ * /proc/capi/capidrv:
+ * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
+ */
+static int proc_capidrv_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf(page+len, "%lu %lu %lu %lu\n",
+ global.nrecvctlpkt,
+ global.nrecvdatapkt,
+ global.nsentctlpkt,
+ global.nsentdatapkt);
+ if (off+count >= len)
+ *eof = 1;
+ if (len < off)
+ return 0;
+ *start = page + off;
+ return ((count < len-off) ? count : len-off);
+}
+
+static struct procfsentries {
+ char *name;
+ mode_t mode;
+ int (*read_proc)(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+ struct proc_dir_entry *procent;
+} procfsentries[] = {
+ /* { "capi", S_IFDIR, 0 }, */
+ { "capi/capidrv", 0 , proc_capidrv_read_proc },
+};
+
+static void proc_init(void)
+{
+ int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+ int i;
+
+ for (i=0; i < nelem; i++) {
+ struct procfsentries *p = procfsentries + i;
+ p->procent = create_proc_entry(p->name, p->mode, 0);
+ if (p->procent) p->procent->read_proc = p->read_proc;
+ }
+}
+
+static void proc_exit(void)
+{
+ int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+ int i;
+
+ for (i=nelem-1; i >= 0; i--) {
+ struct procfsentries *p = procfsentries + i;
+ if (p->procent) {
+ remove_proc_entry(p->name, 0);
+ p->procent = 0;
+ }
+ }
+}
+
static struct capi_interface_user cuser = {
"capidrv",
lower_callback
@@ -2077,6 +2438,7 @@ int capidrv_init(void)
continue;
(void) capidrv_addcontr(contr, &profile);
}
+ proc_init();
return 0;
}
@@ -2098,11 +2460,13 @@ void cleanup_module(void)
for (card = global.contr_list; card; card = next) {
next = card->next;
+ disable_dchannel_trace(card);
capidrv_delcontr(card->contrnr);
}
(void) (*capifuncs->capi_release) (global.appid);
detach_capi_interface(&cuser);
+ proc_exit();
printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
}
diff --git a/drivers/isdn/avmb1/capilli.h b/drivers/isdn/avmb1/capilli.h
new file mode 100644
index 000000000..da64a183b
--- /dev/null
+++ b/drivers/isdn/avmb1/capilli.h
@@ -0,0 +1,110 @@
+/*
+ * $Id: capilli.h,v 1.4 1999/07/23 08:51:05 calle Exp $
+ *
+ * Kernel CAPI 2.0 Driver Interface for Linux
+ *
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ */
+#ifndef __CAPILLI_H__
+#define __CAPILLI_H__
+
+typedef struct capiloaddatapart {
+ int user; /* data in userspace ? */
+ int len;
+ unsigned char *data;
+} capiloaddatapart;
+
+typedef struct capiloaddata {
+ capiloaddatapart firmware;
+ capiloaddatapart configuration;
+} capiloaddata;
+
+typedef struct capicardparams {
+ unsigned int port;
+ unsigned irq;
+ int cardtype;
+ int cardnr;
+ unsigned int membase;
+} capicardparams;
+
+struct capi_driver;
+
+struct capi_ctr {
+ struct capi_ctr *next; /* next ctr of same driver */
+ struct capi_driver *driver;
+ int cnr; /* controller number */
+ char name[32]; /* name of controller */
+ volatile unsigned short cardstate; /* controller state */
+ volatile int blocked; /* output blocked */
+ int traceflag; /* capi trace */
+
+ void *driverdata; /* driver specific */
+
+ /* filled before calling ready callback */
+ __u8 manu[CAPI_MANUFACTURER_LEN]; /* CAPI_GET_MANUFACTURER */
+ capi_version version; /* CAPI_GET_VERSION */
+ capi_profile profile; /* CAPI_GET_PROFILE */
+ __u8 serial[CAPI_SERIAL_LEN]; /* CAPI_GET_SERIAL */
+
+ /* functions */
+ void (*ready)(struct capi_ctr * card);
+ void (*reseted)(struct capi_ctr * card);
+ void (*suspend_output)(struct capi_ctr * card);
+ void (*resume_output)(struct capi_ctr * card);
+ void (*handle_capimsg)(struct capi_ctr * card,
+ __u16 appl, struct sk_buff *skb);
+ void (*appl_registered)(struct capi_ctr * card, __u16 appl);
+ void (*appl_released)(struct capi_ctr * card, __u16 appl);
+
+ void (*new_ncci)(struct capi_ctr * card,
+ __u16 appl, __u32 ncci, __u32 winsize);
+ void (*free_ncci)(struct capi_ctr * card, __u16 appl, __u32 ncci);
+
+ /* management information for kcapi */
+
+ unsigned long nrecvctlpkt;
+ unsigned long nrecvdatapkt;
+ unsigned long nsentctlpkt;
+ unsigned long nsentdatapkt;
+
+ struct proc_dir_entry *procent;
+ char procfn[128];
+};
+
+struct capi_driver_interface {
+ struct capi_ctr *(*attach_ctr)(struct capi_driver *driver, char *name, void *data);
+ int (*detach_ctr)(struct capi_ctr *);
+};
+
+struct capi_driver {
+ char name[32]; /* driver name */
+ char revision[32];
+ int (*load_firmware)(struct capi_ctr *, capiloaddata *);
+ void (*reset_ctr)(struct capi_ctr *);
+ void (*remove_ctr)(struct capi_ctr *);
+ void (*register_appl)(struct capi_ctr *, __u16 appl,
+ capi_register_params *);
+ void (*release_appl)(struct capi_ctr *, __u16 appl);
+ void (*send_message)(struct capi_ctr *, struct sk_buff *skb);
+
+ char *(*procinfo)(struct capi_ctr *);
+ int (*ctr_read_proc)(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *card);
+ int (*driver_read_proc)(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_driver *driver);
+
+ int (*add_card)(struct capi_driver *driver, capicardparams *data);
+
+ /* intitialized by kcapi */
+ struct capi_ctr *controller; /* list of controllers */
+ struct capi_driver *next;
+ int ncontroller;
+ struct proc_dir_entry *procent;
+ char procfn[128];
+};
+
+struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver);
+void detach_capi_driver(struct capi_driver *driver);
+
+#endif /* __CAPILLI_H__ */
diff --git a/drivers/isdn/avmb1/capiutil.c b/drivers/isdn/avmb1/capiutil.c
index 8eb7d3ae1..7f1a9f1ad 100644
--- a/drivers/isdn/avmb1/capiutil.c
+++ b/drivers/isdn/avmb1/capiutil.c
@@ -1,5 +1,5 @@
/*
- * $Id: capiutil.c,v 1.6 1997/11/04 06:12:12 calle Exp $
+ * $Id: capiutil.c,v 1.9 1999/07/09 15:05:46 keil Exp $
*
* CAPI 2.0 convert capi message to capi message struct
*
@@ -7,6 +7,28 @@
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capiutil.c,v $
+ * Revision 1.9 1999/07/09 15:05:46 keil
+ * compat.h is now isdn_compat.h
+ *
+ * Revision 1.8 1999/07/01 15:26:37 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ * Revision 1.7 1999/07/01 08:23:01 keil
+ * compatibility macros now in <linux/isdn_compat.h>
+ *
* 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.
@@ -48,7 +70,7 @@
#include <asm/segment.h>
#include <linux/config.h>
-#include "compat.h"
+#include <linux/isdn_compat.h>
#include "capiutil.h"
/* from CAPI2.0 DDK AVM Berlin GmbH */
diff --git a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c
new file mode 100644
index 000000000..fc58f1241
--- /dev/null
+++ b/drivers/isdn/avmb1/kcapi.c
@@ -0,0 +1,1553 @@
+/*
+ * $Id: kcapi.c,v 1.6 1999/07/20 06:41:49 calle Exp $
+ *
+ * Kernel CAPI 2.0 Module
+ *
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: kcapi.c,v $
+ * Revision 1.6 1999/07/20 06:41:49 calle
+ * Bugfix: After the redesign of the AVM B1 driver, the driver didn't even
+ * compile, if not selected as modules.
+ *
+ * Revision 1.5 1999/07/09 15:05:48 keil
+ * compat.h is now isdn_compat.h
+ *
+ * Revision 1.4 1999/07/08 14:15:17 calle
+ * Forgot to count down ncards in drivercb_detach_ctr.
+ *
+ * Revision 1.3 1999/07/06 07:42:02 calle
+ * - changes in /proc interface
+ * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
+ *
+ * Revision 1.2 1999/07/05 15:09:52 calle
+ * - renamed "appl_release" to "appl_released".
+ * - version und profile data now cleared on controller reset
+ * - extended /proc interface, to allow driver and controller specific
+ * informations to include by driver hackers.
+ *
+ * Revision 1.1 1999/07/01 15:26:42 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ */
+#define CONFIG_AVMB1_COMPAT
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <asm/segment.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/tqueue.h>
+#include <linux/capi.h>
+#include <linux/kernelcapi.h>
+#include <linux/isdn_compat.h>
+#include "capicmd.h"
+#include "capiutil.h"
+#include "capilli.h"
+#ifdef CONFIG_AVMB1_COMPAT
+#include <linux/b1lli.h>
+#endif
+
+static char *revision = "$Revision: 1.6 $";
+
+/* ------------------------------------------------------------- */
+
+#define CARD_FREE 0
+#define CARD_DETECTED 1
+#define CARD_LOADING 2
+#define CARD_RUNNING 3
+
+/* ------------------------------------------------------------- */
+
+int showcapimsgs = 0;
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+MODULE_PARM(showcapimsgs, "0-4i");
+
+/* ------------------------------------------------------------- */
+
+struct msgidqueue {
+ struct msgidqueue *next;
+ __u16 msgid;
+};
+
+struct capi_ncci {
+ struct capi_ncci *next;
+ __u16 applid;
+ __u32 ncci;
+ __u32 winsize;
+ int nmsg;
+ struct msgidqueue *msgidqueue;
+ struct msgidqueue *msgidlast;
+ struct msgidqueue *msgidfree;
+ struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW];
+};
+
+struct capi_appl {
+ __u16 applid;
+ capi_register_params rparam;
+ int releasing;
+ __u32 param;
+ void (*signal) (__u16 applid, __u32 param);
+ struct sk_buff_head recv_queue;
+ int nncci;
+ struct capi_ncci *nccilist;
+
+ unsigned long nrecvctlpkt;
+ unsigned long nrecvdatapkt;
+ unsigned long nsentctlpkt;
+ unsigned long nsentdatapkt;
+};
+
+/* ------------------------------------------------------------- */
+
+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";
+
+#define APPL(a) (&applications[(a)-1])
+#define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)
+#define APPL_IS_FREE(a) (APPL(a)->applid == 0)
+#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0);
+#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0);
+
+#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
+
+#define VALID_CARD(c) ((c) > 0 && (c) <= CAPI_MAXCONTR)
+#define CARD(c) (&cards[(c)-1])
+#define CARDNR(cp) (((cp)-cards)+1)
+
+static struct capi_appl applications[CAPI_MAXAPPL];
+static struct capi_ctr cards[CAPI_MAXCONTR];
+static int ncards = 0;
+static struct sk_buff_head recv_queue;
+static struct capi_interface_user *capi_users = 0;
+static struct capi_driver *drivers;
+#ifdef CONFIG_AVMB1_COMPAT
+static struct capi_driver *b1isa_driver;
+static struct capi_driver *t1isa_driver;
+#endif
+static long notify_up_set = 0;
+static long notify_down_set = 0;
+
+static struct tq_struct tq_state_notify;
+static struct tq_struct tq_recv_notify;
+
+/* -------- util functions ------------------------------------ */
+
+static char *cardstate2str(unsigned short cardstate)
+{
+ switch (cardstate) {
+ default:
+ case CARD_FREE: return "free";
+ case CARD_DETECTED: return "detected";
+ case CARD_LOADING: return "loading";
+ case CARD_RUNNING: return "running";
+ }
+}
+
+static inline int capi_cmd_valid(__u8 cmd)
+{
+ switch (cmd) {
+ case CAPI_ALERT:
+ case CAPI_CONNECT:
+ case CAPI_CONNECT_ACTIVE:
+ case CAPI_CONNECT_B3_ACTIVE:
+ case CAPI_CONNECT_B3:
+ case CAPI_CONNECT_B3_T90_ACTIVE:
+ case CAPI_DATA_B3:
+ case CAPI_DISCONNECT_B3:
+ case CAPI_DISCONNECT:
+ case CAPI_FACILITY:
+ case CAPI_INFO:
+ case CAPI_LISTEN:
+ case CAPI_MANUFACTURER:
+ case CAPI_RESET_B3:
+ case CAPI_SELECT_B_PROTOCOL:
+ return 1;
+ }
+ return 0;
+}
+
+static inline int capi_subcmd_valid(__u8 subcmd)
+{
+ switch (subcmd) {
+ case CAPI_REQ:
+ case CAPI_CONF:
+ case CAPI_IND:
+ case CAPI_RESP:
+ return 1;
+ }
+ return 0;
+}
+
+/* -------- /proc functions ----------------------------------- */
+/*
+ * /proc/capi/applications:
+ * applid l3cnt dblkcnt dblklen #ncci recvqueuelen
+ */
+static int proc_applications_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capi_appl *ap;
+ int i;
+ int len = 0;
+ off_t begin = 0;
+
+ for (i=0; i < CAPI_MAXAPPL; i++) {
+ ap = &applications[i];
+ if (ap->applid == 0) continue;
+ len += sprintf(page+len, "%u %d %d %d %d %d\n",
+ ap->applid,
+ ap->rparam.level3cnt,
+ ap->rparam.datablkcnt,
+ ap->rparam.datablklen,
+ ap->nncci,
+ skb_queue_len(&ap->recv_queue));
+ if (len+begin > off+count)
+ goto endloop;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+endloop:
+ if (i >= CAPI_MAXAPPL)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * /proc/capi/ncci:
+ * applid ncci winsize nblk
+ */
+static int proc_ncci_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capi_appl *ap;
+ struct capi_ncci *np;
+ int i;
+ int len = 0;
+ off_t begin = 0;
+
+ for (i=0; i < CAPI_MAXAPPL; i++) {
+ ap = &applications[i];
+ if (ap->applid == 0) continue;
+ for (np = ap->nccilist; np; np = np->next) {
+ len += sprintf(page+len, "%d 0x%x %d %d\n",
+ np->applid,
+ np->ncci,
+ np->winsize,
+ np->nmsg);
+ if (len+begin > off+count)
+ goto endloop;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+ }
+endloop:
+ if (i >= CAPI_MAXAPPL)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * /proc/capi/driver:
+ * driver ncontroller
+ */
+static int proc_driver_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capi_driver *driver;
+ int len = 0;
+ off_t begin = 0;
+
+ for (driver = drivers; driver; driver = driver->next) {
+ len += sprintf(page+len, "%-32s %d %s\n",
+ driver->name,
+ driver->ncontroller,
+ driver->revision);
+ if (len+begin > off+count)
+ goto endloop;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+endloop:
+ if (!driver)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * /proc/capi/users:
+ * name
+ */
+static int proc_users_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capi_interface_user *cp;
+ int len = 0;
+ off_t begin = 0;
+
+ for (cp = capi_users; cp ; cp = cp->next) {
+ len += sprintf(page+len, "%s\n", cp->name);
+ if (len+begin > off+count)
+ goto endloop;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+endloop:
+ if (cp == 0)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * /proc/capi/controller:
+ * cnr driver cardstate name driverinfo
+ */
+static int proc_controller_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capi_ctr *cp;
+ int i;
+ int len = 0;
+ off_t begin = 0;
+
+ for (i=0; i < CAPI_MAXCONTR; i++) {
+ cp = &cards[i];
+ if (cp->cardstate == CARD_FREE) continue;
+ len += sprintf(page+len, "%d %-10s %-8s %-16s %s\n",
+ cp->cnr, cp->driver->name,
+ cardstate2str(cp->cardstate),
+ cp->name,
+ cp->driver->procinfo ? cp->driver->procinfo(cp) : ""
+ );
+ if (len+begin > off+count)
+ goto endloop;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+endloop:
+ if (i >= CAPI_MAXCONTR)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * /proc/capi/applstats:
+ * applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
+ */
+static int proc_applstats_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capi_appl *ap;
+ int i;
+ int len = 0;
+ off_t begin = 0;
+
+ for (i=0; i < CAPI_MAXAPPL; i++) {
+ ap = &applications[i];
+ if (ap->applid == 0) continue;
+ len += sprintf(page+len, "%u %lu %lu %lu %lu\n",
+ ap->applid,
+ ap->nrecvctlpkt,
+ ap->nrecvdatapkt,
+ ap->nsentctlpkt,
+ ap->nsentdatapkt);
+ if (len+begin > off+count)
+ goto endloop;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+endloop:
+ if (i >= CAPI_MAXAPPL)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * /proc/capi/contrstats:
+ * cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
+ */
+static int proc_contrstats_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capi_ctr *cp;
+ int i;
+ int len = 0;
+ off_t begin = 0;
+
+ for (i=0; i < CAPI_MAXCONTR; i++) {
+ cp = &cards[i];
+ if (cp->cardstate == CARD_FREE) continue;
+ len += sprintf(page+len, "%d %lu %lu %lu %lu\n",
+ cp->cnr,
+ cp->nrecvctlpkt,
+ cp->nrecvdatapkt,
+ cp->nsentctlpkt,
+ cp->nsentdatapkt);
+ if (len+begin > off+count)
+ goto endloop;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+endloop:
+ if (i >= CAPI_MAXCONTR)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+static struct procfsentries {
+ char *name;
+ mode_t mode;
+ int (*read_proc)(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+ struct proc_dir_entry *procent;
+} procfsentries[] = {
+ { "capi", S_IFDIR, 0 },
+ { "capi/applications", 0 , proc_applications_read_proc },
+ { "capi/ncci", 0 , proc_ncci_read_proc },
+ { "capi/driver", 0 , proc_driver_read_proc },
+ { "capi/users", 0 , proc_users_read_proc },
+ { "capi/controller", 0 , proc_controller_read_proc },
+ { "capi/applstats", 0 , proc_applstats_read_proc },
+ { "capi/contrstats", 0 , proc_contrstats_read_proc },
+ { "capi/drivers", S_IFDIR, 0 },
+ { "capi/controllers", S_IFDIR, 0 },
+};
+
+static void proc_capi_init(void)
+{
+ int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+ int i;
+
+ for (i=0; i < nelem; i++) {
+ struct procfsentries *p = procfsentries + i;
+ p->procent = create_proc_entry(p->name, p->mode, 0);
+ if (p->procent) p->procent->read_proc = p->read_proc;
+ }
+}
+
+static void proc_capi_exit(void)
+{
+ int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+ int i;
+
+ for (i=nelem-1; i >= 0; i--) {
+ struct procfsentries *p = procfsentries + i;
+ if (p->procent) {
+ remove_proc_entry(p->name, 0);
+ p->procent = 0;
+ }
+ }
+}
+
+/* -------- NCCI Handling ------------------------------------- */
+
+static inline void mq_init(struct capi_ncci * np)
+{
+ int i;
+ np->msgidqueue = 0;
+ np->msgidlast = 0;
+ np->nmsg = 0;
+ memset(np->msgidpool, 0, sizeof(np->msgidpool));
+ np->msgidfree = &np->msgidpool[0];
+ for (i = 1; i < np->winsize; i++) {
+ np->msgidpool[i].next = np->msgidfree;
+ np->msgidfree = &np->msgidpool[i];
+ }
+}
+
+static inline int mq_enqueue(struct capi_ncci * np, __u16 msgid)
+{
+ struct msgidqueue *mq;
+ if ((mq = np->msgidfree) == 0)
+ return 0;
+ np->msgidfree = mq->next;
+ mq->msgid = msgid;
+ mq->next = 0;
+ if (np->msgidlast)
+ np->msgidlast->next = mq;
+ np->msgidlast = mq;
+ if (!np->msgidqueue)
+ np->msgidqueue = mq;
+ np->nmsg++;
+ return 1;
+}
+
+static inline int mq_dequeue(struct capi_ncci * np, __u16 msgid)
+{
+ struct msgidqueue **pp;
+ for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
+ if ((*pp)->msgid == msgid) {
+ struct msgidqueue *mq = *pp;
+ *pp = mq->next;
+ if (mq == np->msgidlast)
+ np->msgidlast = 0;
+ mq->next = np->msgidfree;
+ np->msgidfree = mq;
+ np->nmsg--;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void controllercb_appl_registered(struct capi_ctr * card, __u16 appl)
+{
+}
+
+static void controllercb_appl_released(struct capi_ctr * card, __u16 appl)
+{
+ struct capi_ncci **pp, **nextpp;
+ for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) {
+ if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
+ struct capi_ncci *np = *pp;
+ *pp = np->next;
+ printk(KERN_INFO "kcapi: appl %d ncci 0x%x down!\n", appl, np->ncci);
+ kfree(np);
+ APPL(appl)->nncci--;
+ nextpp = pp;
+ } else {
+ nextpp = &(*pp)->next;
+ }
+ }
+ APPL(appl)->releasing--;
+ if (APPL(appl)->releasing <= 0) {
+ APPL(appl)->signal = 0;
+ APPL_MARK_FREE(appl);
+ printk(KERN_INFO "kcapi: appl %d down\n", appl);
+ }
+}
+/*
+ * ncci managment
+ */
+
+static void controllercb_new_ncci(struct capi_ctr * card,
+ __u16 appl, __u32 ncci, __u32 winsize)
+{
+ struct capi_ncci *np;
+ if (!VALID_APPLID(appl)) {
+ printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl);
+ return;
+ }
+ if ((np = (struct capi_ncci *) kmalloc(sizeof(struct capi_ncci), GFP_ATOMIC)) == 0) {
+ printk(KERN_ERR "capi_new_ncci: alloc failed ncci 0x%x\n", ncci);
+ return;
+ }
+ if (winsize > CAPI_MAXDATAWINDOW) {
+ printk(KERN_ERR "capi_new_ncci: winsize %d too big, set to %d\n",
+ winsize, CAPI_MAXDATAWINDOW);
+ winsize = CAPI_MAXDATAWINDOW;
+ }
+ np->applid = appl;
+ np->ncci = ncci;
+ np->winsize = winsize;
+ mq_init(np);
+ np->next = APPL(appl)->nccilist;
+ APPL(appl)->nccilist = np;
+ APPL(appl)->nncci++;
+ printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci);
+
+}
+
+static void controllercb_free_ncci(struct capi_ctr * card,
+ __u16 appl, __u32 ncci)
+{
+ struct capi_ncci **pp;
+ if (!VALID_APPLID(appl)) {
+ printk(KERN_ERR "free_ncci: illegal appl %d\n", appl);
+ return;
+ }
+ for (pp = &APPL(appl)->nccilist; *pp; pp = &(*pp)->next) {
+ if ((*pp)->ncci == ncci) {
+ struct capi_ncci *np = *pp;
+ *pp = np->next;
+ kfree(np);
+ APPL(appl)->nncci--;
+ printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci);
+ return;
+ }
+ }
+ printk(KERN_ERR "free_ncci: ncci 0x%x not found\n", ncci);
+}
+
+
+static struct capi_ncci *find_ncci(struct capi_appl * app, __u32 ncci)
+{
+ struct capi_ncci *np;
+ for (np = app->nccilist; np; np = np->next) {
+ if (np->ncci == ncci)
+ return np;
+ }
+ return 0;
+}
+
+/* -------- Receiver ------------------------------------------ */
+
+static void recv_handler(void *dummy)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&recv_queue)) != 0) {
+ __u16 appl = CAPIMSG_APPID(skb->data);
+ struct capi_ncci *np;
+ if (!VALID_APPLID(appl)) {
+ printk(KERN_ERR "kcapi: recv_handler: applid %d ? (%s)\n",
+ appl, capi_message2str(skb->data));
+ kfree_skb(skb);
+ continue;
+ }
+ if (APPL(appl)->signal == 0) {
+ printk(KERN_ERR "kcapi: recv_handler: applid %d has no signal function\n",
+ appl);
+ kfree_skb(skb);
+ continue;
+ }
+ if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
+ && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF
+ && (np = find_ncci(APPL(appl), CAPIMSG_NCCI(skb->data))) != 0
+ && mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) {
+ printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n",
+ CAPIMSG_MSGID(skb->data), np->ncci);
+ }
+ if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
+ && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
+ APPL(appl)->nrecvdatapkt++;
+ } else {
+ APPL(appl)->nrecvctlpkt++;
+ }
+ skb_queue_tail(&APPL(appl)->recv_queue, skb);
+ (APPL(appl)->signal) (APPL(appl)->applid, APPL(appl)->param);
+ }
+}
+
+static void controllercb_handle_capimsg(struct capi_ctr * card,
+ __u16 appl, struct sk_buff *skb)
+{
+ int showctl = 0;
+ __u8 cmd, subcmd;
+
+ if (card->cardstate != CARD_RUNNING) {
+ printk(KERN_INFO "kcapi: controller %d not active, got: %s",
+ card->cnr, capi_message2str(skb->data));
+ goto error;
+ }
+ cmd = CAPIMSG_COMMAND(skb->data);
+ subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+ if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
+ card->nrecvdatapkt++;
+ if (card->traceflag > 2) showctl |= 2;
+ if (card->traceflag) showctl |= 2;
+ } else {
+ card->nrecvctlpkt++;
+ }
+ showctl |= (card->traceflag & 1);
+ if (showctl & 2) {
+ if (showctl & 1) {
+ printk(KERN_DEBUG "kcapi: got [0x%lx] id#%d %s len=%u\n",
+ (unsigned long) card->cnr,
+ CAPIMSG_APPID(skb->data),
+ capi_cmd2str(cmd, subcmd),
+ CAPIMSG_LEN(skb->data));
+ } else {
+ printk(KERN_DEBUG "kcapi: got [0x%lx] %s\n",
+ (unsigned long) card->cnr,
+ capi_message2str(skb->data));
+ }
+
+ }
+ skb_queue_tail(&recv_queue, skb);
+ queue_task(&tq_recv_notify, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ return;
+
+error:
+ kfree_skb(skb);
+}
+
+/* -------- Notifier ------------------------------------------ */
+
+static void notify_up(__u16 contr)
+{
+ struct capi_interface_user *p;
+
+ printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
+ }
+}
+
+static void notify_down(__u16 contr)
+{
+ struct capi_interface_user *p;
+ printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_CONTRDOWN, contr, 0);
+ }
+}
+
+static void notify_handler(void *dummy)
+{
+ __u16 contr;
+
+ for (contr=1; VALID_CARD(contr); contr++)
+ if (test_and_clear_bit(contr, &notify_up_set))
+ notify_up(contr);
+ for (contr=1; VALID_CARD(contr); contr++)
+ if (test_and_clear_bit(contr, &notify_down_set))
+ notify_down(contr);
+}
+
+
+static void controllercb_ready(struct capi_ctr * card)
+{
+ __u16 appl;
+
+ card->cardstate = CARD_RUNNING;
+
+ for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+ if (!VALID_APPLID(appl)) continue;
+ if (APPL(appl)->releasing) continue;
+ card->driver->register_appl(card, appl, &APPL(appl)->rparam);
+ }
+
+ set_bit(CARDNR(card), &notify_up_set);
+ queue_task(&tq_state_notify, &tq_scheduler);
+
+ printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
+ CARDNR(card), card->name);
+}
+
+static void controllercb_reseted(struct capi_ctr * card)
+{
+ __u16 appl;
+
+ if (card->cardstate == CARD_FREE)
+ return;
+ if (card->cardstate == CARD_DETECTED)
+ return;
+
+ card->cardstate = CARD_DETECTED;
+
+ memset(card->manu, 0, sizeof(card->manu));
+ memset(&card->version, 0, sizeof(card->version));
+ memset(&card->profile, 0, sizeof(card->profile));
+ memset(card->serial, 0, sizeof(card->serial));
+
+ for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+ struct capi_ncci **pp, **nextpp;
+ for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) {
+ if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
+ struct capi_ncci *np = *pp;
+ *pp = np->next;
+ printk(KERN_INFO "kcapi: 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 "kcapi: card %d down.\n", CARDNR(card));
+}
+
+static void controllercb_suspend_output(struct capi_ctr *card)
+{
+ if (!card->blocked) {
+ printk(KERN_DEBUG "kcapi: card %d suspend\n", CARDNR(card));
+ card->blocked = 1;
+ }
+}
+
+static void controllercb_resume_output(struct capi_ctr *card)
+{
+ if (card->blocked) {
+ printk(KERN_DEBUG "kcapi: card %d resume\n", CARDNR(card));
+ card->blocked = 0;
+ }
+}
+
+/* ------------------------------------------------------------- */
+
+
+struct capi_ctr *
+drivercb_attach_ctr(struct capi_driver *driver, char *name, void *driverdata)
+{
+ struct capi_ctr *card, **pp;
+ int i;
+
+ for (i=0; i < CAPI_MAXCONTR && cards[i].cardstate != CARD_FREE; i++) ;
+
+ if (i == CAPI_MAXCONTR) {
+ printk(KERN_ERR "kcapi: out of controller slots\n");
+ return 0;
+ }
+ card = &cards[i];
+ memset(card, 0, sizeof(struct capi_ctr));
+ card->driver = driver;
+ card->cnr = CARDNR(card);
+ strncpy(card->name, name, sizeof(card->name));
+ card->cardstate = CARD_DETECTED;
+ card->blocked = 0;
+ card->driverdata = driverdata;
+ card->traceflag = showcapimsgs;
+
+ card->ready = controllercb_ready;
+ card->reseted = controllercb_reseted;
+ card->suspend_output = controllercb_suspend_output;
+ card->resume_output = controllercb_resume_output;
+ card->handle_capimsg = controllercb_handle_capimsg;
+ card->appl_registered = controllercb_appl_registered;
+ card->appl_released = controllercb_appl_released;
+ card->new_ncci = controllercb_new_ncci;
+ card->free_ncci = controllercb_free_ncci;
+
+ for (pp = &driver->controller; *pp; pp = &(*pp)->next) ;
+ card->next = 0;
+ *pp = card;
+ driver->ncontroller++;
+ sprintf(card->procfn, "capi/controllers/%d", card->cnr);
+ card->procent = create_proc_entry(card->procfn, 0, 0);
+ if (card->procent) {
+ card->procent->read_proc =
+ (int (*)(char *,char **,off_t,int,int *,void *))
+ driver->ctr_read_proc;
+ card->procent->data = card;
+ }
+
+ ncards++;
+ printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n",
+ card->cnr, card->name);
+ return card;
+}
+
+static int drivercb_detach_ctr(struct capi_ctr *card)
+{
+ struct capi_driver *driver = card->driver;
+ struct capi_ctr **pp;
+
+ if (card->cardstate == CARD_FREE)
+ return 0;
+ if (card->cardstate != CARD_DETECTED)
+ controllercb_reseted(card);
+ for (pp = &driver->controller; *pp ; pp = &(*pp)->next) {
+ if (*pp == card) {
+ *pp = card->next;
+ driver->ncontroller--;
+ ncards--;
+ break;
+ }
+ }
+ if (card->procent) {
+ remove_proc_entry(card->procfn, 0);
+ card->procent = 0;
+ }
+ card->cardstate = CARD_FREE;
+ printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n",
+ card->cnr, card->name);
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+/* fallback if no driver read_proc function defined by driver */
+
+static int driver_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capi_driver *driver = (struct capi_driver *)data;
+ int len = 0;
+
+ len += sprintf(page+len, "%-16s %s\n", "name", driver->name);
+ len += sprintf(page+len, "%-16s %s\n", "revision", driver->revision);
+
+ if (len < off)
+ return 0;
+ *eof = 1;
+ *start = page - off;
+ return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface di = {
+ drivercb_attach_ctr,
+ drivercb_detach_ctr,
+};
+
+struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver)
+{
+ struct capi_driver **pp;
+
+ for (pp = &drivers; *pp; pp = &(*pp)->next) ;
+ driver->next = 0;
+ *pp = driver;
+ printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name);
+#ifdef CONFIG_AVMB1_COMPAT
+ if (strcmp(driver->name, "b1isa") == 0 && driver->add_card)
+ b1isa_driver = driver;
+ if (strcmp(driver->name, "t1isa") == 0 && driver->add_card)
+ t1isa_driver = driver;
+#endif
+ sprintf(driver->procfn, "capi/drivers/%s", driver->name);
+ driver->procent = create_proc_entry(driver->procfn, 0, 0);
+ if (driver->procent) {
+ if (driver->driver_read_proc) {
+ driver->procent->read_proc =
+ (int (*)(char *,char **,off_t,int,int *,void *))
+ driver->driver_read_proc;
+ } else {
+ driver->procent->read_proc = driver_read_proc;
+ }
+ driver->procent->data = driver;
+ }
+ return &di;
+}
+
+void detach_capi_driver(struct capi_driver *driver)
+{
+ struct capi_driver **pp;
+ for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ;
+ if (*pp) {
+ *pp = (*pp)->next;
+#ifdef CONFIG_AVMB1_COMPAT
+ if (driver == b1isa_driver) b1isa_driver = 0;
+ if (driver == t1isa_driver) t1isa_driver = 0;
+#endif
+ printk(KERN_NOTICE "kcapi: driver %s detached\n", driver->name);
+ } else {
+ printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name);
+ }
+ if (driver->procent) {
+ remove_proc_entry(driver->procfn, 0);
+ driver->procent = 0;
+ }
+}
+
+/* ------------------------------------------------------------- */
+/* -------- CAPI2.0 Interface ---------------------------------- */
+/* ------------------------------------------------------------- */
+
+static int capi_installed(void)
+{
+ int i;
+ for (i = 0; i < CAPI_MAXCONTR; i++) {
+ if (cards[i].cardstate == CARD_RUNNING)
+ return 1;
+ }
+ return 0;
+}
+
+static __u16 capi_register(capi_register_params * rparam, __u16 * applidp)
+{
+ int appl;
+ int i;
+
+ if (rparam->datablklen < 128)
+ return CAPI_LOGBLKSIZETOSMALL;
+
+ for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+ if (APPL_IS_FREE(appl))
+ break;
+ }
+ if (appl > CAPI_MAXAPPL)
+ return CAPI_TOOMANYAPPLS;
+
+ APPL_MARK_USED(appl);
+ skb_queue_head_init(&APPL(appl)->recv_queue);
+ APPL(appl)->nncci = 0;
+
+ memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params));
+
+ for (i = 0; i < CAPI_MAXCONTR; i++) {
+ if (cards[i].cardstate != CARD_RUNNING)
+ continue;
+ cards[i].driver->register_appl(&cards[i], appl,
+ &APPL(appl)->rparam);
+ }
+ *applidp = appl;
+ printk(KERN_INFO "kcapi: appl %d up\n", appl);
+
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_release(__u16 applid)
+{
+ struct sk_buff *skb;
+ int i;
+
+ if (!VALID_APPLID(applid) || APPL(applid)->releasing)
+ return CAPI_ILLAPPNR;
+ while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
+ kfree_skb(skb);
+ for (i = 0; i < CAPI_MAXCONTR; i++) {
+ if (cards[i].cardstate != CARD_RUNNING)
+ continue;
+ APPL(applid)->releasing++;
+ cards[i].driver->release_appl(&cards[i], applid);
+ }
+ if (APPL(applid)->releasing <= 0) {
+ APPL(applid)->signal = 0;
+ APPL_MARK_FREE(applid);
+ printk(KERN_INFO "kcapi: appl %d down\n", applid);
+ }
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_put_message(__u16 applid, struct sk_buff *skb)
+{
+ struct capi_ncci *np;
+ int contr;
+ int showctl = 0;
+ __u8 cmd, subcmd;
+
+ if (ncards == 0)
+ return CAPI_REGNOTINSTALLED;
+ if (!VALID_APPLID(applid))
+ return CAPI_ILLAPPNR;
+ if (skb->len < 12
+ || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
+ || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
+ return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
+ contr = CAPIMSG_CONTROLLER(skb->data);
+ if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) {
+ contr = 1;
+ if (CARD(contr)->cardstate != CARD_RUNNING)
+ return CAPI_REGNOTINSTALLED;
+ }
+ if (CARD(contr)->blocked)
+ return CAPI_SENDQUEUEFULL;
+
+ cmd = CAPIMSG_COMMAND(skb->data);
+ subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+ if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
+ if ((np = find_ncci(APPL(applid), CAPIMSG_NCCI(skb->data))) != 0
+ && mq_enqueue(np, CAPIMSG_MSGID(skb->data)) == 0)
+ return CAPI_SENDQUEUEFULL;
+ CARD(contr)->nsentdatapkt++;
+ APPL(applid)->nsentdatapkt++;
+ if (CARD(contr)->traceflag > 2) showctl |= 2;
+ } else {
+ CARD(contr)->nsentctlpkt++;
+ APPL(applid)->nsentctlpkt++;
+ if (CARD(contr)->traceflag) showctl |= 2;
+ }
+ showctl |= (CARD(contr)->traceflag & 1);
+ if (showctl & 2) {
+ if (showctl & 1) {
+ printk(KERN_DEBUG "kcapi: put [0x%lx] id#%d %s len=%u\n",
+ (unsigned long) contr,
+ CAPIMSG_APPID(skb->data),
+ capi_cmd2str(cmd, subcmd),
+ CAPIMSG_LEN(skb->data));
+ } else {
+ printk(KERN_DEBUG "kcapi: put [0x%lx] %s\n",
+ (unsigned long) contr,
+ capi_message2str(skb->data));
+ }
+
+ }
+ CARD(contr)->driver->send_message(CARD(contr), skb);
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp)
+{
+ struct sk_buff *skb;
+
+ if (!VALID_APPLID(applid))
+ return CAPI_ILLAPPNR;
+ if ((skb = skb_dequeue(&APPL(applid)->recv_queue)) == 0)
+ return CAPI_RECEIVEQUEUEEMPTY;
+ *msgp = skb;
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_set_signal(__u16 applid,
+ void (*signal) (__u16 applid, __u32 param),
+ __u32 param)
+{
+ if (!VALID_APPLID(applid))
+ return CAPI_ILLAPPNR;
+ APPL(applid)->signal = signal;
+ APPL(applid)->param = param;
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_get_manufacturer(__u16 contr, __u8 buf[CAPI_MANUFACTURER_LEN])
+{
+ if (contr == 0) {
+ strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
+ return CAPI_NOERROR;
+ }
+ if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING)
+ return 0x2002;
+
+ strncpy(buf, CARD(contr)->manu, CAPI_MANUFACTURER_LEN);
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_get_version(__u16 contr, struct capi_version *verp)
+{
+ if (contr == 0) {
+ *verp = driver_version;
+ return CAPI_NOERROR;
+ }
+ if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING)
+ return 0x2002;
+
+ memcpy((void *) verp, &CARD(contr)->version, sizeof(capi_version));
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_get_serial(__u16 contr, __u8 serial[CAPI_SERIAL_LEN])
+{
+ if (contr == 0) {
+ strncpy(serial, driver_serial, CAPI_SERIAL_LEN);
+ return CAPI_NOERROR;
+ }
+ if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING)
+ return 0x2002;
+
+ strncpy((void *) serial, CARD(contr)->serial, CAPI_SERIAL_LEN);
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_get_profile(__u16 contr, struct capi_profile *profp)
+{
+ if (contr == 0) {
+ profp->ncontroller = ncards;
+ return CAPI_NOERROR;
+ }
+ if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING)
+ return 0x2002;
+
+ memcpy((void *) profp, &CARD(contr)->profile,
+ sizeof(struct capi_profile));
+ return CAPI_NOERROR;
+}
+
+#ifdef CONFIG_AVMB1_COMPAT
+static int old_capi_manufacturer(unsigned int cmd, void *data)
+{
+ avmb1_loadandconfigdef ldef;
+ avmb1_extcarddef cdef;
+ avmb1_resetdef rdef;
+ avmb1_getdef gdef;
+ struct capi_driver *driver;
+ struct capi_ctr *card;
+ capicardparams cparams;
+ capiloaddata ldata;
+ int retval;
+
+ switch (cmd) {
+ case AVMB1_ADDCARD:
+ case AVMB1_ADDCARD_WITH_TYPE:
+ if (cmd == AVMB1_ADDCARD) {
+ if ((retval = copy_from_user((void *) &cdef, data,
+ sizeof(avmb1_carddef))))
+ return retval;
+ cdef.cardtype = AVM_CARDTYPE_B1;
+ } else {
+ if ((retval = copy_from_user((void *) &cdef, data,
+ sizeof(avmb1_extcarddef))))
+ return retval;
+ }
+ cparams.port = cdef.port;
+ cparams.irq = cdef.irq;
+ cparams.cardnr = cdef.cardnr;
+
+ switch (cdef.cardtype) {
+ case AVM_CARDTYPE_B1: driver = b1isa_driver; break;
+ case AVM_CARDTYPE_T1: driver = t1isa_driver; break;
+ default: driver = 0;
+ }
+ if (!driver || !driver->add_card) {
+ return -EIO;
+ }
+
+ return driver->add_card(driver, &cparams);
+
+ case AVMB1_LOAD:
+ case AVMB1_LOAD_AND_CONFIG:
+
+ if (cmd == AVMB1_LOAD) {
+ if ((retval = copy_from_user((void *) &ldef, data,
+ sizeof(avmb1_loaddef))))
+ return retval;
+ ldef.t4config.len = 0;
+ ldef.t4config.data = 0;
+ } else {
+ if ((retval = copy_from_user((void *) &ldef, data,
+ sizeof(avmb1_loadandconfigdef))))
+ return retval;
+ }
+ if (!VALID_CARD(ldef.contr))
+ return -ESRCH;
+
+ card = CARD(ldef.contr);
+ if (card->cardstate == CARD_FREE)
+ return -ESRCH;
+
+ if (ldef.t4file.len <= 0) {
+ printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
+ return -EINVAL;
+ }
+ if (ldef.t4file.data == 0) {
+ printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
+ return -EINVAL;
+ }
+
+ ldata.firmware.user = 1;
+ ldata.firmware.data = ldef.t4file.data;
+ ldata.firmware.len = ldef.t4file.len;
+ ldata.configuration.user = 1;
+ ldata.configuration.data = ldef.t4config.data;
+ ldata.configuration.len = ldef.t4config.len;
+
+ if (card->cardstate != CARD_DETECTED) {
+ printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
+ return -EBUSY;
+ }
+ card->cardstate = CARD_LOADING;
+
+ retval = card->driver->load_firmware(card, &ldata);
+
+ if (retval) {
+ card->cardstate = CARD_DETECTED;
+ return retval;
+ }
+
+ while (card->cardstate != CARD_RUNNING) {
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/10); /* 0.1 sec */
+
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ return 0;
+
+ case AVMB1_RESETCARD:
+ if ((retval = copy_from_user((void *) &rdef, data,
+ sizeof(avmb1_resetdef))))
+ return retval;
+ if (!VALID_CARD(rdef.contr))
+ return -ESRCH;
+ card = CARD(rdef.contr);
+
+ if (card->cardstate == CARD_FREE)
+ return -ESRCH;
+ if (card->cardstate == CARD_DETECTED)
+ return 0;
+
+ card->driver->reset_ctr(card);
+
+ while (card->cardstate > CARD_DETECTED) {
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/10); /* 0.1 sec */
+
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ return 0;
+
+ case AVMB1_GET_CARDINFO:
+ if ((retval = copy_from_user((void *) &gdef, data,
+ sizeof(avmb1_getdef))))
+ return retval;
+
+ if (!VALID_CARD(gdef.contr))
+ return -ESRCH;
+
+ card = CARD(gdef.contr);
+
+ if (card->cardstate == CARD_FREE)
+ return -ESRCH;
+
+ gdef.cardstate = card->cardstate;
+ if (card->driver == b1isa_driver)
+ gdef.cardtype = AVM_CARDTYPE_B1;
+ else if (card->driver == t1isa_driver)
+ gdef.cardtype = AVM_CARDTYPE_T1;
+ else gdef.cardtype = AVM_CARDTYPE_B1;
+
+ if ((retval = copy_to_user(data, (void *) &gdef,
+ sizeof(avmb1_getdef))))
+ return retval;
+
+ return 0;
+
+ case AVMB1_REMOVECARD:
+ if ((retval = copy_from_user((void *) &rdef, data,
+ sizeof(avmb1_resetdef))))
+ return retval;
+
+ if (!VALID_CARD(rdef.contr))
+ return -ESRCH;
+ card = CARD(rdef.contr);
+
+ if (card->cardstate == CARD_FREE)
+ return -ESRCH;
+
+ if (card->cardstate != CARD_DETECTED)
+ return -EBUSY;
+
+ card->driver->remove_ctr(card);
+
+ while (card->cardstate != CARD_FREE) {
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ/10); /* 0.1 sec */
+
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+#endif
+
+static int capi_manufacturer(unsigned int cmd, void *data)
+{
+ struct capi_ctr *card;
+ kcapi_flagdef fdef;
+ int retval;
+
+ switch (cmd) {
+#ifdef CONFIG_AVMB1_COMPAT
+ case AVMB1_ADDCARD:
+ case AVMB1_ADDCARD_WITH_TYPE:
+ case AVMB1_LOAD:
+ case AVMB1_LOAD_AND_CONFIG:
+ case AVMB1_RESETCARD:
+ case AVMB1_GET_CARDINFO:
+ case AVMB1_REMOVECARD:
+ return old_capi_manufacturer(cmd, data);
+#endif
+ case KCAPI_CMD_TRACE:
+ if ((retval = copy_from_user((void *) &fdef, data,
+ sizeof(kcapi_flagdef))))
+ return retval;
+
+ if (!VALID_CARD(fdef.contr))
+ return -ESRCH;
+ card = CARD(fdef.contr);
+ if (card->cardstate == CARD_FREE)
+ return -ESRCH;
+ card->traceflag = fdef.flag;
+ printk(KERN_INFO "kcapi: contr %d set trace=%d\n",
+ card->cnr, card->traceflag);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+struct capi_interface avmb1_interface =
+{
+ capi_installed,
+ capi_register,
+ capi_release,
+ capi_put_message,
+ capi_get_message,
+ capi_set_signal,
+ capi_get_manufacturer,
+ capi_get_version,
+ capi_get_serial,
+ capi_get_profile,
+ capi_manufacturer
+};
+
+/* ------------------------------------------------------------- */
+/* -------- Exported Functions --------------------------------- */
+/* ------------------------------------------------------------- */
+
+struct capi_interface *attach_capi_interface(struct capi_interface_user *userp)
+{
+ struct capi_interface_user *p;
+
+ for (p = capi_users; p; p = p->next) {
+ if (p == userp) {
+ printk(KERN_ERR "kcapi: double attach from %s\n",
+ userp->name);
+ return 0;
+ }
+ }
+ userp->next = capi_users;
+ capi_users = userp;
+ MOD_INC_USE_COUNT;
+ printk(KERN_NOTICE "kcapi: %s attached\n", userp->name);
+
+ return &avmb1_interface;
+}
+
+int detach_capi_interface(struct capi_interface_user *userp)
+{
+ struct capi_interface_user **pp;
+
+ for (pp = &capi_users; *pp; pp = &(*pp)->next) {
+ if (*pp == userp) {
+ *pp = userp->next;
+ userp->next = 0;
+ MOD_DEC_USE_COUNT;
+ printk(KERN_NOTICE "kcapi: %s detached\n", userp->name);
+ return 0;
+ }
+ }
+ printk(KERN_ERR "kcapi: double detach from %s\n", userp->name);
+ return -1;
+}
+
+/* ------------------------------------------------------------- */
+/* -------- Init & Cleanup ------------------------------------- */
+/* ------------------------------------------------------------- */
+
+EXPORT_SYMBOL(attach_capi_interface);
+EXPORT_SYMBOL(detach_capi_interface);
+EXPORT_SYMBOL(attach_capi_driver);
+EXPORT_SYMBOL(detach_capi_driver);
+
+#ifndef MODULE
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
+extern int b1isa_init(void);
+#endif
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
+extern int b1pci_init(void);
+#endif
+#ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
+extern int t1isa_init(void);
+#endif
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+extern int b1pcmcia_init(void);
+#endif
+#endif
+
+/*
+ * init / exit functions
+ */
+
+#ifdef MODULE
+#define kcapi_init init_module
+#endif
+
+int kcapi_init(void)
+{
+ char *p;
+ char rev[10];
+
+ skb_queue_head_init(&recv_queue);
+ /* init_bh(CAPI_BH, do_capi_bh); */
+
+ tq_state_notify.routine = notify_handler;
+ tq_state_notify.data = 0;
+
+ tq_recv_notify.routine = recv_handler;
+ tq_recv_notify.data = 0;
+
+ proc_capi_init();
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, "1.0");
+
+#ifdef MODULE
+ printk(KERN_NOTICE "CAPI-driver Rev%s: loaded\n", rev);
+#else
+ printk(KERN_NOTICE "CAPI-driver Rev%s: started\n", rev);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
+ (void)b1isa_init();
+#endif
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
+ (void)b1pci_init();
+#endif
+#ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
+ (void)t1isa_init();
+#endif
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+ (void)b1pcmcia_init();
+#endif
+#endif
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ char rev[10];
+ char *p;
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else {
+ strcpy(rev, "1.0");
+ }
+
+ schedule(); /* execute queued tasks .... */
+ proc_capi_exit();
+ printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev);
+}
+#endif
diff --git a/drivers/isdn/avmb1/t1isa.c b/drivers/isdn/avmb1/t1isa.c
new file mode 100644
index 000000000..3546e1061
--- /dev/null
+++ b/drivers/isdn/avmb1/t1isa.c
@@ -0,0 +1,550 @@
+/*
+ * $Id: t1isa.c,v 1.5 1999/08/22 20:26:28 calle Exp $
+ *
+ * Module for AVM T1 HEMA-card.
+ *
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: t1isa.c,v $
+ * Revision 1.5 1999/08/22 20:26:28 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.4 1999/07/09 15:05:50 keil
+ * compat.h is now isdn_compat.h
+ *
+ * Revision 1.3 1999/07/06 07:42:04 calle
+ * - changes in /proc interface
+ * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
+ *
+ * Revision 1.2 1999/07/05 15:09:54 calle
+ * - renamed "appl_release" to "appl_released".
+ * - version und profile data now cleared on controller reset
+ * - extended /proc interface, to allow driver and controller specific
+ * informations to include by driver hackers.
+ *
+ * Revision 1.1 1999/07/01 15:26:44 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/capi.h>
+#include <asm/io.h>
+#include <linux/isdn_compat.h>
+#include "capicmd.h"
+#include "capiutil.h"
+#include "capilli.h"
+#include "avmcard.h"
+
+static char *revision = "$Revision: 1.5 $";
+
+/* ------------------------------------------------------------- */
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
+static int hema_irq_table[16] =
+{0,
+ 0,
+ 0,
+ 0x80, /* irq 3 */
+ 0,
+ 0x90, /* irq 5 */
+ 0,
+ 0xA0, /* irq 7 */
+ 0,
+ 0xB0, /* irq 9 */
+ 0xC0, /* irq 10 */
+ 0xD0, /* irq 11 */
+ 0xE0, /* irq 12 */
+ 0,
+ 0,
+ 0xF0, /* irq 15 */
+};
+
+static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr)
+{
+ unsigned char cregs[8];
+ unsigned char reverse_cardnr;
+ unsigned long flags;
+ unsigned char dummy;
+ int i;
+
+ reverse_cardnr = ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1)
+ | ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3);
+ cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf);
+ cregs[1] = 0x00; /* fast & slow link connected to CON1 */
+ cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */
+ cregs[3] = 0;
+ cregs[4] = 0x11; /* zero wait state */
+ cregs[5] = hema_irq_table[irq & 0xf];
+ cregs[6] = 0;
+ cregs[7] = 0;
+
+ save_flags(flags);
+ cli();
+ /* board reset */
+ t1outp(base, T1_RESETBOARD, 0xf);
+ udelay(100 * 1000);
+ dummy = t1inp(base, T1_FASTLINK+T1_OUTSTAT); /* first read */
+
+ /* write config */
+ dummy = (base >> 4) & 0xff;
+ for (i=1;i<=0xf;i++) t1outp(base, i, dummy);
+ t1outp(base, HEMA_PAL_ID & 0xf, dummy);
+ t1outp(base, HEMA_PAL_ID >> 4, cregs[0]);
+ for(i=1;i<7;i++) t1outp(base, 0, cregs[i]);
+ t1outp(base, ((base >> 4)) & 0x3, cregs[7]);
+ restore_flags(flags);
+
+ udelay(100 * 1000);
+ t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
+ t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
+ udelay(10 * 1000);
+ t1outp(base, T1_FASTLINK+T1_RESETLINK, 1);
+ t1outp(base, T1_SLOWLINK+T1_RESETLINK, 1);
+ udelay(100 * 1000);
+ t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
+ t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
+ udelay(10 * 1000);
+ t1outp(base, T1_FASTLINK+T1_ANALYSE, 0);
+ udelay(5 * 1000);
+ t1outp(base, T1_SLOWLINK+T1_ANALYSE, 0);
+
+ if (t1inp(base, T1_FASTLINK+T1_OUTSTAT) != 0x1) /* tx empty */
+ return 1;
+ if (t1inp(base, T1_FASTLINK+T1_INSTAT) != 0x0) /* rx empty */
+ return 2;
+ if (t1inp(base, T1_FASTLINK+T1_IRQENABLE) != 0x0)
+ return 3;
+ if ((t1inp(base, T1_FASTLINK+T1_FIFOSTAT) & 0xf0) != 0x70)
+ return 4;
+ if ((t1inp(base, T1_FASTLINK+T1_IRQMASTER) & 0x0e) != 0)
+ return 5;
+ if ((t1inp(base, T1_FASTLINK+T1_IDENT) & 0x7d) != 1)
+ return 6;
+ if (t1inp(base, T1_SLOWLINK+T1_OUTSTAT) != 0x1) /* tx empty */
+ return 7;
+ if ((t1inp(base, T1_SLOWLINK+T1_IRQMASTER) & 0x0e) != 0)
+ return 8;
+ if ((t1inp(base, T1_SLOWLINK+T1_IDENT) & 0x7d) != 0)
+ return 9;
+ return 0;
+}
+
+static void t1_handle_interrupt(avmcard * card)
+{
+ struct capi_ctr *ctrl = card->ctrl;
+ unsigned char b1cmd;
+ struct sk_buff *skb;
+
+ unsigned ApplId;
+ unsigned MsgLen;
+ unsigned DataB3Len;
+ unsigned NCCI;
+ unsigned WindowSize;
+
+ while (b1_rx_full(card->port)) {
+
+ b1cmd = b1_get_byte(card->port);
+
+ switch (b1cmd) {
+
+ case RECEIVE_DATA_B3_IND:
+
+ ApplId = (unsigned) b1_get_word(card->port);
+ MsgLen = t1_get_slice(card->port, card->msgbuf);
+ DataB3Len = t1_get_slice(card->port, card->databuf);
+
+ if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
+ printk(KERN_ERR "t1isa: incoming packet dropped\n");
+ } else {
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+ CAPIMSG_SETDATA(skb->data, skb->data + MsgLen);
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_MESSAGE:
+
+ ApplId = (unsigned) b1_get_word(card->port);
+ MsgLen = t1_get_slice(card->port, card->msgbuf);
+ if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
+ printk(KERN_ERR "t1isa: incoming packet dropped\n");
+ } else {
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_NEW_NCCI:
+
+ ApplId = b1_get_word(card->port);
+ NCCI = b1_get_word(card->port);
+ WindowSize = b1_get_word(card->port);
+
+ ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
+
+ break;
+
+ case RECEIVE_FREE_NCCI:
+
+ ApplId = b1_get_word(card->port);
+ NCCI = b1_get_word(card->port);
+
+ if (NCCI != 0xffffffff)
+ ctrl->free_ncci(ctrl, ApplId, NCCI);
+ else ctrl->appl_released(ctrl, ApplId);
+ break;
+
+ case RECEIVE_START:
+ b1_put_byte(card->port, SEND_POLLACK);
+ ctrl->resume_output(ctrl);
+ break;
+
+ case RECEIVE_STOP:
+ ctrl->suspend_output(ctrl);
+ break;
+
+ case RECEIVE_INIT:
+
+ card->versionlen = t1_get_slice(card->port, card->versionbuf);
+ b1_parse_version(card);
+ printk(KERN_INFO "%s: %s-card (%s) now active\n",
+ card->name,
+ card->version[VER_CARDTYPE],
+ card->version[VER_DRIVER]);
+ ctrl->ready(ctrl);
+ break;
+
+ case RECEIVE_TASK_READY:
+ ApplId = (unsigned) b1_get_word(card->port);
+ MsgLen = t1_get_slice(card->port, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
+ card->name, ApplId, card->msgbuf);
+ break;
+
+ case RECEIVE_DEBUGMSG:
+ MsgLen = t1_get_slice(card->port, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
+ break;
+
+ case 0xff:
+ printk(KERN_ERR "%s: card reseted ?\n", card->name);
+ return;
+ default:
+ printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
+ card->name, b1cmd);
+ return;
+ }
+ }
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+ avmcard *card;
+
+ card = (avmcard *) devptr;
+
+ if (!card) {
+ printk(KERN_WARNING "t1_interrupt: wrong device\n");
+ return;
+ }
+ if (card->interrupt) {
+ printk(KERN_ERR "t1_interrupt: reentering interrupt hander (%s)\n", card->name);
+ return;
+ }
+
+ card->interrupt = 1;
+
+ t1_handle_interrupt(card);
+
+ card->interrupt = 0;
+}
+/* ------------------------------------------------------------- */
+
+static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+ unsigned long flags;
+ int retval;
+
+ t1_disable_irq(port);
+ b1_reset(port);
+
+ if ((retval = b1_load_t4file(port, &data->firmware))) {
+ b1_reset(port);
+ printk(KERN_ERR "%s: failed to load t4file!!\n",
+ card->name);
+ return retval;
+ }
+
+ if (data->configuration.len > 0 && data->configuration.data) {
+ if ((retval = b1_load_config(port, &data->configuration))) {
+ b1_reset(port);
+ printk(KERN_ERR "%s: failed to load config!!\n",
+ card->name);
+ return retval;
+ }
+ }
+
+ if (!b1_loaded(port)) {
+ printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
+ return -EIO;
+ }
+
+ save_flags(flags);
+ cli();
+ b1_setinterrupt(port, card->irq, card->cardtype);
+ b1_put_byte(port, SEND_INIT);
+ b1_put_word(port, AVM_NAPPS);
+ b1_put_word(port, AVM_NCCI_PER_CHANNEL*30);
+ b1_put_word(port, ctrl->cnr - 1);
+ restore_flags(flags);
+
+ return 0;
+}
+
+void t1isa_reset_ctr(struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+
+ t1_disable_irq(port);
+ b1_reset(port);
+ b1_reset(port);
+
+ memset(card->version, 0, sizeof(card->version));
+ ctrl->reseted(ctrl);
+}
+
+static void t1isa_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+
+ t1_disable_irq(port);
+ b1_reset(port);
+ b1_reset(port);
+ t1_reset(port);
+
+ di->detach_ctr(ctrl);
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------- */
+
+static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
+{
+ struct capi_ctr *ctrl;
+ avmcard *card;
+ int retval;
+
+ card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+ if (!card) {
+ printk(KERN_WARNING "t1isa: no memory.\n");
+ return -ENOMEM;
+ }
+ memset(card, 0, sizeof(avmcard));
+ sprintf(card->name, "t1isa-%x", p->port);
+ card->port = p->port;
+ card->irq = p->irq;
+ card->cardtype = avm_t1isa;
+ card->cardnr = p->cardnr;
+
+ if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) {
+ printk(KERN_WARNING "t1isa: illegal port 0x%x.\n", card->port);
+ kfree(card);
+ return -EINVAL;
+ }
+
+ if (check_region(card->port, AVMB1_PORTLEN)) {
+ printk(KERN_WARNING
+ "t1isa: ports 0x%03x-0x%03x in use.\n",
+ card->port, card->port + AVMB1_PORTLEN);
+ kfree(card);
+ return -EBUSY;
+ }
+ if (hema_irq_table[card->irq & 0xf] == 0) {
+ printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq);
+ kfree(card);
+ return -EINVAL;
+ }
+ for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) {
+ if (((avmcard *)(ctrl->driverdata))->cardnr == card->cardnr) {
+ printk(KERN_WARNING "t1isa: card with number %d already installed.\n", card->cardnr);
+ kfree(card);
+ return -EBUSY;
+ }
+ }
+ if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
+ printk(KERN_NOTICE "t1isa: NO card at 0x%x (%d)\n",
+ card->port, retval);
+ kfree(card);
+ return -EIO;
+ }
+ t1_disable_irq(card->port);
+ b1_reset(card->port);
+
+ request_region(p->port, AVMB1_PORTLEN, card->name);
+
+ retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card);
+ if (retval) {
+ printk(KERN_ERR "t1isa: unable to get IRQ %d.\n", card->irq);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ card->ctrl = di->attach_ctr(driver, card->name, card);
+ if (!card->ctrl) {
+ printk(KERN_ERR "t1isa: attach controller failed.\n");
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ unsigned int port = card->port;
+ unsigned long flags;
+ __u16 len = CAPIMSG_LEN(skb->data);
+ __u8 cmd = CAPIMSG_COMMAND(skb->data);
+ __u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+ save_flags(flags);
+ cli();
+ if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+ __u16 dlen = CAPIMSG_DATALEN(skb->data);
+ b1_put_byte(port, SEND_DATA_B3_REQ);
+ t1_put_slice(port, skb->data, len);
+ t1_put_slice(port, skb->data + len, dlen);
+ } else {
+ b1_put_byte(port, SEND_MESSAGE);
+ t1_put_slice(port, skb->data, len);
+ }
+ restore_flags(flags);
+ dev_kfree_skb(skb);
+}
+/* ------------------------------------------------------------- */
+
+static char *t1isa_procinfo(struct capi_ctr *ctrl)
+{
+ avmcard *card = (avmcard *)(ctrl->driverdata);
+ if (!card)
+ return "";
+ sprintf(card->infobuf, "%s %s 0x%x %d %d",
+ card->cardname[0] ? card->cardname : "-",
+ card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
+ card->port, card->irq, card->cardnr
+ );
+ return card->infobuf;
+}
+
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver t1isa_driver = {
+ "t1isa",
+ "0.0",
+ t1isa_load_firmware,
+ t1isa_reset_ctr,
+ t1isa_remove_ctr,
+ b1_register_appl,
+ b1_release_appl,
+ t1isa_send_message,
+
+ t1isa_procinfo,
+ b1ctl_read_proc,
+ 0, /* use standard driver_read_proc */
+
+ t1isa_add_card,
+};
+
+#ifdef MODULE
+#define t1isa_init init_module
+void cleanup_module(void);
+#endif
+
+int t1isa_init(void)
+{
+ struct capi_driver *driver = &t1isa_driver;
+ char *p;
+
+ if ((p = strchr(revision, ':'))) {
+ strncpy(driver->revision, p + 1, sizeof(driver->revision));
+ p = strchr(driver->revision, '$');
+ *p = 0;
+ }
+
+ printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
+
+ di = attach_capi_driver(driver);
+
+ if (!di) {
+ printk(KERN_ERR "%s: failed to attach capi_driver\n",
+ driver->name);
+ return -EIO;
+ }
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ detach_capi_driver(&t1isa_driver);
+}
+#endif
diff --git a/drivers/isdn/divert/Makefile b/drivers/isdn/divert/Makefile
new file mode 100644
index 000000000..109c900d8
--- /dev/null
+++ b/drivers/isdn/divert/Makefile
@@ -0,0 +1,21 @@
+L_OBJS :=
+LX_OBJS :=
+M_OBJS :=
+MX_OBJS :=
+O_OBJS :=
+OX_OBJS :=
+L_TARGET :=
+O_TARGET :=
+
+O_OBJS += isdn_divert.o divert_procfs.o
+O_TARGET := dss1_divert.o
+M_OBJS += dss1_divert.o
+OX_OBJS += divert_init.o
+
+include $(TOPDIR)/Rules.make
+
+
+
+
+
+
diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c
new file mode 100644
index 000000000..ce44cfa19
--- /dev/null
+++ b/drivers/isdn/divert/divert_init.c
@@ -0,0 +1,110 @@
+/*
+ * $Id: divert_init.c,v 1.4 1999/08/22 20:26:32 calle Exp $
+ *
+ * Module init for DSS1 diversion services for i4l.
+ *
+ * Copyright 1999 by Werner Cornelius (werner@isdn4linux.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: divert_init.c,v $
+ * Revision 1.4 1999/08/22 20:26:32 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.3 1999/07/05 20:21:39 werner
+ * changes to use diversion sources for all kernel versions.
+ * removed static device, only proc filesystem used
+ *
+ * Revision 1.2 1999/07/04 21:37:30 werner
+ * Ported from kernel version 2.0
+ *
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include "isdn_divert.h"
+
+/********************/
+/* needed externals */
+/********************/
+extern int printk(const char *fmt,...);
+
+/****************************************/
+/* structure containing interface to hl */
+/****************************************/
+isdn_divert_if divert_if =
+ { DIVERT_IF_MAGIC, /* magic value */
+ DIVERT_CMD_REG, /* register cmd */
+ ll_callback, /* callback routine from ll */
+ NULL, /* command still not specified */
+ NULL, /* drv_to_name */
+ NULL, /* name_to_drv */
+ };
+
+/*************************/
+/* Module interface code */
+/* no cmd line parms */
+/*************************/
+int init_module(void)
+{ int i;
+
+ if (divert_dev_init())
+ { printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
+ return(-EIO);
+ }
+ if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
+ { divert_dev_deinit();
+ printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n",i);
+ return(-EIO);
+ }
+#if (LINUX_VERSION_CODE < 0x020111)
+ register_symtab(0);
+#endif
+ printk(KERN_INFO "dss1_divert module successfully installed\n");
+ return(0);
+} /* init_module */
+
+/**********************/
+/* Module deinit code */
+/**********************/
+void cleanup_module(void)
+{ int flags;
+ int i;
+
+ save_flags(flags);
+ cli();
+ divert_if.cmd = DIVERT_CMD_REL; /* release */
+ if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
+ { printk(KERN_WARNING "dss1_divert: error %d releasing module\n",i);
+ restore_flags(flags);
+ return;
+ }
+ if (divert_dev_deinit())
+ { printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
+ restore_flags(flags);
+ return;
+ }
+ restore_flags(flags);
+ deleterule(-1); /* delete all rules and free mem */
+ deleteprocs();
+ printk(KERN_INFO "dss1_divert module successfully removed \n");
+} /* cleanup_module */
+
+
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
new file mode 100644
index 000000000..035aa3636
--- /dev/null
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -0,0 +1,456 @@
+/*
+ * $Id: divert_procfs.c,v 1.4 1999/08/06 07:42:48 calle Exp $
+ *
+ * Filesystem handling for the diversion supplementary services.
+ *
+ * Copyright 1998 by Werner Cornelius (werner@isdn4linux.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: divert_procfs.c,v $
+ * Revision 1.4 1999/08/06 07:42:48 calle
+ * Added COMPAT_HAS_NEW_WAITQ for rd_queue for newer kernels.
+ *
+ * Revision 1.3 1999/07/05 20:21:41 werner
+ * changes to use diversion sources for all kernel versions.
+ * removed static device, only proc filesystem used
+ *
+ * Revision 1.2 1999/07/04 21:37:31 werner
+ * Ported from kernel version 2.0
+ *
+ *
+ *
+ */
+
+#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
+#ifdef CONFIG_PROC_FS
+ #include <linux/proc_fs.h>
+#else
+ #include <linux/fs.h>
+#endif
+#include <linux/isdnif.h>
+#include <linux/isdn_compat.h>
+#include "isdn_divert.h"
+
+/*********************************/
+/* Variables for interface queue */
+/*********************************/
+ulong if_used = 0; /* number of interface users */
+static struct divert_info *divert_info_head = NULL; /* head of queue */
+static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
+#ifdef COMPAT_HAS_NEW_WAITQ
+static wait_queue_head_t rd_queue;
+#else
+static struct wait_queue *rd_queue = 0; /* Queue IO */
+#endif
+
+/*********************************/
+/* put an info buffer into queue */
+/*********************************/
+void put_info_buffer(char *cp)
+{ struct divert_info *ib;
+ int flags;
+
+ if (if_used <= 0) return;
+ if (!cp) return;
+ if (!*cp) return;
+ if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info)+strlen(cp), GFP_ATOMIC))) return; /* no memory */
+ strcpy(ib->info_start,cp); /* set output string */
+ ib->next = NULL;
+ save_flags(flags);
+ cli();
+ ib->usage_cnt = if_used;
+ if (!divert_info_head)
+ divert_info_head = ib; /* new head */
+ else
+ divert_info_tail->next = ib; /* follows existing messages */
+ divert_info_tail = ib; /* new tail */
+ restore_flags(flags);
+
+ /* delete old entrys */
+ while (divert_info_head->next)
+ { if ((divert_info_head->usage_cnt <= 0) &&
+ (divert_info_head->next->usage_cnt <= 0))
+ { ib = divert_info_head;
+ divert_info_head = divert_info_head->next;
+ kfree(ib);
+ }
+ else break;
+ } /* divert_info_head->next */
+ wake_up_interruptible(&(rd_queue));
+} /* put_info_buffer */
+
+/**********************************/
+/* deflection device read routine */
+/**********************************/
+#if (LINUX_VERSION_CODE < 0x020117)
+static int isdn_divert_read(struct inode *inode, struct file *file, char *buf, RWARG count)
+#else
+static ssize_t isdn_divert_read(struct file *file, char *buf, size_t count, loff_t *off)
+#endif
+{ struct divert_info *inf;
+ int len;
+
+ if (!*((struct divert_info **)file->private_data))
+ { if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ interruptible_sleep_on(&(rd_queue));
+ }
+ if (!(inf = *((struct divert_info **)file->private_data))) return(0);
+
+ inf->usage_cnt--; /* new usage count */
+ (struct divert_info **)file->private_data = &inf->next; /* next structure */
+ if ((len = strlen(inf->info_start)) <= count)
+ { if (copy_to_user(buf, inf->info_start, len))
+ return -EFAULT;
+ file->f_pos += len;
+ return(len);
+ }
+ return(0);
+} /* isdn_divert_read */
+
+/**********************************/
+/* deflection device write routine */
+/**********************************/
+#if (LINUX_VERSION_CODE < 0x020117)
+static int isdn_divert_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
+#else
+static ssize_t isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t *off)
+#endif
+{
+ return(-ENODEV);
+} /* isdn_divert_write */
+
+
+/***************************************/
+/* select routines for various kernels */
+/***************************************/
+#if (LINUX_VERSION_CODE < 0x020117)
+static int isdn_divert_select(struct inode *inode, struct file *file, int type, select_table * st)
+{
+ if (*((struct divert_info **)file->private_data))
+ return 1;
+ else
+ { if (st) select_wait(&(rd_queue), st);
+ return 0;
+ }
+} /* isdn_divert_select */
+#else
+static unsigned int isdn_divert_poll(struct file *file, poll_table * wait)
+{ unsigned int mask = 0;
+
+ poll_wait(file, &(rd_queue), wait);
+ /* mask = POLLOUT | POLLWRNORM; */
+ if (*((struct divert_info **)file->private_data))
+ { mask |= POLLIN | POLLRDNORM;
+ }
+ return mask;
+} /* isdn_divert_poll */
+#endif
+
+/****************/
+/* Open routine */
+/****************/
+static int isdn_divert_open(struct inode *ino, struct file *filep)
+{ int flags;
+
+ MOD_INC_USE_COUNT;
+ save_flags(flags);
+ cli();
+ if_used++;
+ if (divert_info_head)
+ (struct divert_info **)filep->private_data = &(divert_info_tail->next);
+ else
+ (struct divert_info **)filep->private_data = &divert_info_head;
+ restore_flags(flags);
+ /* start_divert(); */
+ return(0);
+} /* isdn_divert_open */
+
+/*******************/
+/* close routine */
+/*******************/
+#if (LINUX_VERSION_CODE < 0x020117)
+static void isdn_divert_close(struct inode *ino, struct file *filep)
+#else
+static int isdn_divert_close(struct inode *ino, struct file *filep)
+#endif
+{ struct divert_info *inf;
+ int flags;
+
+ save_flags(flags);
+ cli();
+ if_used--;
+ inf = *((struct divert_info **)filep->private_data);
+ while (inf)
+ { inf->usage_cnt--;
+ inf = inf->next;
+ }
+ restore_flags(flags);
+ if (if_used <= 0)
+ while (divert_info_head)
+ { inf = divert_info_head;
+ divert_info_head = divert_info_head->next;
+ kfree(inf);
+ }
+ MOD_DEC_USE_COUNT;
+#if (LINUX_VERSION_CODE < 0x020117)
+#else
+ return(0);
+#endif
+} /* isdn_divert_close */
+
+/*********/
+/* IOCTL */
+/*********/
+static int isdn_divert_ioctl(struct inode *inode, struct file *file,
+ uint cmd, ulong arg)
+{ divert_ioctl dioctl;
+ int i, flags;
+ divert_rule *rulep;
+ char *cp;
+
+ if ((i = copy_from_user(&dioctl,(char *) arg, sizeof(dioctl))))
+ return(i);
+
+ switch (cmd)
+ {
+ case IIOCGETVER:
+ dioctl.drv_version = DIVERT_IIOC_VERSION ; /* set version */
+ break;
+
+ case IIOCGETDRV:
+ if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
+ return(-EINVAL);
+ break;
+
+ case IIOCGETNAM:
+ cp = divert_if.drv_to_name(dioctl.getid.drvid);
+ if (!cp) return(-EINVAL);
+ if (!*cp) return(-EINVAL);
+ strcpy(dioctl.getid.drvnam,cp);
+ break;
+
+ case IIOCGETRULE:
+ if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
+ return(-EINVAL);
+ dioctl.getsetrule.rule = *rulep; /* copy data */
+ break;
+
+ case IIOCMODRULE:
+ if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
+ return(-EINVAL);
+ save_flags(flags);
+ cli();
+ *rulep = dioctl.getsetrule.rule; /* copy data */
+ restore_flags(flags);
+ return(0); /* no copy required */
+ break;
+
+ case IIOCINSRULE:
+ return(insertrule(dioctl.getsetrule.ruleidx,&dioctl.getsetrule.rule));
+ break;
+
+ case IIOCDELRULE:
+ return(deleterule(dioctl.getsetrule.ruleidx));
+ break;
+
+ case IIOCDODFACT:
+ return(deflect_extern_action(dioctl.fwd_ctrl.subcmd,
+ dioctl.fwd_ctrl.callid,
+ dioctl.fwd_ctrl.to_nr));
+
+ case IIOCDOCFACT:
+ case IIOCDOCFDIS:
+ case IIOCDOCFINT:
+ if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
+ return(-EINVAL); /* invalid driver */
+ if ((i = cf_command(dioctl.cf_ctrl.drvid,
+ (cmd == IIOCDOCFACT) ? 1: (cmd == IIOCDOCFDIS) ? 0:2,
+ dioctl.cf_ctrl.cfproc,
+ dioctl.cf_ctrl.msn,
+ dioctl.cf_ctrl.service,
+ dioctl.cf_ctrl.fwd_nr,
+ &dioctl.cf_ctrl.procid)))
+ return(i);
+ break;
+
+ default:
+ return(-EINVAL);
+ } /* switch cmd */
+ return(copy_to_user((char *) arg, &dioctl, sizeof(dioctl))); /* success */
+} /* isdn_divert_ioctl */
+
+
+#ifdef CONFIG_PROC_FS
+#if (LINUX_VERSION_CODE < 0x020117)
+static LSTYPE
+isdn_divert_lseek(struct inode *inode, struct file *file, LSARG offset, int orig)
+#else
+static loff_t
+isdn_divert_lseek(struct file *file, loff_t offset, int orig)
+#endif
+{
+ return -ESPIPE;
+}
+
+#if (LINUX_VERSION_CODE < 0x020117)
+static struct file_operations isdn_fops =
+{
+ isdn_divert_lseek,
+ isdn_divert_read,
+ isdn_divert_write,
+ NULL, /* isdn_readdir */
+ isdn_divert_select, /* isdn_select */
+ isdn_divert_ioctl, /* isdn_ioctl */
+ NULL, /* isdn_mmap */
+ isdn_divert_open,
+ isdn_divert_close,
+ NULL /* fsync */
+};
+
+#else
+
+static struct file_operations isdn_fops =
+{
+ isdn_divert_lseek,
+ isdn_divert_read,
+ isdn_divert_write,
+ NULL, /* isdn_readdir */
+ isdn_divert_poll, /* isdn_poll */
+ isdn_divert_ioctl, /* isdn_ioctl */
+ NULL, /* isdn_mmap */
+ isdn_divert_open,
+ NULL, /* flush */
+ isdn_divert_close,
+ NULL /* fsync */
+};
+#endif /* kernel >= 2.1 */
+
+
+/*
+ * proc directories can do almost nothing..
+ */
+struct inode_operations proc_isdn_inode_ops = {
+ &isdn_fops, /* isdn divert special file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+/****************************/
+/* isdn subdir in /proc/net */
+/****************************/
+static struct proc_dir_entry isdn_proc_entry =
+ { 0, 4, "isdn", S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, 0,
+ &proc_dir_inode_operations,NULL,NULL,NULL,NULL,NULL
+ };
+
+static struct proc_dir_entry isdn_divert_entry =
+{ 0, 6, "divert",S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_isdn_inode_ops,
+ NULL
+ };
+
+/*****************************************************************/
+/* variables used for automatic determining existence of proc fs */
+/*****************************************************************/
+static int (*proc_reg_dynamic)(struct proc_dir_entry *, struct proc_dir_entry *) = NULL;
+static int (*proc_unreg)(struct proc_dir_entry *, int) = NULL;
+
+#endif CONFIG_PROC_FS
+
+/***************************************************************************/
+/* divert_dev_init must be called before the proc filesystem may be used */
+/***************************************************************************/
+int divert_dev_init(void)
+{ int i;
+
+#ifdef COMPAT_HAS_NEW_WAITQ
+ init_waitqueue_head(&rd_queue);
+#endif
+
+#ifdef CONFIG_PROC_FS
+#if (LINUX_VERSION_CODE < 0x020117)
+ (void *) proc_reg_dynamic = get_module_symbol("","proc_register_dynamic");
+ (void *) proc_unreg = get_module_symbol("","proc_unregister");
+ if (proc_unreg)
+ { i = proc_reg_dynamic(&proc_net,&isdn_proc_entry);
+ if (i) return(i);
+ i = proc_reg_dynamic(&isdn_proc_entry,&isdn_divert_entry);
+ if (i)
+ { proc_unreg(&proc_net,isdn_proc_entry.low_ino);
+ return(i);
+ }
+ } /* proc exists */
+#else
+ (void *) proc_reg_dynamic = get_module_symbol("","proc_register");
+ (void *) proc_unreg = get_module_symbol("","proc_unregister");
+ if (proc_unreg)
+ { i = proc_reg_dynamic(proc_net,&isdn_proc_entry);
+ if (i) return(i);
+ i = proc_reg_dynamic(&isdn_proc_entry,&isdn_divert_entry);
+ if (i)
+ { proc_unreg(proc_net,isdn_proc_entry.low_ino);
+ return(i);
+ }
+ } /* proc exists */
+#endif
+#endif CONFIG_PROC_FS
+
+ return(0);
+} /* divert_dev_init */
+
+/***************************************************************************/
+/* divert_dev_deinit must be called before leaving isdn when included as */
+/* a module. */
+/***************************************************************************/
+int divert_dev_deinit(void)
+{ int i;
+
+#ifdef CONFIG_PROC_FS
+ if (proc_unreg)
+ { i = proc_unreg(&isdn_proc_entry,isdn_divert_entry.low_ino);
+ if (i) return(i);
+#if (LINUX_VERSION_CODE < 0x020117)
+ i = proc_unreg(&proc_net,isdn_proc_entry.low_ino);
+#else
+ i = proc_unreg(proc_net,isdn_proc_entry.low_ino);
+#endif
+ if (i) return(i);
+ } /* proc exists */
+#endif CONFIG_PROC_FS
+
+ return(0);
+} /* divert_dev_deinit */
+
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
new file mode 100644
index 000000000..f10ea18b2
--- /dev/null
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -0,0 +1,911 @@
+/*
+ * $Id: isdn_divert.c,v 1.4 1999/08/25 20:02:21 werner Exp $
+ *
+ * DSS1 main diversion supplementary handling for i4l.
+ *
+ * Copyright 1999 by Werner Cornelius (werner@isdn4linux.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_divert.c,v $
+ * Revision 1.4 1999/08/25 20:02:21 werner
+ * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts
+ * with existing software definitions. (PtP incomplete called party number)
+ *
+ * Revision 1.3 1999/08/22 20:26:35 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.2 1999/07/04 21:37:32 werner
+ * Ported from kernel version 2.0
+ *
+ *
+ *
+ */
+
+
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include "isdn_divert.h"
+
+/**********************************/
+/* structure keeping calling info */
+/**********************************/
+struct call_struc
+ { isdn_ctrl ics; /* delivered setup + driver parameters */
+ ulong divert_id; /* Id delivered to user */
+ unsigned char akt_state; /* actual state */
+ char deflect_dest[35]; /* deflection destination */
+ struct timer_list timer; /* timer control structure */
+ char info[90]; /* device info output */
+ struct call_struc *next; /* pointer to next entry */
+ struct call_struc *prev;
+ };
+
+
+/********************************************/
+/* structure keeping deflection table entry */
+/********************************************/
+struct deflect_struc
+ { struct deflect_struc *next,*prev;
+ divert_rule rule; /* used rule */
+ };
+
+
+/*****************************************/
+/* variables for main diversion services */
+/*****************************************/
+/* diversion/deflection processes */
+static struct call_struc *divert_head = NULL; /* head of remembered entrys */
+static ulong next_id = 1; /* next info id */
+static struct deflect_struc *table_head = NULL;
+static struct deflect_struc *table_tail = NULL;
+static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
+
+/***************************/
+/* timer callback function */
+/***************************/
+static void deflect_timer_expire(ulong arg)
+{ int flags;
+ struct call_struc *cs = (struct call_struc *) arg;
+
+ save_flags(flags);
+ cli();
+ del_timer(&cs->timer); /* delete active timer */
+ restore_flags(flags);
+
+ switch(cs->akt_state)
+ { case DEFLECT_PROCEED:
+ cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
+ divert_if.ll_cmd(&cs->ics);
+ save_flags(flags);
+ cli();
+ cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+ add_timer(&cs->timer);
+ restore_flags(flags);
+ break;
+
+ case DEFLECT_ALERT:
+ cs->ics.command = ISDN_CMD_REDIR; /* protocol */
+ strcpy(cs->ics.parm.setup.phone,cs->deflect_dest);
+ strcpy(cs->ics.parm.setup.eazmsn,"Testtext delayed");
+ divert_if.ll_cmd(&cs->ics);
+ save_flags(flags);
+ cli();
+ cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+ add_timer(&cs->timer);
+ restore_flags(flags);
+ break;
+
+ case DEFLECT_AUTODEL:
+ default:
+ save_flags(flags);
+ cli();
+ if (cs->prev)
+ cs->prev->next = cs->next; /* forward link */
+ else
+ divert_head = cs->next;
+ if (cs->next)
+ cs->next->prev = cs->prev; /* back link */
+ restore_flags(flags);
+ kfree(cs);
+ return;
+
+ } /* switch */
+} /* deflect_timer_func */
+
+
+/*****************************************/
+/* handle call forwarding de/activations */
+/* 0 = deact, 1 = act, 2 = interrogate */
+/*****************************************/
+int cf_command(int drvid, int mode,
+ u_char proc, char *msn,
+ u_char service, char *fwd_nr, ulong *procid)
+{ int retval,msnlen,flags;
+ int fwd_len;
+ char *p,*ielenp,tmp[60];
+ struct call_struc *cs;
+
+ if (strchr(msn,'.')) return(-EINVAL); /* subaddress not allowed in msn */
+ if ((proc & 0x7F) > 2) return(-EINVAL);
+ proc &= 3;
+ p = tmp;
+ *p++ = 0x30; /* enumeration */
+ ielenp = p++; /* remember total length position */
+ *p++ = 0xa; /* proc tag */
+ *p++ = 1; /* length */
+ *p++ = proc & 0x7F; /* procedure to de/activate/interrogate */
+ *p++ = 0xa; /* service tag */
+ *p++ = 1; /* length */
+ *p++ = service; /* service to handle */
+
+ if (mode == 1)
+ { if (!*fwd_nr) return(-EINVAL); /* destination missing */
+ if (strchr(fwd_nr,'.')) return(-EINVAL); /* subaddress not allowed */
+ fwd_len = strlen(fwd_nr);
+ *p++ = 0x30; /* number enumeration */
+ *p++ = fwd_len + 2; /* complete forward to len */
+ *p++ = 0x80; /* fwd to nr */
+ *p++ = fwd_len; /* length of number */
+ strcpy(p,fwd_nr); /* copy number */
+ p += fwd_len; /* pointer beyond fwd */
+ } /* activate */
+
+ msnlen = strlen(msn);
+ *p++ = 0x80; /* msn number */
+ if (msnlen > 1)
+ { *p++ = msnlen; /* length */
+ strcpy(p,msn);
+ p += msnlen;
+ }
+ else *p++ = 0;
+
+ *ielenp = p - ielenp - 1; /* set total IE length */
+
+ /* allocate mem for information struct */
+ if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
+ return(-ENOMEM); /* no memory */
+ init_timer(&cs->timer);
+ cs->info[0] = '\0';
+ cs->timer.function = deflect_timer_expire;
+ cs->timer.data = (ulong) cs; /* pointer to own structure */
+ cs->ics.driver = drvid;
+ cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */
+ cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */
+ cs->ics.parm.dss1_io.proc = (mode == 1) ? 7: (mode == 2) ? 11:8; /* operation */
+ cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */
+ cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */
+ cs->ics.parm.dss1_io.data = tmp; /* start of buffer */
+
+ save_flags(flags);
+ cli();
+ cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */
+ restore_flags(flags);
+ *procid = cs->ics.parm.dss1_io.ll_id;
+
+ sprintf(cs->info,"%d 0x%lx %s%s 0 %s %0x %d%s%s\n",
+ (!mode ) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
+ cs->ics.parm.dss1_io.ll_id,
+ (mode != 2) ? "" : "0 ",
+ divert_if.drv_to_name(cs->ics.driver),
+ msn,
+ service & 0xFF,
+ proc,
+ (mode != 1) ? "" : " 0 ",
+ (mode != 1) ? "" : fwd_nr);
+
+ retval = divert_if.ll_cmd(&cs->ics); /* excute command */
+
+ if (!retval)
+ { cs->prev = NULL;
+ save_flags(flags);
+ cli();
+ cs->next = divert_head;
+ divert_head = cs;
+ restore_flags(flags);
+ }
+ else
+ kfree(cs);
+ return(retval);
+} /* cf_command */
+
+
+/****************************************/
+/* handle a external deflection command */
+/****************************************/
+int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
+{ struct call_struc *cs;
+ isdn_ctrl ic;
+ int flags;
+ int i;
+
+ if ((cmd & 0x7F) > 2) return(-EINVAL); /* invalid command */
+ cs = divert_head; /* start of parameter list */
+ while (cs)
+ { if (cs->divert_id == callid) break; /* found */
+ cs = cs->next;
+ } /* search entry */
+ if (!cs) return(-EINVAL); /* invalid callid */
+
+ ic.driver = cs->ics.driver;
+ ic.arg = cs->ics.arg;
+ i = -EINVAL;
+ if (cs->akt_state == DEFLECT_AUTODEL) return(i); /* no valid call */
+ switch (cmd & 0x7F)
+ { case 0: /* hangup */
+ del_timer(&cs->timer);
+ ic.command = ISDN_CMD_HANGUP;
+ i = divert_if.ll_cmd(&ic);
+ save_flags(flags);
+ cli();
+ cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+ add_timer(&cs->timer);
+ restore_flags(flags);
+ break;
+
+ case 1: /* alert */
+ if (cs->akt_state == DEFLECT_ALERT) return(0);
+ cmd &= 0x7F; /* never wait */
+ del_timer(&cs->timer);
+ ic.command = ISDN_CMD_ALERT;
+ if ((i = divert_if.ll_cmd(&ic)))
+ { save_flags(flags);
+ cli();
+ cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+ add_timer(&cs->timer);
+ restore_flags(flags);
+ }
+ else
+ cs->akt_state = DEFLECT_ALERT;
+ break;
+
+ case 2: /* redir */
+ del_timer(&cs->timer);
+ strcpy(cs->ics.parm.setup.phone, to_nr);
+ strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
+ ic.command = ISDN_CMD_REDIR;
+ if ((i = divert_if.ll_cmd(&ic)))
+ { save_flags(flags);
+ cli();
+ cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+ add_timer(&cs->timer);
+ restore_flags(flags);
+ }
+ else
+ cs->akt_state = DEFLECT_ALERT;
+ break;
+
+ } /* switch */
+ return(i);
+} /* deflect_extern_action */
+
+/********************************/
+/* insert a new rule before idx */
+/********************************/
+int insertrule(int idx, divert_rule *newrule)
+{ struct deflect_struc *ds,*ds1;
+ int flags;
+
+ if (!(ds = (struct deflect_struc *) kmalloc(sizeof(struct deflect_struc),
+ GFP_KERNEL)))
+ return(-ENOMEM); /* no memory */
+
+ ds->rule = *newrule; /* set rule */
+
+ save_flags(flags);
+ cli();
+
+ if (idx >= 0)
+ { ds1 = table_head;
+ while ((ds1) && (idx > 0))
+ { idx--;
+ ds1 = ds1->next;
+ }
+ if (!ds1) idx = -1;
+ }
+
+ if (idx < 0)
+ { ds->prev = table_tail; /* previous entry */
+ ds->next = NULL; /* end of chain */
+ if (ds->prev)
+ ds->prev->next = ds; /* last forward */
+ else
+ table_head = ds; /* is first entry */
+ table_tail = ds; /* end of queue */
+ }
+ else
+ { ds->next = ds1; /* next entry */
+ ds->prev = ds1->prev; /* prev entry */
+ ds1->prev = ds; /* backward chain old element */
+ if (!ds->prev)
+ table_head = ds; /* first element */
+ }
+
+ restore_flags(flags);
+ return(0);
+} /* insertrule */
+
+/***********************************/
+/* delete the rule at position idx */
+/***********************************/
+int deleterule(int idx)
+{ struct deflect_struc *ds,*ds1;
+ int flags;
+
+ if (idx < 0)
+ { save_flags(flags);
+ cli();
+ ds = table_head;
+ table_head = NULL;
+ table_tail = NULL;
+ restore_flags(flags);
+ while (ds)
+ { ds1 = ds;
+ ds = ds->next;
+ kfree(ds1);
+ }
+ return(0);
+ }
+
+ save_flags(flags);
+ cli();
+ ds = table_head;
+
+ while ((ds) && (idx > 0))
+ { idx--;
+ ds = ds->next;
+ }
+
+ if (!ds)
+ { restore_flags(flags);
+ return(-EINVAL);
+ }
+
+ if (ds->next)
+ ds->next->prev = ds->prev; /* backward chain */
+ else
+ table_tail = ds->prev; /* end of chain */
+
+ if (ds->prev)
+ ds->prev->next = ds->next; /* forward chain */
+ else
+ table_head = ds->next; /* start of chain */
+
+ restore_flags(flags);
+ kfree(ds);
+ return(0);
+} /* deleterule */
+
+/*******************************************/
+/* get a pointer to a specific rule number */
+/*******************************************/
+divert_rule *getruleptr(int idx)
+{ struct deflect_struc *ds = table_head;
+
+ if (idx < 0) return(NULL);
+ while ((ds) && (idx >= 0))
+ { if (!(idx--))
+ { return(&ds->rule);
+ break;
+ }
+ ds = ds->next;
+ }
+ return(NULL);
+} /* getruleptr */
+
+/*************************************************/
+/* called from common module on an incoming call */
+/*************************************************/
+int isdn_divert_icall(isdn_ctrl *ic)
+{ int retval = 0;
+ int flags;
+ struct call_struc *cs = NULL;
+ struct deflect_struc *dv;
+ char *p,*p1;
+ u_char accept;
+
+ /* first check the internal deflection table */
+ for (dv = table_head; dv ; dv = dv->next )
+ { /* scan table */
+ if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
+ ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
+ continue; /* call option check */
+ if (!(dv->rule.drvid & (1L << ic->driver)))
+ continue; /* driver not matching */
+ if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1))
+ continue; /* si1 not matching */
+ if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2))
+ continue; /* si2 not matching */
+
+ p = dv->rule.my_msn;
+ p1 = ic->parm.setup.eazmsn;
+ accept = 0;
+ while (*p)
+ { /* complete compare */
+ if (*p == '-')
+ { accept = 1; /* call accepted */
+ break;
+ }
+ if (*p++ != *p1++)
+ break; /* not accepted */
+ if ((!*p) && (!*p1))
+ accept = 1;
+ } /* complete compare */
+ if (!accept) continue; /* not accepted */
+
+ if ((strcmp(dv->rule.caller,"0")) || (ic->parm.setup.phone[0]))
+ { p = dv->rule.caller;
+ p1 = ic->parm.setup.phone;
+ accept = 0;
+ while (*p)
+ { /* complete compare */
+ if (*p == '-')
+ { accept = 1; /* call accepted */
+ break;
+ }
+ if (*p++ != *p1++)
+ break; /* not accepted */
+ if ((!*p) && (!*p1))
+ accept = 1;
+ } /* complete compare */
+ if (!accept) continue; /* not accepted */
+ }
+
+ switch (dv->rule.action)
+ { case DEFLECT_IGNORE:
+ return(0);
+ break;
+
+ case DEFLECT_ALERT:
+ case DEFLECT_PROCEED:
+ case DEFLECT_REPORT:
+ case DEFLECT_REJECT:
+ if (dv->rule.action == DEFLECT_PROCEED)
+ if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
+ return(0); /* no external deflection needed */
+ if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
+ return(0); /* no memory */
+ init_timer(&cs->timer);
+ cs->info[0] = '\0';
+ cs->timer.function = deflect_timer_expire;
+ cs->timer.data = (ulong) cs; /* pointer to own structure */
+
+ cs->ics = *ic; /* copy incoming data */
+ if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone,"0");
+ if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn,"0");
+ cs->ics.parm.setup.screen = dv->rule.screen;
+ if (dv->rule.waittime)
+ cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
+ else
+ if (dv->rule.action == DEFLECT_PROCEED)
+ cs->timer.expires = jiffies + (HZ * extern_wait_max);
+ else
+ cs->timer.expires = 0;
+ cs->akt_state = dv->rule.action;
+ save_flags(flags);
+ cli();
+ cs->divert_id = next_id++; /* new sequence number */
+ restore_flags(flags);
+ cs->prev = NULL;
+ if (cs->akt_state == DEFLECT_ALERT)
+ { strcpy(cs->deflect_dest,dv->rule.to_nr);
+ if (!cs->timer.expires)
+ { strcpy(ic->parm.setup.eazmsn,"Testtext direkt");
+ ic->parm.setup.screen = dv->rule.screen;
+ strcpy(ic->parm.setup.phone,dv->rule.to_nr);
+ cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+ retval = 5;
+ }
+ else
+ retval = 1; /* alerting */
+ }
+ else
+ { cs->deflect_dest[0] = '\0';
+ retval = 4; /* only proceed */
+ }
+ sprintf(cs->info,"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
+ cs->akt_state,
+ cs->divert_id,
+ divert_if.drv_to_name(cs->ics.driver),
+ (ic->command == ISDN_STAT_ICALLW) ? "1":"0",
+ cs->ics.parm.setup.phone,
+ cs->ics.parm.setup.eazmsn,
+ cs->ics.parm.setup.si1,
+ cs->ics.parm.setup.si2,
+ cs->ics.parm.setup.screen,
+ dv->rule.waittime,
+ cs->deflect_dest);
+ if ((dv->rule.action == DEFLECT_REPORT) ||
+ (dv->rule.action == DEFLECT_REJECT))
+ { put_info_buffer(cs->info);
+ kfree(cs); /* remove */
+ return((dv->rule.action == DEFLECT_REPORT) ? 0:2); /* nothing to do */
+ }
+ break;
+
+ default:
+ return(0); /* ignore call */
+ break;
+ } /* switch action */
+ break;
+ } /* scan_table */
+
+ if (cs)
+ { cs->prev = NULL;
+ save_flags(flags);
+ cli();
+ cs->next = divert_head;
+ divert_head = cs;
+ if (cs->timer.expires) add_timer(&cs->timer);
+ restore_flags(flags);
+
+ put_info_buffer(cs->info);
+ return(retval);
+ }
+ else
+ return(0);
+} /* isdn_divert_icall */
+
+
+void deleteprocs(void)
+{ struct call_struc *cs, *cs1;
+ int flags;
+
+ save_flags(flags);
+ cli();
+ cs = divert_head;
+ divert_head = NULL;
+ while (cs)
+ { del_timer(&cs->timer);
+ cs1 = cs;
+ cs = cs->next;
+ kfree(cs1);
+ }
+ restore_flags(flags);
+} /* deleteprocs */
+
+/****************************************************/
+/* put a address including address type into buffer */
+/****************************************************/
+int put_address(char *st, u_char *p, int len)
+{ u_char retval = 0;
+ u_char adr_typ = 0; /* network standard */
+
+ if (len < 2) return(retval);
+ if (*p == 0xA1)
+ { retval = *(++p) + 2; /* total length */
+ if (retval > len) return(0); /* too short */
+ len = retval - 2; /* remaining length */
+ if (len < 3) return(0);
+ if ((*(++p) != 0x0A) || (*(++p) != 1)) return(0);
+ adr_typ = *(++p);
+ len -= 3;
+ p++;
+ if (len < 2) return(0);
+ if (*p++ != 0x12) return(0);
+ if (*p > len) return(0); /* check number length */
+ len = *p++;
+ }
+ else
+ if (*p == 0x80)
+ { retval = *(++p) + 2; /* total length */
+ if (retval > len) return(0);
+ len = retval - 2;
+ p++;
+ }
+ else
+ return(0); /* invalid address information */
+
+ sprintf(st,"%d ",adr_typ);
+ st += strlen(st);
+ if (!len)
+ *st++ = '-';
+ else
+ while (len--)
+ *st++ = *p++;
+ *st = '\0';
+ return(retval);
+} /* put_address */
+
+/*************************************/
+/* report a succesfull interrogation */
+/*************************************/
+int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
+{ char *src = ic->parm.dss1_io.data;
+ int restlen = ic->parm.dss1_io.datalen;
+ int cnt = 1;
+ u_char n,n1;
+ char st[90], *p, *stp;
+
+ if (restlen < 2) return(-100); /* frame too short */
+ if (*src++ != 0x30) return(-101);
+ if ((n = *src++) > 0x81) return(-102); /* invalid length field */
+ restlen -= 2; /* remaining bytes */
+ if (n == 0x80)
+ { if (restlen < 2) return(-103);
+ if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-104);
+ restlen -= 2;
+ }
+ else
+ if ( n == 0x81)
+ { n = *src++;
+ restlen--;
+ if (n > restlen) return(-105);
+ restlen = n;
+ }
+ else
+ if (n > restlen) return(-106);
+ else
+ restlen = n; /* standard format */
+ if (restlen < 3) return(-107); /* no procedure */
+ if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return(-108);
+ restlen -= 3;
+ if (restlen < 2) return(-109); /* list missing */
+ if (*src == 0x31)
+ { src++;
+ if ((n = *src++) > 0x81) return(-110); /* invalid length field */
+ restlen -= 2; /* remaining bytes */
+ if (n == 0x80)
+ { if (restlen < 2) return(-111);
+ if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-112);
+ restlen -= 2;
+ }
+ else
+ if ( n == 0x81)
+ { n = *src++;
+ restlen--;
+ if (n > restlen) return(-113);
+ restlen = n;
+ }
+ else
+ if (n > restlen) return(-114);
+ else
+ restlen = n; /* standard format */
+ } /* result list header */
+
+ while (restlen >= 2)
+ { stp = st;
+ sprintf(stp,"%d 0x%lx %d %s ",DIVERT_REPORT, ic->parm.dss1_io.ll_id,
+ cnt++,divert_if.drv_to_name(ic->driver));
+ stp += strlen(stp);
+ if (*src++ != 0x30) return(-115); /* invalid enum */
+ n = *src++;
+ restlen -= 2;
+ if (n > restlen) return(-116); /* enum length wrong */
+ restlen -= n;
+ p = src; /* one entry */
+ src += n;
+ if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
+ stp += strlen(stp);
+ p += n1;
+ n -= n1;
+ if (n < 6) continue; /* no service and proc */
+ if ((*p++ != 0x0A) || (*p++ != 1)) continue;
+ sprintf(stp," 0x%02x ",(*p++) & 0xFF);
+ stp += strlen(stp);
+ if ((*p++ != 0x0A) || (*p++ != 1)) continue;
+ sprintf(stp,"%d ",(*p++) & 0xFF);
+ stp += strlen(stp);
+ n -= 6;
+ if (n > 2)
+ { if (*p++ != 0x30) continue;
+ if (*p > (n-2)) continue;
+ n = *p++;
+ if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
+ stp += strlen(stp);
+ }
+ sprintf(stp,"\n");
+ put_info_buffer(st);
+ } /* while restlen */
+ if (restlen) return(-117);
+ return(0);
+} /* interrogate_success */
+
+/*********************************************/
+/* callback for protocol specific extensions */
+/*********************************************/
+int prot_stat_callback(isdn_ctrl *ic)
+{ struct call_struc *cs, *cs1;
+ int i,flags;
+
+ cs = divert_head; /* start of list */
+ cs1 = NULL;
+ while (cs)
+ { if (ic->driver == cs->ics.driver)
+ { switch (cs->ics.arg)
+ { case DSS1_CMD_INVOKE:
+ if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
+ (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id))
+ { switch (ic->arg)
+ { case DSS1_STAT_INVOKE_ERR:
+ sprintf(cs->info,"128 0x%lx 0x%x\n",
+ ic->parm.dss1_io.ll_id,
+ ic->parm.dss1_io.timeout);
+ put_info_buffer(cs->info);
+ break;
+
+ case DSS1_STAT_INVOKE_RES:
+ switch (cs->ics.parm.dss1_io.proc)
+ { case 7:
+ case 8:
+ put_info_buffer(cs->info);
+ break;
+
+ case 11:
+ i = interrogate_success(ic,cs);
+ if (i)
+ sprintf(cs->info,"%d 0x%lx %d\n",DIVERT_REPORT,
+ ic->parm.dss1_io.ll_id,i);
+ put_info_buffer(cs->info);
+ break;
+
+ default:
+ printk(KERN_WARNING "dss1_divert: unknown proc %d\n",cs->ics.parm.dss1_io.proc);
+ break;
+ }
+
+
+#if 0
+ sprintf(st, "0x%lx 0x%lx",ic->arg, ic->parm.dss1_io.ll_id);
+ p = st + strlen(st);
+ p1 = ic->parm.dss1_io.data;
+ i = ic->parm.dss1_io.datalen;
+ while ((i > 0) && (p - st < 530))
+ { p += sprintf(p," %02x",(*p1++) & 0xFF);
+ i--;
+ }
+ sprintf(p, "\n");
+ put_info_buffer(st);
+#endif
+ break;
+
+ default:
+ printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n",ic->arg);
+ break;
+ }
+ cs1 = cs; /* remember structure */
+ cs = NULL;
+ continue; /* abort search */
+ } /* id found */
+ break;
+
+ case DSS1_CMD_INVOKE_ABORT:
+ printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
+ break;
+
+ default:
+ printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n",cs->ics.arg);
+ break;
+ } /* switch ics.arg */
+ cs = cs->next;
+ } /* driver ok */
+ }
+
+ if (!cs1)
+ { printk(KERN_WARNING "dss1_divert unhandled process\n");
+ return(0);
+ }
+
+ if (cs1->ics.driver == -1)
+ { save_flags(flags);
+ cli();
+ del_timer(&cs1->timer);
+ if (cs1->prev)
+ cs1->prev->next = cs1->next; /* forward link */
+ else
+ divert_head = cs1->next;
+ if (cs1->next)
+ cs1->next->prev = cs1->prev; /* back link */
+ restore_flags(flags);
+ kfree(cs1);
+ }
+
+ return(0);
+} /* prot_stat_callback */
+
+
+/***************************/
+/* status callback from HL */
+/***************************/
+int isdn_divert_stat_callback(isdn_ctrl *ic)
+{ struct call_struc *cs, *cs1;
+ int flags, retval;
+
+ retval = -1;
+ cs = divert_head; /* start of list */
+ while (cs)
+ { if ((ic->driver == cs->ics.driver) && (ic->arg == cs->ics.arg))
+ { switch (ic->command)
+ { case ISDN_STAT_DHUP:
+ sprintf(cs->info,"129 0x%lx\n",cs->divert_id);
+ del_timer(&cs->timer);
+ cs->ics.driver = -1;
+ break;
+
+ case ISDN_STAT_CAUSE:
+ sprintf(cs->info,"130 0x%lx %s\n",cs->divert_id,ic->parm.num);
+ break;
+
+ case ISDN_STAT_REDIR:
+ sprintf(cs->info,"131 0x%lx\n",cs->divert_id);
+ del_timer(&cs->timer);
+ cs->ics.driver = -1;
+ break;
+
+ default:
+ sprintf(cs->info,"999 0x%lx 0x%x\n",cs->divert_id,(int)(ic->command));
+ break;
+ }
+ put_info_buffer(cs->info);
+ retval = 0;
+ }
+ cs1 = cs;
+ cs = cs->next;
+ if (cs1->ics.driver == -1)
+ {
+ save_flags(flags);
+ cli();
+ if (cs1->prev)
+ cs1->prev->next = cs1->next; /* forward link */
+ else
+ divert_head = cs1->next;
+ if (cs1->next)
+ cs1->next->prev = cs1->prev; /* back link */
+ restore_flags(flags);
+ kfree(cs1);
+ }
+ }
+ return(retval); /* not found */
+} /* isdn_divert_stat_callback */
+
+
+/********************/
+/* callback from ll */
+/********************/
+int ll_callback(isdn_ctrl *ic)
+{
+ switch (ic->command)
+ { case ISDN_STAT_ICALL:
+ case ISDN_STAT_ICALLW:
+ return(isdn_divert_icall(ic));
+ break;
+
+ case ISDN_STAT_PROT:
+ if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO)
+ { if (ic->arg != DSS1_STAT_INVOKE_BRD)
+ return(prot_stat_callback(ic));
+ else
+ return(0); /* DSS1 invoke broadcast */
+ }
+ else
+ return(-1); /* protocol not euro */
+
+ default:
+ return(isdn_divert_stat_callback(ic));
+ }
+} /* ll_callback */
+
diff --git a/drivers/isdn/divert/isdn_divert.h b/drivers/isdn/divert/isdn_divert.h
new file mode 100644
index 000000000..1d329c0fb
--- /dev/null
+++ b/drivers/isdn/divert/isdn_divert.h
@@ -0,0 +1,164 @@
+/*
+ * $Id: isdn_divert.h,v 1.3 1999/08/22 20:26:37 calle Exp $
+ *
+ * Header for the diversion supplementary ioctl interface.
+ *
+ * Copyright 1998 by Werner Cornelius (werner@ikt.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_divert.h,v $
+ * Revision 1.3 1999/08/22 20:26:37 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.2 1999/07/04 21:37:33 werner
+ * Ported from kernel version 2.0
+ *
+ *
+ *
+ */
+
+
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/******************************************/
+/* IOCTL codes for interface to user prog */
+/******************************************/
+#define DIVERT_IIOC_VERSION 0x01 /* actual version */
+#define IIOCGETVER _IO('I', 1) /* get version of interface */
+#define IIOCGETDRV _IO('I', 2) /* get driver number */
+#define IIOCGETNAM _IO('I', 3) /* get driver name */
+#define IIOCGETRULE _IO('I', 4) /* read one rule */
+#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */
+#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */
+#define IIOCDELRULE _IO('I', 7) /* delete a rule */
+#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */
+#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */
+#define IIOCDOCFDIS _IO('I',10) /* deactivate control forwarding in PBX */
+#define IIOCDOCFINT _IO('I',11) /* interrogate control forwarding in PBX */
+
+/*************************************/
+/* states reported through interface */
+/*************************************/
+#define DEFLECT_IGNORE 0 /* ignore incoming call */
+#define DEFLECT_REPORT 1 /* only report */
+#define DEFLECT_PROCEED 2 /* deflect when externally triggered */
+#define DEFLECT_ALERT 3 /* alert and deflect after delay */
+#define DEFLECT_REJECT 4 /* reject immediately */
+#define DIVERT_ACTIVATE 5 /* diversion activate */
+#define DIVERT_DEACTIVATE 6 /* diversion deactivate */
+#define DIVERT_REPORT 7 /* interrogation result */
+#define DEFLECT_AUTODEL 255 /* only for internal use */
+
+#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */
+
+typedef struct
+ { ulong drvid; /* driver ids, bit mapped */
+ char my_msn[35]; /* desired msn, subaddr allowed */
+ char caller[35]; /* caller id, partial string with * + subaddr allowed */
+ char to_nr[35]; /* deflected to number incl. subaddress */
+ u_char si1,si2; /* service indicators, si1=bitmask, si1+2 0 = all */
+ u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */
+ u_char callopt; /* option for call handling:
+ 0 = all calls
+ 1 = only non waiting calls
+ 2 = only waiting calls */
+ u_char action; /* desired action:
+ 0 = don't report call -> ignore
+ 1 = report call, do not allow/proceed for deflection
+ 2 = report call, send proceed, wait max waittime secs
+ 3 = report call, alert and deflect after waittime
+ 4 = report call, reject immediately
+ actions 1-2 only take place if interface is opened
+ */
+ u_char waittime; /* maximum wait time for proceeding */
+ } divert_rule;
+
+typedef union
+ { int drv_version; /* return of driver version */
+ struct
+ { int drvid; /* id of driver */
+ char drvnam[30]; /* name of driver */
+ } getid;
+ struct
+ { int ruleidx; /* index of rule */
+ divert_rule rule; /* rule parms */
+ } getsetrule;
+ struct
+ { u_char subcmd; /* 0 = hangup/reject,
+ 1 = alert,
+ 2 = deflect */
+ ulong callid; /* id of call delivered by ascii output */
+ char to_nr[35]; /* destination when deflect,
+ else uus1 string (maxlen 31),
+ data from rule used if empty */
+ } fwd_ctrl;
+ struct
+ { int drvid; /* id of driver */
+ u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */
+ ulong procid; /* process id returned when no error */
+ u_char service; /* basically coded service, 0 = all */
+ char msn[25]; /* desired msn, empty = all */
+ char fwd_nr[35];/* forwarded to number + subaddress */
+ } cf_ctrl;
+ } divert_ioctl;
+
+#ifdef __KERNEL__
+
+#include <linux/isdnif.h>
+#include <linux/isdn_divertif.h>
+
+#define AUTODEL_TIME 30 /* timeout in s to delete internal entrys */
+
+/**************************************************/
+/* structure keeping ascii info for device output */
+/**************************************************/
+struct divert_info
+ { struct divert_info *next;
+ ulong usage_cnt; /* number of files still to work */
+ char info_start[2]; /* info string start */
+ };
+
+
+/**************/
+/* Prototypes */
+/**************/
+extern ulong if_used; /* number of interface users */
+extern int divert_dev_deinit(void);
+extern int divert_dev_init(void);
+extern void put_info_buffer(char *);
+extern int ll_callback(isdn_ctrl *);
+extern isdn_divert_if divert_if;
+extern divert_rule *getruleptr(int);
+extern int insertrule(int, divert_rule *);
+extern int deleterule(int);
+extern void deleteprocs(void);
+extern int deflect_extern_action(u_char, ulong, char *);
+extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *);
+
+#endif __KERNEL__
+
+
+
+
+
+
+
+
diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h
index 9552d2b54..beee023dc 100644
--- a/drivers/isdn/eicon/eicon.h
+++ b/drivers/isdn/eicon/eicon.h
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.5 1999/03/29 11:19:41 armin Exp $
+/* $Id: eicon.h,v 1.11 1999/08/29 17:23:44 armin Exp $
*
* ISDN low-level module for Eicon.Diehl active ISDN-Cards.
*
@@ -21,6 +21,33 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon.h,v $
+ * Revision 1.11 1999/08/29 17:23:44 armin
+ * New setup compat.
+ * Bugfix if compile as not module.
+ *
+ * Revision 1.10 1999/08/22 20:26:41 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.9 1999/08/18 20:16:57 armin
+ * Added XLOG function for all cards.
+ * Bugfix of alloc_skb NULL pointer.
+ *
+ * Revision 1.8 1999/07/25 15:12:01 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
+ * Revision 1.7 1999/07/11 17:16:23 armin
+ * Bugfixes in queue handling.
+ * Added DSP-DTMF decoder functions.
+ * Reorganized ack_handler.
+ *
+ * Revision 1.6 1999/06/09 19:31:24 armin
+ * Wrong PLX size for request_region() corrected.
+ * Added first MCA code from Erik Weber.
+ *
* Revision 1.5 1999/03/29 11:19:41 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
@@ -60,6 +87,7 @@
#define EICON_IOCTL_LOADPCI 7
#define EICON_IOCTL_LOADISA 8
#define EICON_IOCTL_GETVER 9
+#define EICON_IOCTL_GETXLOG 10
#define EICON_IOCTL_MANIF 90
@@ -89,6 +117,7 @@
#define MAX_HEADER_LEN 10
+
/* Struct for adding new cards */
typedef struct eicon_cdef {
int membase;
@@ -100,6 +129,7 @@ typedef struct eicon_cdef {
#define EICON_ISA_BOOT_NORMAL 2
/* Struct for downloading protocol via ioctl for ISA cards */
+/* same struct for downloading protocol via ioctl for MCA cards */
typedef struct {
/* start-up parameters */
unsigned char tei;
@@ -156,6 +186,7 @@ typedef struct {
/* Data for downloading protocol via ioctl */
typedef union {
eicon_isa_codebuf isa;
+ eicon_isa_codebuf mca;
eicon_pci_codebuf pci;
} eicon_codebuf;
@@ -171,6 +202,7 @@ typedef struct {
#ifdef __KERNEL__
/* Kernel includes */
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/tqueue.h>
@@ -194,6 +226,8 @@ typedef struct {
#include <linux/isdnif.h>
+#include <linux/isdn_compat.h>
+
typedef struct {
__u16 length __attribute__ ((packed)); /* length of data/parameter field */
__u8 P[1]; /* data/parameter field */
@@ -209,6 +243,92 @@ typedef struct {
#endif /* KERNEL */
+#define DIVAS_SHARED_OFFSET (0x1000)
+
+#define MIPS_BUFFER_SZ 128
+#define MIPS_MAINT_OFFS 0xff00
+
+#define XLOG_ERR_CARD_NUM (13)
+#define XLOG_ERR_DONE (14)
+#define XLOG_ERR_CMD (15)
+#define XLOG_ERR_TIMEOUT (16)
+#define XLOG_ERR_CARD_STATE (17)
+#define XLOG_ERR_UNKNOWN (18)
+#define XLOG_OK (0)
+
+typedef struct {
+ __u8 Id __attribute__ ((packed));
+ __u8 uX __attribute__ ((packed));
+ __u8 listen __attribute__ ((packed));
+ __u8 active __attribute__ ((packed));
+ __u8 sin[3] __attribute__ ((packed));
+ __u8 bc[6] __attribute__ ((packed));
+ __u8 llc[6] __attribute__ ((packed));
+ __u8 hlc[6] __attribute__ ((packed));
+ __u8 oad[20] __attribute__ ((packed));
+}DSigStruc;
+
+typedef struct {
+ __u32 cx_b1 __attribute__ ((packed));
+ __u32 cx_b2 __attribute__ ((packed));
+ __u32 cr_b1 __attribute__ ((packed));
+ __u32 cr_b2 __attribute__ ((packed));
+ __u32 px_b1 __attribute__ ((packed));
+ __u32 px_b2 __attribute__ ((packed));
+ __u32 pr_b1 __attribute__ ((packed));
+ __u32 pr_b2 __attribute__ ((packed));
+ __u16 er_b1 __attribute__ ((packed));
+ __u16 er_b2 __attribute__ ((packed));
+}BL1Struc;
+
+typedef struct {
+ __u32 XTotal __attribute__ ((packed));
+ __u32 RTotal __attribute__ ((packed));
+ __u16 XError __attribute__ ((packed));
+ __u16 RError __attribute__ ((packed));
+}L2Struc;
+
+typedef struct {
+ __u16 free_n;
+}OSStruc;
+
+typedef union
+{
+ DSigStruc DSigStats;
+ BL1Struc BL1Stats;
+ L2Struc L2Stats;
+ OSStruc OSStats;
+ __u8 b[MIPS_BUFFER_SZ];
+ __u16 w[MIPS_BUFFER_SZ>>1];
+ __u16 l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+ __u32 d[MIPS_BUFFER_SZ>>2];
+} MIPS_BUFFER;
+
+typedef struct
+{
+ __u8 req __attribute__ ((packed));
+ __u8 rc __attribute__ ((packed));
+ __u8 reserved[2] __attribute__ ((packed)); /* R3000 alignment ... */
+ __u8 *mem __attribute__ ((packed));
+ __u16 length __attribute__ ((packed)); /* used to be short */
+ __u16 port __attribute__ ((packed));
+ __u8 fill[4] __attribute__ ((packed)); /* data at offset 16 */
+ MIPS_BUFFER data __attribute__ ((packed));
+} mi_pc_maint_t;
+
+typedef struct
+{
+ __u16 command;
+ mi_pc_maint_t pcm;
+}xlogreq_t;
+
+typedef struct{
+ __u16 code __attribute__ ((packed)); /* used to be short */
+ __u16 timeh __attribute__ ((packed));
+ __u16 timel __attribute__ ((packed));
+ char buffer[MIPS_BUFFER_SZ - 6];
+}xlog_entry_t;
+
#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100
@@ -333,19 +453,39 @@ typedef struct {
__u16 ref; /* saved reference */
} entity;
+#define FAX_MAX_SCANLINE 256
+
+typedef struct {
+ __u8 PrevObject;
+ __u8 NextObject;
+ __u8 abLine[FAX_MAX_SCANLINE];
+ __u8 abFrame[FAX_MAX_SCANLINE];
+ unsigned int LineLen;
+ unsigned int LineDataLen;
+ __u32 LineData;
+ unsigned int NullBytesPos;
+ __u8 NullByteExist;
+ int PageCount;
+ __u8 Dle;
+ __u8 Eop;
+} eicon_ch_fax_buf;
typedef struct {
int No; /* Channel Number */
unsigned short callref; /* Call Reference */
unsigned short fsm_state; /* Current D-Channel state */
unsigned short eazmask; /* EAZ-Mask for this Channel */
- unsigned int queued; /* User-Data Bytes in TX queue */
- unsigned int waitq; /* User-Data Bytes in wait queue */
- unsigned int waitpq; /* User-Data Bytes in packet queue */
+ int queued; /* User-Data Bytes in TX queue */
+ int waitq; /* User-Data Bytes in wait queue */
+ int waitpq; /* User-Data Bytes in packet queue */
unsigned short plci;
unsigned short ncci;
unsigned char l2prot; /* Layer 2 protocol */
unsigned char l3prot; /* Layer 3 protocol */
+#ifdef CONFIG_ISDN_TTY_FAX
+ T30_s *fax; /* pointer to fax data in LL */
+ eicon_ch_fax_buf fax2; /* fax related struct */
+#endif
entity e; /* Entity */
char cpn[32]; /* remember cpn */
char oad[32]; /* remember oad */
@@ -392,14 +532,10 @@ typedef struct {
#define EICON_LOCK_TX 0
#define EICON_LOCK_RX 1
-typedef struct {
- int dummy;
-} eicon_mca_card;
-
typedef union {
eicon_isa_card isa;
eicon_pci_card pci;
- eicon_mca_card mca;
+ eicon_isa_card mca;
} eicon_hwif;
typedef struct {
@@ -465,6 +601,9 @@ typedef struct eicon_card {
char *status_buf_end;
isdn_if interface; /* Interface to upper layer */
char regname[35]; /* Name used for request_region */
+#ifdef CONFIG_MCA
+ int mca_slot; /* # of cards MCA slot */
+#endif
} eicon_card;
/* -----------------------------------------------------------**
@@ -521,6 +660,13 @@ extern void eicon_io_transmit(eicon_card *card);
extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs);
extern void eicon_io_rcv_dispatch(eicon_card *ccard);
extern void eicon_io_ack_dispatch(eicon_card *ccard);
+extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq);
+#ifdef CONFIG_MCA
+extern int eicon_mca_find_card(int, int, int, char *);
+extern int eicon_mca_probe(int, int, int, int, char *);
+extern int eicon_info(char *, int , void *);
+#endif /* CONFIG_MCA */
+
extern ulong DebugVar;
#endif /* __KERNEL__ */
diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h
index 94a4595c8..9ffbd9bdb 100644
--- a/drivers/isdn/eicon/eicon_dsp.h
+++ b/drivers/isdn/eicon/eicon_dsp.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_dsp.h,v 1.2 1999/03/29 11:19:42 armin Exp $
+/* $Id: eicon_dsp.h,v 1.4 1999/07/25 15:12:02 armin Exp $
*
* ISDN lowlevel-module for Eicon.Diehl active cards.
* DSP definitions
@@ -21,6 +21,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_dsp.h,v $
+ * Revision 1.4 1999/07/25 15:12:02 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
+ * Revision 1.3 1999/07/11 17:16:24 armin
+ * Bugfixes in queue handling.
+ * Added DSP-DTMF decoder functions.
+ * Reorganized ack_handler.
+ *
* Revision 1.2 1999/03/29 11:19:42 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
@@ -31,7 +40,7 @@
*
*/
-#ifndef DSP_H
+#ifndef DSP_H
#define DSP_H
#define DSP_UDATA_REQUEST_RECONFIGURE 0
@@ -264,6 +273,10 @@ parameters:
<word> tone duration (ms)
<word> gap duration (ms)
*/
+typedef struct enable_dtmf_s {
+ __u16 tone;
+ __u16 gap;
+} enable_dtmf_s;
#define DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER 18
/*
@@ -300,5 +313,107 @@ returns:
- none -
*/
+/* ============= FAX ================ */
+
+#define EICON_FAXID_LEN 20
+
+typedef struct eicon_t30_s {
+ __u8 code;
+ __u8 rate;
+ __u8 resolution;
+ __u8 format;
+ __u8 pages_low;
+ __u8 pages_high;
+ __u8 atf;
+ __u8 control_bits_low;
+ __u8 control_bits_high;
+ __u8 feature_bits_low;
+ __u8 feature_bits_high;
+ __u8 universal_5;
+ __u8 universal_6;
+ __u8 universal_7;
+ __u8 station_id_len;
+ __u8 head_line_len;
+ __u8 station_id[EICON_FAXID_LEN];
+/* __u8 head_line[]; */
+} eicon_t30_s;
+
+ /* EDATA transmit messages */
+#define EDATA_T30_DIS 0x01
+#define EDATA_T30_FTT 0x02
+#define EDATA_T30_MCF 0x03
+
+ /* EDATA receive messages */
+#define EDATA_T30_DCS 0x81
+#define EDATA_T30_TRAIN_OK 0x82
+#define EDATA_T30_EOP 0x83
+#define EDATA_T30_MPS 0x84
+#define EDATA_T30_EOM 0x85
+#define EDATA_T30_DTC 0x86
+
+#define T30_FORMAT_SFF 0
+#define T30_FORMAT_ASCII 1
+#define T30_FORMAT_COUNT 2
+
+#define T30_CONTROL_BIT_DISABLE_FINE 0x0001
+#define T30_CONTROL_BIT_ENABLE_ECM 0x0002
+#define T30_CONTROL_BIT_ECM_64_BYTES 0x0004
+#define T30_CONTROL_BIT_ENABLE_2D_CODING 0x0008
+#define T30_CONTROL_BIT_ENABLE_T6_CODING 0x0010
+#define T30_CONTROL_BIT_ENABLE_UNCOMPR 0x0020
+#define T30_CONTROL_BIT_ACCEPT_POLLING 0x0040
+#define T30_CONTROL_BIT_REQUEST_POLLING 0x0080
+#define T30_CONTROL_BIT_MORE_DOCUMENTS 0x0100
+
+#define T30_CONTROL_BIT_ALL_FEATURES\
+ (T30_CONTROL_BIT_ENABLE_ECM | T30_CONTROL_BIT_ENABLE_2D_CODING |\
+ T30_CONTROL_BIT_ENABLE_T6_CODING | T30_CONTROL_BIT_ENABLE_UNCOMPR)
+
+#define T30_FEATURE_BIT_FINE 0x0001
+#define T30_FEATURE_BIT_ECM 0x0002
+#define T30_FEATURE_BIT_ECM_64_BYTES 0x0004
+#define T30_FEATURE_BIT_2D_CODING 0x0008
+#define T30_FEATURE_BIT_T6_CODING 0x0010
+#define T30_FEATURE_BIT_UNCOMPR_ENABLED 0x0020
+#define T30_FEATURE_BIT_POLLING 0x0040
+
+#define FAX_OBJECT_DOCU 1
+#define FAX_OBJECT_PAGE 2
+#define FAX_OBJECT_LINE 3
+
+#define T4_EOL 0x800
+#define T4_EOL_BITSIZE 12
+#define T4_EOL_DWORD (T4_EOL << (32 - T4_EOL_BITSIZE))
+#define T4_EOL_MASK_DWORD ((__u32) -1 << (32 - T4_EOL_BITSIZE))
+
+#define SFF_LEN_FLD_SIZE 3
+
+#define _DLE_ 0x10
+#define _ETX_ 0x03
+
+typedef struct eicon_sff_dochead {
+ __u32 id __attribute__ ((packed));
+ __u8 version __attribute__ ((packed));
+ __u8 reserved1 __attribute__ ((packed));
+ __u16 userinfo __attribute__ ((packed));
+ __u16 pagecount __attribute__ ((packed));
+ __u16 off1pagehead __attribute__ ((packed));
+ __u32 offnpagehead __attribute__ ((packed));
+ __u32 offdocend __attribute__ ((packed));
+} eicon_sff_dochead;
+
+typedef struct eicon_sff_pagehead {
+ __u8 pageheadid __attribute__ ((packed));
+ __u8 pageheadlen __attribute__ ((packed));
+ __u8 resvert __attribute__ ((packed));
+ __u8 reshoriz __attribute__ ((packed));
+ __u8 coding __attribute__ ((packed));
+ __u8 reserved2 __attribute__ ((packed));
+ __u16 linelength __attribute__ ((packed));
+ __u16 pagelength __attribute__ ((packed));
+ __u32 offprevpage __attribute__ ((packed));
+ __u32 offnextpage __attribute__ ((packed));
+} eicon_sff_pagehead;
+
#endif /* DSP_H */
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c
index a28f316c1..af9c30483 100644
--- a/drivers/isdn/eicon/eicon_idi.c
+++ b/drivers/isdn/eicon/eicon_idi.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.9 1999/03/29 11:19:42 armin Exp $
+/* $Id: eicon_idi.c,v 1.15 1999/08/28 21:32:50 armin Exp $
*
* ISDN lowlevel-module for Eicon.Diehl active cards.
* IDI interface
@@ -21,6 +21,33 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.c,v $
+ * Revision 1.15 1999/08/28 21:32:50 armin
+ * Prepared for fax related functions.
+ * Now compilable without errors/warnings.
+ *
+ * Revision 1.14 1999/08/28 20:24:40 armin
+ * Corrected octet 3/3a in CPN/OAD information element.
+ * Thanks to John Simpson <xfl23@dial.pipex.com>
+ *
+ * Revision 1.13 1999/08/22 20:26:44 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.12 1999/08/18 20:16:59 armin
+ * Added XLOG function for all cards.
+ * Bugfix of alloc_skb NULL pointer.
+ *
+ * Revision 1.11 1999/07/25 15:12:03 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
+ * Revision 1.10 1999/07/11 17:16:24 armin
+ * Bugfixes in queue handling.
+ * Added DSP-DTMF decoder functions.
+ * Reorganized ack_handler.
+ *
* Revision 1.9 1999/03/29 11:19:42 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
@@ -61,6 +88,7 @@
*
*/
+#include <linux/config.h>
#define __NO_VERSION__
#include "eicon.h"
#include "eicon_idi.h"
@@ -68,7 +96,7 @@
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.9 $";
+char *eicon_idi_revision = "$Revision: 1.15 $";
eicon_manifbuf *manbuf;
@@ -86,11 +114,15 @@ static char HLC_faxg3[2] = { 0x91, 0x84 };
int eicon_idi_manage_assign(eicon_card *card);
int eicon_idi_manage_remove(eicon_card *card);
+int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer);
int
idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
{
int l = 0;
+ int tmp;
+
+ tmp = 0;
if (!signet) {
/* Signal Layer */
reqbuf->XBuffer.P[l++] = CAI;
@@ -133,10 +165,25 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
case ISDN_PROTO_L2_MODEM:
reqbuf->XBuffer.P[l++] = 2;
break;
+ case ISDN_PROTO_L2_FAX:
+ if (chan->fsm_state == EICON_STATE_IWAIT)
+ reqbuf->XBuffer.P[l++] = 3; /* autoconnect on incoming */
+ else
+ reqbuf->XBuffer.P[l++] = 2;
+ break;
default:
reqbuf->XBuffer.P[l++] = 1;
}
switch(chan->l3prot) {
+ case ISDN_PROTO_L3_FAX:
+#ifdef CONFIG_ISDN_TTY_FAX
+ reqbuf->XBuffer.P[l++] = 6;
+ reqbuf->XBuffer.P[l++] = NLC;
+ tmp = idi_fill_in_T30(chan, &reqbuf->XBuffer.P[l+1]);
+ reqbuf->XBuffer.P[l++] = tmp;
+ l += tmp;
+ break;
+#endif
case ISDN_PROTO_L3_TRANS:
default:
reqbuf->XBuffer.P[l++] = 4;
@@ -210,6 +257,20 @@ idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan)
reqbuf->XBuffer.P[6] = 128;
reqbuf->XBuffer.P[7] = 0;
break;
+ case ISDN_PROTO_L2_FAX:
+ reqbuf->XBuffer.P[2] = 0x10;
+ reqbuf->XBuffer.P[3] = 0;
+ reqbuf->XBuffer.P[4] = 0;
+ reqbuf->XBuffer.P[5] = 0;
+ reqbuf->XBuffer.P[6] = 128;
+ reqbuf->XBuffer.P[7] = 0;
+ break;
+ case ISDN_PROTO_L2_TRANS:
+ switch(chan->l3prot) {
+ case ISDN_PROTO_L3_TRANSDSP:
+ reqbuf->XBuffer.P[2] = 22; /* DTMF, audio events on */
+ }
+ break;
}
reqbuf->XBuffer.P[8] = 0;
reqbuf->XBuffer.length = l;
@@ -232,7 +293,11 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
if ((!skb) || (!skb2)) {
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No);
+ printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No);
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
return -ENOMEM;
}
@@ -241,7 +306,7 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
if (DebugVar & 8)
- printk(KERN_DEBUG "idi_req: Ch%d: 0x%02x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
+ printk(KERN_DEBUG "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
if (layer) cmd |= 0x700;
switch(cmd) {
case ASSIGN:
@@ -282,6 +347,8 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
default:
if (DebugVar & 1)
printk(KERN_ERR "idi_req: Ch%d: Unknown request\n", chan->No);
+ dev_kfree_skb(skb);
+ dev_kfree_skb(skb2);
return(-1);
}
@@ -358,6 +425,9 @@ idi_hangup(eicon_card *card, eicon_chan *chan)
chan->fsm_state = EICON_STATE_NULL;
if (DebugVar & 8)
printk(KERN_DEBUG"idi_req: Ch%d: Hangup\n", chan->No);
+#ifdef CONFIG_ISDN_TTY_FAX
+ chan->fax = 0;
+#endif
return(0);
}
@@ -389,7 +459,11 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
if ((!skb) || (!skb2)) {
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No);
+ printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No);
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
return -ENOMEM;
}
@@ -403,14 +477,14 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
reqbuf->XBuffer.P[l++] = CPN;
reqbuf->XBuffer.P[l++] = strlen(phone) + 1;
- reqbuf->XBuffer.P[l++] = 0xc1;
+ reqbuf->XBuffer.P[l++] = 0x81;
for(i=0; i<strlen(phone);i++)
reqbuf->XBuffer.P[l++] = phone[i];
reqbuf->XBuffer.P[l++] = OAD;
reqbuf->XBuffer.P[l++] = strlen(eazmsn) + 2;
reqbuf->XBuffer.P[l++] = 0x01;
- reqbuf->XBuffer.P[l++] = 0x81;
+ reqbuf->XBuffer.P[l++] = 0x80;
for(i=0; i<strlen(eazmsn);i++)
reqbuf->XBuffer.P[l++] = eazmsn[i];
@@ -472,6 +546,20 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
reqbuf->XBuffer.P[l-2] = 128;
reqbuf->XBuffer.P[l-1] = 0;
break;
+ case ISDN_PROTO_L2_FAX:
+ reqbuf->XBuffer.P[l-6] = 0x10;
+ reqbuf->XBuffer.P[l-5] = 0;
+ reqbuf->XBuffer.P[l-4] = 0;
+ reqbuf->XBuffer.P[l-3] = 0;
+ reqbuf->XBuffer.P[l-2] = 128;
+ reqbuf->XBuffer.P[l-1] = 0;
+ break;
+ case ISDN_PROTO_L2_TRANS:
+ switch(chan->l3prot) {
+ case ISDN_PROTO_L3_TRANSDSP:
+ reqbuf->XBuffer.P[l-6] = 22; /* DTMF, audio events on */
+ }
+ break;
}
reqbuf->XBuffer.P[l++] = 0; /* end */
@@ -813,6 +901,195 @@ idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned ch
}
}
+/********************* FAX stuff ***************************/
+
+#ifdef CONFIG_ISDN_TTY_FAX
+
+int
+idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer)
+{
+
+ /* TODO , code follows */
+
+ return(0);
+}
+
+/* send fax struct */
+int
+idi_send_edata(eicon_card *card, eicon_chan *chan)
+{
+
+ /* TODO , code follows */
+
+ return (0);
+}
+
+void
+idi_parse_edata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_fax_cmd(eicon_card *card, eicon_chan *chan)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_edata_rcveop(eicon_card *card, eicon_chan *chan)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_reset_fax_stat(eicon_chan *chan)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+fax_put_rcv(eicon_card *ccard, eicon_chan *chan, u_char *Data, int len)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_faxdata_rcv(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
+{
+
+ /* TODO , code follows */
+
+}
+
+int
+idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf)
+{
+
+ /* TODO , code follows */
+
+ return(0);
+}
+
+int
+idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
+{
+
+ /* TODO , code follows */
+
+ return(0);
+}
+
+void
+idi_fax_hangup(eicon_card *ccard, eicon_chan *chan)
+{
+
+ /* TODO , code follows */
+
+}
+
+#endif /******** FAX ********/
+
+int
+idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int len)
+{
+ struct sk_buff *skb;
+ struct sk_buff *skb2;
+ eicon_REQ *reqbuf;
+ eicon_chan_ptr *chan2;
+
+ if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
+ if (DebugVar & 1)
+ printk(KERN_DEBUG"idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state);
+ return -ENODEV;
+ }
+ if (DebugVar & 8)
+ printk(KERN_DEBUG"idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No,
+ UReq, buffer[0], buffer[1], buffer[2], buffer[3]);
+
+ skb = alloc_skb(sizeof(eicon_REQ) + len + 1, GFP_ATOMIC);
+ skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+ if ((!skb) || (!skb2)) {
+ if (DebugVar & 1)
+ printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No);
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
+ return -ENOMEM;
+ }
+
+ chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+ chan2->ptr = chan;
+
+ reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ));
+
+ reqbuf->Req = IDI_N_UDATA;
+ reqbuf->ReqCh = 0;
+ reqbuf->ReqId = 1;
+
+ reqbuf->XBuffer.length = len + 1;
+ reqbuf->XBuffer.P[0] = UReq;
+ memcpy(&reqbuf->XBuffer.P[1], buffer, len);
+ reqbuf->Reference = 1; /* Net Entity */
+
+ skb_queue_tail(&chan->e.X, skb);
+ skb_queue_tail(&card->sndq, skb2);
+ eicon_schedule_tx(card);
+ return (0);
+}
+
+void
+idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value)
+{
+ u_char buf[6];
+ struct enable_dtmf_s *dtmf_buf = (struct enable_dtmf_s *)buf;
+
+ memset(buf, 0, 6);
+ switch(cmd) {
+ case ISDN_AUDIO_SETDD:
+ if (value[0]) {
+ dtmf_buf->tone = (__u16) (value[1] * 5);
+ dtmf_buf->gap = (__u16) (value[1] * 5);
+ idi_send_udata(ccard, chan,
+ DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER,
+ buf, 4);
+ } else {
+ idi_send_udata(ccard, chan,
+ DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER,
+ buf, 0);
+ }
+ break;
+ }
+}
+
void
idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
{
@@ -822,6 +1099,9 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int
{"", "V.21", "V.23", "V.22", "V.22bis", "V.32bis", "V.34",
"V.8", "Bell 212A", "Bell 103", "V.29 Leased", "V.33 Leased", "V.90",
"V.21 CH2", "V.27ter", "V.29", "V.33", "V.17"};
+ static u_char dtmf_code[] = {
+ '1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D'
+ };
switch (buffer[0]) {
case DSP_UDATA_INDICATION_SYNC:
@@ -863,6 +1143,17 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int
if (DebugVar & 8)
printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
break;
+ case DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED:
+ if (DebugVar & 8)
+ printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No,
+ dtmf_code[buffer[1]]);
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_AUDIO;
+ cmd.parm.num[0] = ISDN_AUDIO_DTMF;
+ cmd.parm.num[1] = dtmf_code[buffer[1]];
+ cmd.arg = chan->No;
+ ccard->interface.statcallb(&cmd);
+ break;
default:
if (DebugVar & 8)
printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
@@ -887,7 +1178,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
if ((DebugVar & 128) ||
((DebugVar & 16) && (ind->Ind != 8))) {
- printk(KERN_DEBUG "idi_hdl: Ch%d: Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
+ printk(KERN_DEBUG "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
}
@@ -921,6 +1212,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.command = ISDN_STAT_DHUP;
ccard->interface.statcallb(&cmd);
eicon_idi_listen_req(ccard, chan);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (!chan->e.B2Id)
+ chan->fax = 0;
+#endif
break;
case INDICATE_IND:
if (DebugVar & 8)
@@ -994,9 +1289,17 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.command = ISDN_STAT_DCONN;
cmd.arg = chan->No;
ccard->interface.statcallb(&cmd);
- idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+ if (chan->l2prot != ISDN_PROTO_L2_FAX) {
+ idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+ }
+#ifdef CONFIG_ISDN_TTY_FAX
+ else {
+ if (chan->fax)
+ chan->fax->phase = ISDN_FAX_PHASE_A;
+ }
+#endif
} else
- idi_hangup(ccard, chan);
+ idi_hangup(ccard, chan);
break;
case CALL_CON:
if (DebugVar & 8)
@@ -1009,6 +1312,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
ccard->interface.statcallb(&cmd);
idi_do_req(ccard, chan, ASSIGN, 1);
idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ if (chan->fax)
+ chan->fax->phase = ISDN_FAX_PHASE_A;
+ }
+#endif
} else
idi_hangup(ccard, chan);
break;
@@ -1038,6 +1347,27 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
chan->fsm_state = EICON_STATE_WMCONN;
break;
}
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+#ifdef CONFIG_ISDN_TTY_FAX
+ chan->fsm_state = EICON_STATE_ACTIVE;
+ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+ if (chan->fax) {
+ if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+ idi_fax_send_header(ccard, chan, 2);
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_DCS;
+ ccard->interface.statcallb(&cmd);
+ }
+ }
+ else {
+ if (DebugVar & 1)
+ printk(KERN_DEBUG "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
+ }
+#endif
+ break;
+ }
chan->fsm_state = EICON_STATE_ACTIVE;
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BCONN;
@@ -1048,6 +1378,9 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
if (DebugVar & 16)
printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect\n", chan->No);
if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1);
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ break;
+ }
if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
chan->fsm_state = EICON_STATE_WMCONN;
break;
@@ -1065,19 +1398,35 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1);
idi_do_req(ccard, chan, REMOVE, 1);
}
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+ idi_fax_hangup(ccard, chan);
+ }
+#endif
chan->queued = 0;
chan->waitq = 0;
chan->waitpq = 0;
+ idi_do_req(ccard, chan, HANGUP, 0);
if (chan->fsm_state == EICON_STATE_ACTIVE) {
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BHUP;
cmd.arg = chan->No;
ccard->interface.statcallb(&cmd);
}
+#ifdef CONFIG_ISDN_TTY_FAX
+ chan->fax = 0;
+#endif
break;
case IDI_N_DISC_ACK:
if (DebugVar & 16)
printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+ idi_fax_hangup(ccard, chan);
+ }
+#endif
break;
case IDI_N_DATA_ACK:
if (DebugVar & 16)
@@ -1087,12 +1436,23 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
skb_pull(skb, sizeof(eicon_IND) - 1);
if (DebugVar & 128)
printk(KERN_DEBUG"idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
- ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
- free_buff = 0;
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+#ifdef CONFIG_ISDN_TTY_FAX
+ idi_faxdata_rcv(ccard, chan, skb);
+#endif
+ } else {
+ ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
+ free_buff = 0;
+ }
break;
case IDI_N_UDATA:
idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
break;
+#ifdef CONFIG_ISDN_TTY_FAX
+ case IDI_N_EDATA:
+ idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+ break;
+#endif
default:
if (DebugVar & 8)
printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
@@ -1105,90 +1465,138 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
if (free_buff) dev_kfree_skb(skb);
}
-void
-idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
+int
+idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
{
- int j;
- eicon_RC *ack = (eicon_RC *)skb->data;
- eicon_chan *chan;
isdn_ctrl cmd;
- if ((ack->Rc != ASSIGN_OK) && (ack->Rc != OK)) {
- if ((chan = ccard->IdTable[ack->RcId]) != NULL) {
- chan->e.busy = 0;
- if (DebugVar & 24)
- printk(KERN_ERR "eicon_ack: Ch%d: Not OK: Rc=%d Id=%d Ch=%d\n", chan->No,
- ack->Rc, ack->RcId, ack->RcCh);
- if (chan->No == ccard->nchannels) { /* Management */
- chan->fsm_state = 2;
- } else { /* any other channel */
- /* card reports error: we hangup */
- idi_hangup(ccard, chan);
- cmd.driver = ccard->myid;
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = chan->No;
- ccard->interface.statcallb(&cmd);
- }
+ if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
+ /* I dont know why this happens, just ignoring this RC */
+ if (DebugVar & 16)
+ printk(KERN_DEBUG "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No,
+ ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
+ return 1;
+ }
+
+ /* Management Interface */
+ if (chan->No == ccard->nchannels) {
+ /* Managementinterface: changing state */
+ if (chan->e.Req == 0x04)
+ chan->fsm_state = 1;
+ }
+
+ /* Remove an Id */
+ if (chan->e.Req == REMOVE) {
+ if (ack->Reference != chan->e.ref) {
+ if (DebugVar & 16)
+ printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
+ ack->Reference, chan->e.ref);
+ return 0;
}
- }
- else {
- if ((chan = ccard->IdTable[ack->RcId]) != NULL) {
- if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No,
- ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
- } else {
- if (chan->No == ccard->nchannels) { /* Management */
- if (chan->e.Req == 0x04) chan->fsm_state = 1;
- }
- if (chan->e.ReqCh) {
- switch(chan->e.Req & 0x0f) {
- case IDI_N_MDATA:
- case IDI_N_DATA:
- chan->queued -= chan->waitq;
- if (chan->queued < 0) chan->queued = 0;
- if ((chan->e.Req & 0x0f) == IDI_N_DATA) {
+ ccard->IdTable[ack->RcId] = NULL;
+ if (DebugVar & 16)
+ printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
+ ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
+ if (!chan->e.ReqCh)
+ chan->e.D3Id = 0;
+ else
+ chan->e.B2Id = 0;
+ return 1;
+ }
+
+ /* Signal layer */
+ if (!chan->e.ReqCh) {
+ if (DebugVar & 16)
+ printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+ ack->RcId, ack->RcCh, ack->Reference);
+ } else {
+ /* Network layer */
+ switch(chan->e.Req & 0x0f) {
+ case IDI_N_MDATA:
+ case IDI_N_DATA:
+ if ((chan->e.Req & 0x0f) == IDI_N_DATA) {
+ if (chan->queued) {
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_BSENT;
+ cmd.arg = chan->No;
+ cmd.parm.length = chan->waitpq;
+ ccard->interface.statcallb(&cmd);
+ }
+ chan->waitpq = 0;
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ if (((chan->queued - chan->waitq) < 1) &&
+ (chan->fax2.Eop)) {
+ chan->fax2.Eop = 0;
+ if (chan->fax) {
cmd.driver = ccard->myid;
- cmd.command = ISDN_STAT_BSENT;
+ cmd.command = ISDN_STAT_FAXIND;
cmd.arg = chan->No;
- cmd.parm.length = chan->waitpq;
- chan->waitpq = 0;
+ chan->fax->r_code = ISDN_TTY_FAX_SENT;
ccard->interface.statcallb(&cmd);
}
- break;
- default:
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No,
- ack->RcId, ack->RcCh, ack->Reference);
+ else {
+ if (DebugVar & 1)
+ printk(KERN_DEBUG "idi_ack: Sent with NULL fax struct, ERROR\n");
+ }
+ }
}
- }
- else {
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No,
- ack->RcId, ack->RcCh, ack->Reference);
+#endif
}
+ chan->queued -= chan->waitq;
+ if (chan->queued < 0) chan->queued = 0;
+ break;
+ default:
+ if (DebugVar & 16)
+ printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+ ack->RcId, ack->RcCh, ack->Reference);
+ }
+ }
+ return 1;
+}
- if (chan->e.Req == REMOVE) {
- if (ack->Reference == chan->e.ref) {
- ccard->IdTable[ack->RcId] = NULL;
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%d Ch=%d (%s)\n", chan->No,
- ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
- if (!chan->e.ReqCh)
- chan->e.D3Id = 0;
- else
- chan->e.B2Id = 0;
- }
- else {
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
- ack->Reference, chan->e.ref);
- }
- }
- chan->e.busy = 0;
+void
+idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
+{
+ int j;
+ eicon_RC *ack = (eicon_RC *)skb->data;
+ eicon_chan *chan;
+ isdn_ctrl cmd;
+ int dCh = -1;
+
+ if ((chan = ccard->IdTable[ack->RcId]) != NULL)
+ dCh = chan->No;
+
+
+ switch (ack->Rc) {
+ case OK_FC:
+ case N_FLOW_CONTROL:
+ case ASSIGN_RC:
+ if (DebugVar & 1)
+ printk(KERN_ERR "idi_ack: Ch%d: unhandled RC 0x%x\n",
+ dCh, ack->Rc);
+ break;
+ case READY_INT:
+ case TIMER_INT:
+ /* we do nothing here */
+ break;
+
+ case OK:
+ if (!chan) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "idi_ack: Ch%d: OK on chan without Id\n", dCh);
+ break;
+ }
+ if (!idi_handle_ack_ok(ccard, chan, ack))
+ chan = NULL;
+ break;
+
+ case ASSIGN_OK:
+ if (chan) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
+ chan->No, chan->e.D3Id, chan->e.B2Id);
}
- }
- else {
for(j = 0; j < ccard->nchannels + 1; j++) {
if (ccard->bch[j].e.ref == ack->Reference) {
if (!ccard->bch[j].e.ReqCh)
@@ -1199,7 +1607,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
ccard->bch[j].e.busy = 0;
ccard->bch[j].e.ref = 0;
if (DebugVar & 16)
- printk(KERN_DEBUG"idi_ack: Ch%d: Id %d assigned (%s)\n", j,
+ printk(KERN_DEBUG"idi_ack: Ch%d: Id %x assigned (%s)\n", j,
ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
break;
}
@@ -1209,14 +1617,39 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
printk(KERN_DEBUG"idi_ack: Ch??: ref %d not found for Id %d\n",
ack->Reference, ack->RcId);
}
- }
+ break;
+
+ case OUT_OF_RESOURCES:
+ case UNKNOWN_COMMAND:
+ case WRONG_COMMAND:
+ case WRONG_ID:
+ case WRONG_CH:
+ case UNKNOWN_IE:
+ case WRONG_IE:
+ default:
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_ack: Ch%d: Not OK !!: Rc=%d Id=%x Ch=%d\n", dCh,
+ ack->Rc, ack->RcId, ack->RcCh);
+ if (dCh == ccard->nchannels) { /* Management */
+ chan->fsm_state = 2;
+ } else if (dCh >= 0) {
+ /* any other channel */
+ /* card reports error: we hangup */
+ idi_hangup(ccard, chan);
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = chan->No;
+ ccard->interface.statcallb(&cmd);
+ }
}
- dev_kfree_skb(skb);
- eicon_schedule_tx(ccard);
+ if (chan)
+ chan->e.busy = 0;
+ dev_kfree_skb(skb);
+ eicon_schedule_tx(ccard);
}
int
-idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
+idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que)
{
struct sk_buff *xmit_skb;
struct sk_buff *skb2;
@@ -1240,6 +1673,7 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
return 0;
if (DebugVar & 128)
printk(KERN_DEBUG"idi_snd: Ch%d: %d bytes\n", chan->No, len);
+
save_flags(flags);
cli();
while(offset < len) {
@@ -1249,10 +1683,14 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
xmit_skb = alloc_skb(plen + sizeof(eicon_REQ), GFP_ATOMIC);
skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
- if ((!skb) || (!skb2)) {
+ if ((!xmit_skb) || (!skb2)) {
restore_flags(flags);
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No);
+ printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
+ if (xmit_skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
return -ENOMEM;
}
@@ -1278,7 +1716,8 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
offset += plen;
}
- chan->queued += len;
+ if (que)
+ chan->queued += len;
restore_flags(flags);
eicon_schedule_tx(card);
dev_kfree_skb(skb);
@@ -1286,7 +1725,6 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
}
-
int
eicon_idi_manage_assign(eicon_card *card)
{
@@ -1303,7 +1741,11 @@ eicon_idi_manage_assign(eicon_card *card)
if ((!skb) || (!skb2)) {
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: alloc_skb failed\n");
+ printk(KERN_WARNING "idi_err: alloc_skb failed in manage_assign()\n");
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
return -ENOMEM;
}
@@ -1342,7 +1784,11 @@ eicon_idi_manage_remove(eicon_card *card)
if ((!skb) || (!skb2)) {
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: alloc_skb failed\n");
+ printk(KERN_WARNING "idi_err: alloc_skb failed in manage_remove()\n");
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
return -ENOMEM;
}
@@ -1379,7 +1825,8 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
chan = &(card->bch[card->nchannels]);
- if (chan->e.D3Id) return -EBUSY;
+ if (chan->e.D3Id)
+ return -EBUSY;
chan->e.D3Id = 1;
while((skb2 = skb_dequeue(&chan->e.X)))
dev_kfree_skb(skb2);
@@ -1409,6 +1856,7 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
return -ENOMEM;
}
if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) {
+ kfree(manbuf);
chan->e.D3Id = 0;
return -EFAULT;
}
@@ -1418,7 +1866,11 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
if ((!skb) || (!skb2)) {
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err_manif: alloc_skb failed\n");
+ printk(KERN_WARNING "idi_err_manif: alloc_skb failed in manage()\n");
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
kfree(manbuf);
chan->e.D3Id = 0;
return -ENOMEM;
@@ -1464,11 +1916,13 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
}
if ((ret = eicon_idi_manage_remove(card))) {
+ kfree(manbuf);
chan->e.D3Id = 0;
return(ret);
}
if (copy_to_user(mb, manbuf, sizeof(eicon_manifbuf))) {
+ kfree(manbuf);
chan->e.D3Id = 0;
return -EFAULT;
}
diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h
index a0605cdef..e09c1954d 100644
--- a/drivers/isdn/eicon/eicon_idi.h
+++ b/drivers/isdn/eicon/eicon_idi.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.h,v 1.4 1999/03/29 11:19:44 armin Exp $
+/* $Id: eicon_idi.h,v 1.7 1999/08/22 20:26:46 calle Exp $
*
* ISDN lowlevel-module for the Eicon.Diehl active cards.
* IDI-Interface
@@ -21,6 +21,21 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.h,v $
+ * Revision 1.7 1999/08/22 20:26:46 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.6 1999/07/25 15:12:04 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
+ * Revision 1.5 1999/07/11 17:16:26 armin
+ * Bugfixes in queue handling.
+ * Added DSP-DTMF decoder functions.
+ * Reorganized ack_handler.
+ *
* Revision 1.4 1999/03/29 11:19:44 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
@@ -45,6 +60,7 @@
#ifndef IDI_H
#define IDI_H
+#include <linux/config.h>
#define ASSIGN 0x01
#define REMOVE 0xff
@@ -232,6 +248,12 @@ typedef struct {
__u8 B[1]; /* buffer space for Req,Ind and Rc */
} eicon_pr_ram;
+typedef struct {
+ __u8 *Data;
+ unsigned int Size;
+ unsigned int Len;
+ __u8 *Next;
+} eicon_OBJBUFFER;
extern int idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer);
extern int idi_hangup(eicon_card *card, eicon_chan *chan);
@@ -243,6 +265,11 @@ extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb);
extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb);
extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb);
-extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb);
+extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que);
+extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value);
+#ifdef CONFIG_ISDN_TTY_FAX
+extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan);
+extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb);
+#endif
#endif
diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c
index 1c69d37cd..60b5b4818 100644
--- a/drivers/isdn/eicon/eicon_io.c
+++ b/drivers/isdn/eicon/eicon_io.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_io.c,v 1.1 1999/03/29 11:19:45 armin Exp $
+/* $Id: eicon_io.c,v 1.4 1999/08/22 20:26:47 calle Exp $
*
* ISDN low-level module for Eicon.Diehl active ISDN-Cards.
* Code for communicating with hardware.
@@ -24,6 +24,20 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_io.c,v $
+ * Revision 1.4 1999/08/22 20:26:47 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.3 1999/08/18 20:17:01 armin
+ * Added XLOG function for all cards.
+ * Bugfix of alloc_skb NULL pointer.
+ *
+ * Revision 1.2 1999/07/25 15:12:05 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
* Revision 1.1 1999/03/29 11:19:45 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
@@ -32,6 +46,7 @@
*/
+#include <linux/config.h>
#include "eicon.h"
void
@@ -56,8 +71,8 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
/* doesn't matter if this happens */
break;
default:
- printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%d\n", ind->Ind, ind->IndId);
- printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n",
+ printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId);
+ printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
}
}
@@ -84,12 +99,18 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
if (DebugVar & 1)
printk(KERN_ERR "eicon: buffer incomplete, but 0 in queue\n");
dev_kfree_skb(skb);
- dev_kfree_skb(skb2);
continue;
}
ind2 = (eicon_IND *)skb2->data;
skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length),
GFP_ATOMIC);
+ if (!skb_new) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_io: skb_alloc failed in rcv_dispatch()\n");
+ dev_kfree_skb(skb);
+ dev_kfree_skb(skb2);
+ continue;
+ }
ind_new = (eicon_IND *)skb_put(skb_new,
((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length));
ind_new->Ind = ind2->Ind;
@@ -272,6 +293,92 @@ void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) {
}
/*
+ * XLOG
+ */
+int
+eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq)
+{
+ int timeout, i;
+ int divas_shared_offset = 0;
+ int len = 0;
+ int stype = 0;
+ __u32 time = 0;
+ mi_pc_maint_t *pcm = &xlogreq->pcm;
+ eicon_pci_card *pci_card = &card->hwif.pci;
+ eicon_isa_card *isa_card = &card->hwif.isa;
+ eicon_pr_ram *prram = 0;
+ char *ram;
+
+ switch(card->type) {
+ case EICON_CTYPE_MAESTRAP:
+ ram = (char *)pci_card->PCIram;
+ prram = (eicon_pr_ram *)ram;
+ divas_shared_offset = DIVAS_SHARED_OFFSET;
+ len = sizeof(mi_pc_maint_t);
+ break;
+ case EICON_CTYPE_MAESTRA:
+ prram = 0;
+ divas_shared_offset = 0;
+ len = sizeof(mi_pc_maint_t);
+ break;
+ case EICON_CTYPE_S:
+ case EICON_CTYPE_SX:
+ case EICON_CTYPE_SCOM:
+ case EICON_CTYPE_QUADRO:
+ case EICON_CTYPE_S2M:
+ prram = (eicon_pr_ram *)isa_card->shmem;
+ divas_shared_offset = 0xfb80;
+ len = sizeof(mi_pc_maint_t) - 78;
+ stype = 1;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t));
+
+ xlogreq->pcm.rc = 0;
+ xlogreq->pcm.req = 1; /* DO_LOG */
+
+ ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset;
+
+ ram_outb(card, ram+1, pcm->rc);
+ ram_outb(card, ram+0, pcm->req);
+
+ timeout = jiffies + 50;
+ while (timeout > jiffies) {
+ pcm->rc = ram_inb(card, ram+1);
+ pcm->req = ram_inb(card, ram+0);
+ if (!pcm->req) break;
+ SLEEP(10);
+ }
+
+ if (pcm->req) {
+ return XLOG_ERR_TIMEOUT;
+ }
+
+ if (pcm->rc != OK) {
+ return XLOG_ERR_DONE;
+ }
+
+ ram_copyfromcard(card, pcm, ram, len);
+
+ if (stype) {
+ for (i=0; i<8; i++)
+ ((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i];
+ time = (__u32)pcm->data.w[2] * 3600 * 1000 +
+ (__u32)pcm->data.w[1] * 1000 +
+ (__u32)pcm->data.b[1] * 20 +
+ (__u32)pcm->data.b[0] ;
+ pcm->data.w[1] = (__u16) (time >> 16);
+ pcm->data.w[2] = (__u16) (time & 0x0000ffff);
+ pcm->data.w[0] = 2;
+ }
+
+ return XLOG_OK;
+}
+
+/*
* Transmit-Function
*/
void
@@ -303,6 +410,7 @@ eicon_io_transmit(eicon_card *ccard) {
}
switch(ccard->type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -314,6 +422,7 @@ eicon_io_transmit(eicon_card *ccard) {
scom = 0;
prram = (eicon_pr_ram *)isa_card->shmem;
break;
+#endif
case EICON_CTYPE_MAESTRAP:
scom = 0;
ram = (char *)pci_card->PCIram;
@@ -366,9 +475,13 @@ eicon_io_transmit(eicon_card *ccard) {
chan = chan2->ptr;
if (!chan->e.busy) {
if((skb = skb_dequeue(&chan->e.X))) {
- save_flags(flags);
- cli();
- reqbuf = (eicon_REQ *)skb->data;
+ save_flags(flags);
+ cli();
+ reqbuf = (eicon_REQ *)skb->data;
+ if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) {
+ if (DebugVar & 16)
+ printk(KERN_WARNING "eicon: transmit: error Id=0 on %d (Net)\n", chan->No);
+ } else {
if (scom) {
ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length);
ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
@@ -383,7 +496,7 @@ eicon_io_transmit(eicon_card *ccard) {
ram_outb(ccard, &ReqOut->Req, reqbuf->Req);
}
- if (reqbuf->ReqId &0x1f) { /* if this is no ASSIGN */
+ if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */
if (!reqbuf->Reference) { /* Signal Layer */
if (scom)
@@ -432,14 +545,15 @@ eicon_io_transmit(eicon_card *ccard) {
ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next));
chan->e.busy = 1;
- restore_flags(flags);
if (DebugVar & 32)
- printk(KERN_DEBUG "eicon: Req=%x Id=%x Ch=%x Len=%x Ref=%d\n",
+ printk(KERN_DEBUG "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n",
reqbuf->Req,
ram_inb(ccard, &ReqOut->ReqId),
reqbuf->ReqCh, reqbuf->XBuffer.length,
chan->e.ref);
- dev_kfree_skb(skb);
+ }
+ restore_flags(flags);
+ dev_kfree_skb(skb);
}
dev_kfree_skb(skb2);
}
@@ -510,6 +624,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
isa_card = &ccard->hwif.isa;
switch(ccard->type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -523,6 +638,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
prram = (eicon_pr_ram *)isa_card->shmem;
irqprobe = &isa_card->irqprobe;
break;
+#endif
case EICON_CTYPE_MAESTRAP:
scom = 0;
ram = (char *)pci_card->PCIram;
@@ -546,6 +662,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
if (*irqprobe) {
switch(ccard->type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -563,6 +680,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
}
(*irqprobe)++;
break;
+#endif
case EICON_CTYPE_MAESTRAP:
if (readb(&ram[0x3fe])) {
writeb(0, &prram->RcOutput);
@@ -581,6 +699,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
}
switch(ccard->type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -592,6 +711,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
return;
}
break;
+#endif
case EICON_CTYPE_MAESTRAP:
if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */
if (DebugVar & 1)
@@ -623,16 +743,21 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
}
} else {
skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
- ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
- ack->Rc = tmp;
- ack->RcId = ram_inb(ccard, &com->RcId);
- ack->RcCh = ram_inb(ccard, &com->RcCh);
- ack->Reference = ccard->ref_in++;
- if (DebugVar & 64)
- printk(KERN_INFO "eicon: IRQ Rc=%d Id=%d Ch=%d Ref=%d\n",
- tmp,ack->RcId,ack->RcCh,ack->Reference);
- skb_queue_tail(&ccard->rackq, skb);
- eicon_schedule_ack(ccard);
+ if (!skb) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+ } else {
+ ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
+ ack->Rc = tmp;
+ ack->RcId = ram_inb(ccard, &com->RcId);
+ ack->RcCh = ram_inb(ccard, &com->RcCh);
+ ack->Reference = ccard->ref_in++;
+ if (DebugVar & 64)
+ printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
+ tmp,ack->RcId,ack->RcCh,ack->Reference);
+ skb_queue_tail(&ccard->rackq, skb);
+ eicon_schedule_ack(ccard);
+ }
ram_outb(ccard, &com->Req, 0);
ram_outb(ccard, &com->Rc, 0);
}
@@ -644,19 +769,24 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
eicon_IND *ind;
int len = ram_inw(ccard, &com->RBuffer.length);
skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
- ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
- ind->Ind = tmp;
- ind->IndId = ram_inb(ccard, &com->IndId);
- ind->IndCh = ram_inb(ccard, &com->IndCh);
- ind->MInd = ram_inb(ccard, &com->MInd);
- ind->MLength = ram_inw(ccard, &com->MLength);
- ind->RBuffer.length = len;
- if (DebugVar & 64)
- printk(KERN_INFO "eicon: IRQ Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n",
- tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
- ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len);
- skb_queue_tail(&ccard->rcvq, skb);
- eicon_schedule_rx(ccard);
+ if (!skb) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+ } else {
+ ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
+ ind->Ind = tmp;
+ ind->IndId = ram_inb(ccard, &com->IndId);
+ ind->IndCh = ram_inb(ccard, &com->IndCh);
+ ind->MInd = ram_inb(ccard, &com->MInd);
+ ind->MLength = ram_inw(ccard, &com->MLength);
+ ind->RBuffer.length = len;
+ if (DebugVar & 64)
+ printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+ tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
+ ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len);
+ skb_queue_tail(&ccard->rcvq, skb);
+ eicon_schedule_rx(ccard);
+ }
ram_outb(ccard, &com->Ind, 0);
}
}
@@ -673,17 +803,22 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
if((Rc=ram_inb(ccard, &RcIn->Rc))) {
skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
- ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
- ack->Rc = Rc;
- ack->RcId = ram_inb(ccard, &RcIn->RcId);
- ack->RcCh = ram_inb(ccard, &RcIn->RcCh);
- ack->Reference = ram_inw(ccard, &RcIn->Reference);
- if (DebugVar & 64)
- printk(KERN_INFO "eicon: IRQ Rc=%d Id=%d Ch=%d Ref=%d\n",
- Rc,ack->RcId,ack->RcCh,ack->Reference);
- ram_outb(ccard, &RcIn->Rc, 0);
- skb_queue_tail(&ccard->rackq, skb);
- eicon_schedule_ack(ccard);
+ if (!skb) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+ } else {
+ ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
+ ack->Rc = Rc;
+ ack->RcId = ram_inb(ccard, &RcIn->RcId);
+ ack->RcCh = ram_inb(ccard, &RcIn->RcCh);
+ ack->Reference = ram_inw(ccard, &RcIn->Reference);
+ if (DebugVar & 64)
+ printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
+ Rc,ack->RcId,ack->RcCh,ack->Reference);
+ skb_queue_tail(&ccard->rackq, skb);
+ eicon_schedule_ack(ccard);
+ }
+ ram_outb(ccard, &RcIn->Rc, 0);
}
/* get buffer address of next return code */
RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &RcIn->next)];
@@ -703,19 +838,24 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
if(Ind) {
int len = ram_inw(ccard, &IndIn->RBuffer.length);
skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
- ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
- ind->Ind = Ind;
- ind->IndId = ram_inb(ccard, &IndIn->IndId);
- ind->IndCh = ram_inb(ccard, &IndIn->IndCh);
- ind->MInd = ram_inb(ccard, &IndIn->MInd);
- ind->MLength = ram_inw(ccard, &IndIn->MLength);
- ind->RBuffer.length = len;
- if (DebugVar & 64)
- printk(KERN_INFO "eicon: IRQ Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n",
- Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
- ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len);
- skb_queue_tail(&ccard->rcvq, skb);
- eicon_schedule_rx(ccard);
+ if (!skb) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+ } else {
+ ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
+ ind->Ind = Ind;
+ ind->IndId = ram_inb(ccard, &IndIn->IndId);
+ ind->IndCh = ram_inb(ccard, &IndIn->IndCh);
+ ind->MInd = ram_inb(ccard, &IndIn->MInd);
+ ind->MLength = ram_inw(ccard, &IndIn->MLength);
+ ind->RBuffer.length = len;
+ if (DebugVar & 64)
+ printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+ Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
+ ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len);
+ skb_queue_tail(&ccard->rcvq, skb);
+ eicon_schedule_rx(ccard);
+ }
ram_outb(ccard, &IndIn->Ind, 0);
}
/* get buffer address of next indication */
@@ -728,6 +868,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
/* clear interrupt */
switch(ccard->type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_QUADRO:
writeb(0, isa_card->intack);
writeb(0, &com[0x401]);
@@ -738,6 +879,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
case EICON_CTYPE_S2M:
writeb(0, isa_card->intack);
break;
+#endif
case EICON_CTYPE_MAESTRAP:
writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
writew(0, &cfg[MP_IRQ_RESET + 2]);
diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c
index 184f1c394..75122559c 100644
--- a/drivers/isdn/eicon/eicon_isa.c
+++ b/drivers/isdn/eicon/eicon_isa.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.c,v 1.5 1999/04/01 12:48:33 armin Exp $
+/* $Id: eicon_isa.c,v 1.7 1999/08/22 20:26:48 calle Exp $
*
* ISDN low-level module for Eicon.Diehl active ISDN-Cards.
* Hardware-specific code for old ISA cards.
@@ -22,6 +22,16 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_isa.c,v $
+ * Revision 1.7 1999/08/22 20:26:48 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.6 1999/07/25 15:12:06 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
* Revision 1.5 1999/04/01 12:48:33 armin
* Changed some log outputs.
*
@@ -46,6 +56,7 @@
*
*/
+#include <linux/config.h>
#include "eicon.h"
#include "eicon_isa.h"
@@ -53,7 +64,9 @@
#define release_shmem release_region
#define request_shmem request_region
-char *eicon_isa_revision = "$Revision: 1.5 $";
+char *eicon_isa_revision = "$Revision: 1.7 $";
+
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
/* Mask for detecting invalid IRQ parameter */
static int eicon_isa_valid_irq[] = {
@@ -430,3 +443,5 @@ eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) {
card->irqprobe = 0;
return 0;
}
+
+#endif /* CONFIG_ISDN_DRV_EICON_ISA */
diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
index c14d91d7e..1ac22aa80 100644
--- a/drivers/isdn/eicon/eicon_mod.c
+++ b/drivers/isdn/eicon/eicon_mod.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.5 1999/04/01 12:48:35 armin Exp $
+/* $Id: eicon_mod.c,v 1.11 1999/08/29 17:23:45 armin Exp $
*
* ISDN lowlevel-module for Eicon.Diehl active cards.
*
@@ -26,6 +26,31 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_mod.c,v $
+ * Revision 1.11 1999/08/29 17:23:45 armin
+ * New setup compat.
+ * Bugfix if compile as not module.
+ *
+ * Revision 1.10 1999/08/28 21:32:53 armin
+ * Prepared for fax related functions.
+ * Now compilable without errors/warnings.
+ *
+ * Revision 1.9 1999/08/18 20:17:02 armin
+ * Added XLOG function for all cards.
+ * Bugfix of alloc_skb NULL pointer.
+ *
+ * Revision 1.8 1999/07/25 15:12:08 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
+ * Revision 1.7 1999/07/11 17:16:27 armin
+ * Bugfixes in queue handling.
+ * Added DSP-DTMF decoder functions.
+ * Reorganized ack_handler.
+ *
+ * Revision 1.6 1999/06/09 19:31:26 armin
+ * Wrong PLX size for request_region() corrected.
+ * Added first MCA code from Erik Weber.
+ *
* Revision 1.5 1999/04/01 12:48:35 armin
* Changed some log outputs.
*
@@ -50,17 +75,23 @@
*
*/
+#define DRIVERPATCH ""
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
+#ifdef CONFIG_MCA
+#include <linux/mca.h>
+#endif
#include "eicon.h"
#define INCLUDE_INLINE_FUNCS
-static eicon_card *cards = (eicon_card *) NULL;
+static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains
+ start of card-list */
-static char *eicon_revision = "$Revision: 1.5 $";
+static char *eicon_revision = "$Revision: 1.11 $";
extern char *eicon_pci_revision;
extern char *eicon_isa_revision;
@@ -70,24 +101,28 @@ extern char *eicon_idi_revision;
#define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))
#endif
-#define EICON_CTRL_VERSION 1
+#define EICON_CTRL_VERSION 2
ulong DebugVar;
/* Parameters to be set by insmod */
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
static int membase = -1;
static int irq = -1;
+#endif
static char *id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
MODULE_DESCRIPTION( "Driver for Eicon.Diehl active ISDN cards");
MODULE_AUTHOR( "Armin Schindler");
MODULE_SUPPORTED_DEVICE( "ISDN subsystem");
+MODULE_PARM_DESC(id, "ID-String of first card");
+MODULE_PARM(id, "s");
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
MODULE_PARM_DESC(membase, "Base address of first ISA card");
MODULE_PARM_DESC(irq, "IRQ of first card");
-MODULE_PARM_DESC(id, "ID-String of first card");
MODULE_PARM(membase, "i");
MODULE_PARM(irq, "i");
-MODULE_PARM(id, "s");
+#endif
char *eicon_ctype_name[] = {
"ISDN-S",
@@ -291,10 +326,10 @@ eicon_rcv_dispatch(struct eicon_card *card)
{
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
case EICON_BUS_PCI:
eicon_io_rcv_dispatch(card);
break;
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -307,10 +342,10 @@ eicon_ack_dispatch(struct eicon_card *card)
{
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
case EICON_BUS_PCI:
eicon_io_ack_dispatch(card);
break;
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -323,10 +358,10 @@ eicon_transmit(struct eicon_card *card)
{
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
case EICON_BUS_PCI:
eicon_io_transmit(card);
break;
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -334,6 +369,32 @@ eicon_transmit(struct eicon_card *card)
}
}
+static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq)
+{
+ xlogreq_t *xlr;
+ int ret_val;
+
+ if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) {
+ if (DebugVar & 1)
+ printk(KERN_WARNING "idi_err: alloc_xlogreq_t failed\n");
+ return -ENOMEM;
+ }
+ if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) {
+ kfree(xlr);
+ return -EFAULT;
+ }
+
+ ret_val = eicon_get_xlog(card, xlr);
+
+ if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) {
+ kfree(xlr);
+ return -EFAULT;
+ }
+ kfree(xlr);
+
+ return ret_val;
+}
+
static int
eicon_command(eicon_card * card, isdn_ctrl * c)
{
@@ -345,6 +406,10 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
int ret = 0;
unsigned long flags;
+ if (DebugVar & 16)
+ printk(KERN_WARNING "eicon_cmd 0x%x with arg 0x%lx (0x%lx)\n",
+ c->command, c->arg, (ulong) *c->parm.num);
+
switch (c->command) {
case ISDN_CMD_IOCTL:
memcpy(&a, c->parm.num, sizeof(ulong));
@@ -356,6 +421,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
case EICON_IOCTL_GETMMIO:
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
return (int)card->hwif.isa.shmem;
#if CONFIG_PCI
case EICON_BUS_PCI:
@@ -368,11 +434,13 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
card->bus);
ret = -ENODEV;
}
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_IOCTL_SETMMIO:
if (card->flags & EICON_FLAGS_LOADED)
return -EBUSY;
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
if (eicon_isa_find_card(a,
card->hwif.isa.irq,
card->regname) < 0)
@@ -386,9 +454,11 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
card->bus);
ret = -ENODEV;
}
+#endif
case EICON_IOCTL_GETIRQ:
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
return card->hwif.isa.irq;
#if CONFIG_PCI
case EICON_BUS_PCI:
@@ -408,6 +478,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
return -EFAULT;
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
card->hwif.isa.irq = a;
return 0;
default:
@@ -417,11 +488,13 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
card->bus);
ret = -ENODEV;
}
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_IOCTL_LOADBOOT:
if (card->flags & EICON_FLAGS_RUNNING)
return -EBUSY;
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
ret = eicon_isa_bootload(
&(card->hwif.isa),
&(((eicon_codebuf *)a)->isa));
@@ -434,11 +507,14 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
ret = -ENODEV;
}
return ret;
+#endif
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_IOCTL_LOADISA:
if (card->flags & EICON_FLAGS_RUNNING)
return -EBUSY;
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
ret = eicon_isa_load(
&(card->hwif.isa),
&(((eicon_codebuf *)a)->isa));
@@ -465,7 +541,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
ret = -ENODEV;
}
return ret;
-
+#endif
case EICON_IOCTL_MANIF:
if (!card->flags & EICON_FLAGS_RUNNING)
return -ENODEV;
@@ -475,6 +551,12 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
card,
(eicon_manifbuf *)a);
return ret;
+
+ case EICON_IOCTL_GETXLOG:
+ if (!card->flags & EICON_FLAGS_RUNNING)
+ return XLOG_ERR_CARD_STATE;
+ ret = eicon_xlog(card, (xlogreq_t *)a);
+ return ret;
#if CONFIG_PCI
case EICON_IOCTL_LOADPCI:
if (card->flags & EICON_FLAGS_RUNNING)
@@ -639,14 +721,13 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
case ISDN_CMD_SETL3:
if (!card->flags & EICON_FLAGS_RUNNING)
return -ENODEV;
- if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
- if (DebugVar & 1)
- printk(KERN_WARNING "L3 protocol unknown\n");
- return -1;
- }
if (!(chan = find_channel(card, c->arg & 0x1f)))
break;
chan->l3prot = (c->arg >> 8);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l3prot == ISDN_PROTO_L3_FAX)
+ chan->fax = c->parm.fax;
+#endif
return 0;
case ISDN_CMD_GETL3:
if (!card->flags & EICON_FLAGS_RUNNING)
@@ -678,6 +759,24 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
case ISDN_CMD_UNLOCK:
MOD_DEC_USE_COUNT;
return 0;
+#ifdef CONFIG_ISDN_TTY_FAX
+ case ISDN_CMD_FAXCMD:
+ if (!card->flags & EICON_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x1f)))
+ break;
+ if (!chan->fax)
+ break;
+ idi_fax_cmd(card, chan);
+ return 0;
+#endif
+ case ISDN_CMD_AUDIO:
+ if (!card->flags & EICON_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x1f)))
+ break;
+ idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num);
+ return 0;
}
return -EINVAL;
@@ -718,16 +817,19 @@ if_command(isdn_ctrl * c)
static int
if_writecmd(const u_char * buf, int len, int user, int id, int channel)
{
+#if 0
+ /* Not yet used */
eicon_card *card = eicon_findcard(id);
if (card) {
if (!card->flags & EICON_FLAGS_RUNNING)
- return -ENODEV;
+ return (len);
return (len);
}
printk(KERN_ERR
"eicon: if_writecmd called with invalid driverId!\n");
- return -ENODEV;
+#endif
+ return (len);
}
static int
@@ -745,7 +847,7 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel)
printk(KERN_ERR
"eicon: if_readstatus called with invalid driverId!\n");
#endif
- return -ENODEV;
+ return 0;
}
static int
@@ -753,6 +855,10 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
{
eicon_card *card = eicon_findcard(id);
eicon_chan *chan;
+ int ret = 0;
+ int len;
+
+ len = skb->len;
if (card) {
if (!card->flags & EICON_FLAGS_RUNNING) {
@@ -763,9 +869,17 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
dev_kfree_skb(skb);
return -ENODEV;
}
- if (chan->fsm_state == EICON_STATE_ACTIVE)
- return (idi_send_data(card, chan, ack, skb));
- else {
+ if (chan->fsm_state == EICON_STATE_ACTIVE) {
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ if ((ret = idi_faxdata_send(card, chan, skb)) > 0)
+ ret = len;
+ }
+ else
+#endif
+ ret = idi_send_data(card, chan, ack, skb, 1);
+ return (ret);
+ } else {
dev_kfree_skb(skb);
return -ENODEV;
}
@@ -787,7 +901,9 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
int i;
int j;
int qloop;
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
char qid[5];
+#endif
eicon_card *card;
#if CONFIG_PCI
eicon_pci_card *pcic;
@@ -828,12 +944,32 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->myid = -1;
card->type = Type;
switch (Type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
+#if CONFIG_MCA /* only needed for MCA */
+ case EICON_CTYPE_S:
+ case EICON_CTYPE_SX:
+ case EICON_CTYPE_SCOM:
+ if (membase == -1)
+ membase = EICON_ISA_MEMBASE;
+ if (irq == -1)
+ irq = EICON_ISA_IRQ;
+ card->bus = EICON_BUS_MCA;
+ card->hwif.isa.card = (void *)card;
+ card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
+ card->hwif.isa.master = 1;
+
+ card->hwif.isa.irq = irq;
+ card->hwif.isa.type = Type;
+ card->nchannels = 2;
+ card->interface.channels = 1;
+ break;
+#endif /* CONFIG_MCA */
case EICON_CTYPE_QUADRO:
if (membase == -1)
membase = EICON_ISA_MEMBASE;
if (irq == -1)
irq = EICON_ISA_IRQ;
- card->bus = EICON_BUS_ISA;
+ card->bus = EICON_BUS_ISA;
card->hwif.isa.card = (void *)card;
card->hwif.isa.shmem = (eicon_isa_shmem *)(membase + (i+1) * EICON_ISA_QOFFSET);
card->hwif.isa.master = 0;
@@ -868,6 +1004,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->nchannels = 2;
card->interface.channels = 1;
break;
+#endif
#if CONFIG_PCI
case EICON_CTYPE_MAESTRA:
(eicon_pci_card *)pcic = (eicon_pci_card *)membase;
@@ -876,7 +1013,10 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
ISDN_FEATURE_L2_V11096 |
ISDN_FEATURE_L2_V11019 |
ISDN_FEATURE_L2_V11038 |
- ISDN_FEATURE_L2_MODEM;
+ ISDN_FEATURE_L2_MODEM |
+ /* ISDN_FEATURE_L2_FAX | */
+ ISDN_FEATURE_L3_TRANSDSP |
+ ISDN_FEATURE_L3_FAX;
card->hwif.pci.card = (void *)card;
card->hwif.pci.PCIreg = pcic->PCIreg;
card->hwif.pci.PCIcfg = pcic->PCIcfg;
@@ -897,7 +1037,10 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
ISDN_FEATURE_L2_V11096 |
ISDN_FEATURE_L2_V11019 |
ISDN_FEATURE_L2_V11038 |
- ISDN_FEATURE_L2_MODEM;
+ ISDN_FEATURE_L2_MODEM |
+ /* ISDN_FEATURE_L2_FAX | */
+ ISDN_FEATURE_L3_TRANSDSP |
+ ISDN_FEATURE_L3_FAX;
card->hwif.pci.card = (void *)card;
card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem;
card->hwif.pci.PCIreg = pcic->PCIreg;
@@ -913,6 +1056,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->interface.channels = 1;
break;
#endif
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_ISABRI:
if (membase == -1)
membase = EICON_ISA_MEMBASE;
@@ -932,7 +1076,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
membase = EICON_ISA_MEMBASE;
if (irq == -1)
irq = EICON_ISA_IRQ;
- card->bus = EICON_BUS_ISA;
+ card->bus = EICON_BUS_ISA;
card->hwif.isa.card = (void *)card;
card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
card->hwif.isa.master = 1;
@@ -941,6 +1085,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->nchannels = 30;
card->interface.channels = 1;
break;
+#endif
default:
printk(KERN_WARNING "eicon_alloccard: Invalid type %d\n", Type);
kfree(card);
@@ -978,15 +1123,21 @@ static int
eicon_registercard(eicon_card * card)
{
switch (card->bus) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_BUS_ISA:
/* TODO something to print */
break;
+#ifdef CONFIG_MCA
+ case EICON_BUS_MCA:
+ eicon_isa_printpar(&card->hwif.isa);
+ break;
+#endif
+#endif
case EICON_BUS_PCI:
#if CONFIG_PCI
eicon_pci_printpar(&card->hwif.pci);
break;
#endif
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -1015,15 +1166,19 @@ unregister_card(eicon_card * card)
cmd.driver = card->myid;
card->interface.statcallb(&cmd);
switch (card->bus) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_BUS_ISA:
+#ifdef CONFIG_MCA
+ case EICON_BUS_MCA:
+#endif
eicon_isa_release(&card->hwif.isa);
break;
+#endif
case EICON_BUS_PCI:
#if CONFIG_PCI
eicon_pci_release(&card->hwif.pci);
break;
#endif
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -1050,9 +1205,11 @@ eicon_addcard(int Type, int membase, int irq, char *id)
int added = 0;
int failed = 0;
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
if (!Type) /* ISA */
if ((Type = eicon_isa_find_card(membase, irq, id)) < 0)
return 0;
+#endif
eicon_alloccard(Type, membase, irq, id);
p = cards;
while (p) {
@@ -1063,11 +1220,14 @@ eicon_addcard(int Type, int membase, int irq, char *id)
*/
added++;
switch (p->bus) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
if (eicon_registercard(p))
break;
registered = 1;
break;
+#endif
case EICON_BUS_PCI:
#if CONFIG_PCI
if (eicon_registercard(p))
@@ -1075,7 +1235,6 @@ eicon_addcard(int Type, int membase, int irq, char *id)
registered = 1;
break;
#endif
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -1116,10 +1275,10 @@ eicon_addcard(int Type, int membase, int irq, char *id)
#define eicon_init init_module
#endif
-__initfunc(int
-eicon_init(void))
+int __init
+eicon_init(void)
{
- int tmp = 0;
+ int card_count = 0;
int release = 0;
char tmprev[50];
@@ -1130,30 +1289,66 @@ eicon_init(void))
printk("%s/", eicon_getrev(tmprev));
release += getrel(tmprev);
strcpy(tmprev, eicon_pci_revision);
+#if CONFIG_PCI
printk("%s/", eicon_getrev(tmprev));
+#else
+ printk("---/");
+#endif
release += getrel(tmprev);
strcpy(tmprev, eicon_isa_revision);
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
printk("%s/", eicon_getrev(tmprev));
+#else
+ printk("---/");
+#endif
release += getrel(tmprev);
strcpy(tmprev, eicon_idi_revision);
printk("%s\n", eicon_getrev(tmprev));
release += getrel(tmprev);
sprintf(tmprev,"%d", release);
- printk(KERN_INFO "%s Release: %s.%s\n", DRIVERNAME,
- DRIVERRELEASE, tmprev);
+ printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME,
+ DRIVERRELEASE, tmprev, DRIVERPATCH);
- tmp = eicon_addcard(0, membase, irq, id);
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
+#ifdef CONFIG_MCA
+ /* Check if we have MCA-bus */
+ if (!MCA_bus)
+ {
+ printk(KERN_INFO
+ "eicon: No MCA bus, ISDN-interfaces not probed.\n");
+ } else {
+ if (DebugVar & 8)
+ printk(KERN_DEBUG
+ "eicon_mca_find_card, irq=%d.\n",
+ irq);
+ if (!eicon_mca_find_card(0, membase, irq, id))
+ card_count++;
+ };
+#else
+ card_count = eicon_addcard(0, membase, irq, id);
+#endif /* CONFIG_MCA */
+#endif /* CONFIG_ISDN_DRV_EICON_ISA */
+
#if CONFIG_PCI
- tmp += eicon_pci_find_card(id);
+ card_count += eicon_pci_find_card(id);
#endif
if (!cards) {
#ifdef MODULE
+#ifndef CONFIG_PCI
+#ifndef CONFIG_ISDN_DRV_EICON_ISA
+ printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n");
+#else
printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n");
#endif
+#else
+ printk(KERN_INFO "Eicon: No PCI-cards found, driver not loaded !\n");
+#endif
+#endif /* MODULE */
return -ENODEV;
} else
- printk(KERN_INFO "Eicon: %d card%s added\n", tmp, (tmp>1)?"s":"");
+ printk(KERN_INFO "Eicon: %d card%s added\n", card_count,
+ (card_count>1)?"s":"");
/* No symbols to export, hide all symbols */
EXPORT_NO_SYMBOLS;
return 0;
@@ -1166,6 +1361,13 @@ cleanup_module(void)
eicon_card *card = cards;
eicon_card *last;
while (card) {
+#ifdef CONFIG_MCA
+ if (MCA_bus)
+ {
+ mca_mark_as_unused (card->mca_slot);
+ mca_set_adapter_procfn(card->mca_slot, NULL, NULL);
+ };
+#endif
unregister_card(card);
card = card->next;
}
@@ -1178,14 +1380,27 @@ cleanup_module(void)
printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
}
+#else /* no module */
+
+#ifdef COMPAT_HAS_NEW_SETUP
+static int __init
+eicon_setup(char *line)
+{
+ int i, argc;
+ int ints[5];
+ char *str;
+
+ str = get_options(line, 4, ints);
#else
-__initfunc(void
-eicon_setup(char *str, int *ints))
+void __init
+eicon_setup(char *str, int *ints)
{
int i, argc;
+#endif
argc = ints[0];
i = 1;
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
if (argc) {
membase = irq = -1;
if (argc) {
@@ -1203,8 +1418,187 @@ eicon_setup(char *str, int *ints))
} else {
strcpy(id, "eicon");
}
- /* eicon_addcard(0, membase, irq, id); */
- printk(KERN_INFO "eicon: membase=0x%x irq=%d id=%s\n", membase, irq, id);
+ printk(KERN_INFO "Eicon ISDN active driver setup (id=%s membase=0x%x irq=%d)\n",
+ id, membase, irq);
}
+#else
+ printk(KERN_INFO "Eicon ISDN active driver setup\n");
+#endif
+#ifdef COMPAT_HAS_NEW_SETUP
+ return(1);
+}
+__setup("eicon=", eicon_setup);
+#else
}
#endif
+
+#endif /* MODULE */
+
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
+#ifdef CONFIG_MCA
+
+struct eicon_mca_adapters_struct {
+ char * name;
+ int adf_id;
+};
+/* possible MCA-brands of eicon cards */
+struct eicon_mca_adapters_struct eicon_mca_adapters[] = {
+ { "ISDN-P/2 Adapter", 0x6abb },
+ { "ISDN-[S|SX|SCOM]/2 Adapter", 0x6a93 },
+ { "DIVA /MCA", 0x6336 },
+ { NULL, 0 },
+};
+
+int eicon_mca_find_card(int type, /* type-idx of eicon-card */
+ int membase,
+ int irq,
+ char * id) /* name of eicon-isdn-dev */
+{
+ int j, curr_slot = 0;
+
+ if (DebugVar & 8)
+ printk(KERN_DEBUG
+ "eicon_mca_find_card type: %d, membase: %#x, irq %d \n",
+ type, membase, irq);
+ /* find a no-driver-assigned eicon card */
+ for (j=0; eicon_mca_adapters[j].adf_id != 0; j++)
+ {
+ for ( curr_slot=0; curr_slot<=MCA_MAX_SLOT_NR; curr_slot++)
+ {
+ curr_slot = mca_find_unused_adapter(
+ eicon_mca_adapters[j].adf_id, curr_slot);
+ if (curr_slot != MCA_NOTFOUND)
+ {
+ /* check if pre-set parameters match
+ these of the card, check cards memory */
+ if (!(int) eicon_mca_probe(curr_slot,
+ j,
+ membase,
+ irq,
+ id))
+ {
+ return 0;
+ /* means: adapter parms did match */
+ };
+ };
+ break;
+ /* MCA_NOTFOUND-branch: no matching adapter of
+ THIS flavor found, next flavor */
+
+ };
+ };
+ /* all adapter flavors checked without match, finito with: */
+ return ENODEV;
+};
+
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ * stolen from 3c523.c/elmc_getinfo, ewe, 10.5.1999
+ */
+int eicon_info(char * buf, int slot, void *d)
+{
+ int len = 0;
+ struct eicon_card *dev;
+
+ dev = (struct eicon_card *) d;
+
+ if (dev == NULL)
+ return len;
+ len += sprintf(buf+len, "eicon ISDN adapter, type %d.\n",dev->type);
+ len += sprintf(buf+len, "IRQ: %d\n", dev->hwif.isa.irq);
+ len += sprintf(buf+len, "MEMBASE: %#lx\n", (unsigned long)dev->hwif.isa.shmem);
+
+ return len;
+};
+
+int eicon_mca_probe(int slot, /* slot-nr where the card was detected */
+ int a_idx, /* idx-nr of probed card in eicon_mca_adapters */
+ int membase,
+ int irq,
+ char * id) /* name of eicon-isdn-dev */
+{
+ unsigned char adf_pos0;
+ int cards_irq, cards_membase, cards_io;
+ int type = EICON_CTYPE_S;
+ int irq_array[]={0,3,4,2};
+ int irq_array1[]={3,4,0,0,2,10,11,12};
+
+ adf_pos0 = mca_read_stored_pos(slot,2);
+ if (DebugVar & 8)
+ printk(KERN_DEBUG
+ "eicon_mca_probe irq=%d, membase=%d\n",
+ irq,
+ membase);
+ switch (a_idx) {
+ case 0: /* P/2-Adapter (== PRI/S2M ? ) */
+ cards_membase= 0xC0000+((adf_pos0>>4)*0x4000);
+ if (membase == -1) {
+ membase = cards_membase;
+ } else {
+ if (membase != cards_membase)
+ return ENODEV;
+ };
+ cards_irq=irq_array[((adf_pos0 & 0xC)>>2)];
+ if (irq == -1) {
+ irq = cards_irq;
+ } else {
+ if (irq != irq)
+ return ENODEV;
+ };
+ cards_io= 0xC00 + ((adf_pos0>>4)*0x10);
+ type = EICON_CTYPE_ISAPRI;
+ break;
+
+ case 1: /* [S|SX|SCOM]/2 */
+ cards_membase= 0xC0000+((adf_pos0>>4)*0x2000);
+ if (membase == -1) {
+ membase = cards_membase;
+ } else {
+ if (membase != cards_membase)
+ return ENODEV;
+ };
+ cards_irq=irq_array[((adf_pos0 & 0xC)>>2)];
+ if (irq == -1) {
+ irq = cards_irq;
+ } else {
+ if (irq != cards_irq)
+ return ENODEV;
+ };
+
+ cards_io= 0xC00 + ((adf_pos0>>4)*0x10);
+ type = EICON_CTYPE_SCOM;
+ break;
+
+ case 2: /* DIVA/MCA */
+ cards_io = 0x200+ ((adf_pos0>>4)* 0x20);
+ cards_irq = irq_array1[(adf_pos0 & 0x7)];
+ if (irq == -1) {
+ irq = cards_irq;
+ } else {
+ if (irq != irq)
+ return ENODEV;
+ };
+ type = 0;
+ break;
+ default:
+ return ENODEV;
+ };
+ /* Uebereinstimmung vorgegebener membase & irq */
+ if ( 1 == eicon_addcard(type, membase, irq, id)) {
+ mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name);
+ mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards);
+
+ mca_mark_as_used(slot);
+ cards->mca_slot = slot;
+ /* card->io noch setzen oder ?? */
+ if (DebugVar & 8)
+ printk("eicon_addcard: erfolgreich fuer slot: %d.\n",
+ cards->mca_slot+1);
+ return 0 ; /* eicon_addcard hat eine Karte zugefuegt */
+ } else {
+ return ENODEV;
+ };
+};
+#endif /* CONFIG_MCA */
+#endif /* CONFIG_ISDN_DRV_EICON_ISA */
+
diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c
index 3d07167ce..c1919e9f8 100644
--- a/drivers/isdn/eicon/eicon_pci.c
+++ b/drivers/isdn/eicon/eicon_pci.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.c,v 1.6 1999/04/01 12:48:37 armin Exp $
+/* $Id: eicon_pci.c,v 1.10 1999/08/22 20:26:49 calle Exp $
*
* ISDN low-level module for Eicon.Diehl active ISDN-Cards.
* Hardware-specific code for PCI cards.
@@ -26,6 +26,22 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_pci.c,v $
+ * Revision 1.10 1999/08/22 20:26:49 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.9 1999/08/11 21:01:11 keil
+ * new PCI codefix
+ *
+ * Revision 1.8 1999/08/10 16:02:20 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 1.7 1999/06/09 19:31:29 armin
+ * Wrong PLX size for request_region() corrected.
+ * Added first MCA code from Erik Weber.
+ *
* Revision 1.6 1999/04/01 12:48:37 armin
* Changed some log outputs.
*
@@ -61,7 +77,7 @@
#include "eicon_pci.h"
-char *eicon_pci_revision = "$Revision: 1.6 $";
+char *eicon_pci_revision = "$Revision: 1.10 $";
#if CONFIG_PCI /* intire stuff is only for PCI */
@@ -136,8 +152,8 @@ int eicon_pci_find_card(char *ID)
aparms->type = EICON_CTYPE_MAESTRA;
aparms->irq = pdev->irq;
- preg = pdev->base_address[2] & 0xfffffffc;
- pcfg = pdev->base_address[1] & 0xffffff80;
+ preg = get_pcibase(pdev, 2) & 0xfffffffc;
+ pcfg = get_pcibase(pdev, 1) & 0xffffff80;
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
@@ -158,9 +174,9 @@ int eicon_pci_find_card(char *ID)
printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n");
aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/
aparms->irq = pdev->irq;
- pram = pdev->base_address[0] & 0xfffff000;
- preg = pdev->base_address[2] & 0xfffff000;
- pcfg = pdev->base_address[4] & 0xfffff000;
+ pram = get_pcibase(pdev, 0) & 0xfffff000;
+ preg = get_pcibase(pdev, 2) & 0xfffff000;
+ pcfg = get_pcibase(pdev, 4) & 0xfffff000;
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
@@ -194,12 +210,13 @@ int eicon_pci_find_card(char *ID)
} else {
request_region(aparms->PCIreg, 0x20, "eicon reg");
}
- if (check_region((aparms->PCIcfg), 0x100)) {
+ if (check_region((aparms->PCIcfg), 0x80)) {
printk(KERN_WARNING "eicon_pci: cfg port already in use !\n");
aparms->PCIcfg = 0;
+ release_region(aparms->PCIreg, 0x20);
break;
} else {
- request_region(aparms->PCIcfg, 0x100, "eicon cfg");
+ request_region(aparms->PCIcfg, 0x80, "eicon cfg");
}
break;
case PCI_MAESTRAQ:
@@ -327,7 +344,7 @@ eicon_pci_release_shmem(eicon_pci_card *card) {
outw(0, card->PCIreg + M_DATA);
release_region(card->PCIreg, 0x20);
- release_region(card->PCIcfg, 0x100);
+ release_region(card->PCIcfg, 0x80);
break;
case EICON_CTYPE_MAESTRAQ:
case EICON_CTYPE_MAESTRAQ_U:
diff --git a/drivers/isdn/hisax/.cvsignore b/drivers/isdn/hisax/.cvsignore
deleted file mode 100644
index 857dd22e9..000000000
--- a/drivers/isdn/hisax/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.depend
-.*.flags
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index 9e7cb7773..051df6182 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -25,13 +25,11 @@ ifeq ($(CONFIG_HISAX_1TR6),y)
endif
ISAC_OBJ :=
-ARCOFI_OBJ :=
HSCX_OBJ :=
ISAR_OBJ :=
HFC_OBJ :=
HFC_2BDS0 :=
-RAWHDLC_OBJ :=
-
+JADE_OBJ :=
ifeq ($(CONFIG_HISAX_16_0),y)
O_OBJS += teles0.o
ISAC_OBJ := isac.o
@@ -78,7 +76,6 @@ 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)
@@ -127,16 +124,15 @@ endif
ifeq ($(CONFIG_HISAX_NETJET),y)
O_OBJS += netjet.o
ISAC_OBJ := isac.o
-# RAWHDLC_OBJ := rawhdlc.o
endif
-ifeq ($(CONFIG_HISAX_TELES3C),y)
- O_OBJS += teles3c.o
+ifeq ($(CONFIG_HISAX_HFCS),y)
+ O_OBJS += hfcscard.o
HFC_2BDS0 := hfc_2bds0.o
endif
-ifeq ($(CONFIG_HISAX_AMD7930),y)
- O_OBJS += amd7930.o
- RAWHDLC_OBJ := rawhdlc.o
+
+ifeq ($(CONFIG_HISAX_HFC_PCI),y)
+ HFC_2BDS0 += hfc_pci.o
endif
ifeq ($(CONFIG_HISAX_NICCY),y)
@@ -145,8 +141,45 @@ ifeq ($(CONFIG_HISAX_NICCY),y)
HSCX_OBJ := hscx.o
endif
-O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(ARCOFI_OBJ)
-O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(RAWHDLC_OBJ)
+ifeq ($(CONFIG_HISAX_ISURF),y)
+ O_OBJS += isurf.o
+ ISAC_OBJ := isac.o
+ ISAR_OBJ := isar.o
+endif
+
+ifeq ($(CONFIG_HISAX_HSTSAPHIR),y)
+ O_OBJS += saphir.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_BKM_A4T),y)
+ O_OBJS += bkm_a4t.o
+ ISAC_OBJ := isac.o
+ JADE_OBJ := jade.o
+endif
+ifeq ($(CONFIG_HISAX_SCT_QUADRO),y)
+ O_OBJS += bkm_a8.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_GAZEL),y)
+ O_OBJS += gazel.o
+ ISAC_OBJ := isac.o
+ HSCX_OBJ := hscx.o
+endif
+
+# ifeq ($(CONFIG_HISAX_TESTEMU),y)
+# O_OBJS += testemu.o
+# endif
+
+ifeq ($(ISAC_OBJ), isac.o)
+ ISAC_OBJ += arcofi.o
+endif
+
+O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(JADE_OBJ)
+O_OBJS += $(HFC_OBJ) $(HFC_2BDS0)
OX_OBJS += config.o
O_TARGET :=
@@ -164,7 +197,8 @@ endif
include $(TOPDIR)/Rules.make
MD5FILES += isac.c isdnl1.c isdnl2.c isdnl3.c \
- tei.c callc.c cert.c l3dss1.c l3_1tr6.c elsa.c
+ tei.c callc.c cert.c l3dss1.c l3_1tr6.c \
+ elsa.c diva.c
CERT = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
diff --git a/drivers/isdn/hisax/amd7930.c b/drivers/isdn/hisax/amd7930.c
index 1cf2307b3..7bcc8827c 100644
--- a/drivers/isdn/hisax/amd7930.c
+++ b/drivers/isdn/hisax/amd7930.c
@@ -1,4 +1,4 @@
-/* $Id: amd7930.c,v 1.2 1998/02/12 23:07:10 keil Exp $
+/* $Id: amd7930.c,v 1.3 1999/07/12 21:04:52 keil Exp $
*
* HiSax ISDN driver - chip specific routines for AMD 7930
*
@@ -7,6 +7,10 @@
*
*
* $Log: amd7930.c,v $
+ * Revision 1.3 1999/07/12 21:04:52 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
* Revision 1.2 1998/02/12 23:07:10 keil
* change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
*
@@ -105,7 +109,7 @@
#include "rawhdlc.h"
#include <linux/interrupt.h>
-static const char *amd7930_revision = "$Revision: 1.2 $";
+static const char *amd7930_revision = "$Revision: 1.3 $";
#define RCV_BUFSIZE 1024 /* Size of raw receive buffer in bytes */
#define RCV_BUFBLKS 4 /* Number of blocks to divide buffer into
@@ -734,8 +738,6 @@ amd7930_card_msg(struct IsdnCardState *cs, int mt, void *arg)
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);
@@ -747,7 +749,7 @@ amd7930_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __init
setup_amd7930(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c
index a7c091321..9e582641d 100644
--- a/drivers/isdn/hisax/arcofi.c
+++ b/drivers/isdn/hisax/arcofi.c
@@ -1,4 +1,4 @@
-/* $Id: arcofi.c,v 1.6 1998/09/30 22:21:56 keil Exp $
+/* $Id: arcofi.c,v 1.8 1999/08/25 16:50:51 keil Exp $
* arcofi.c Ansteuerung ARCOFI 2165
*
@@ -7,6 +7,12 @@
*
*
* $Log: arcofi.c,v $
+ * Revision 1.8 1999/08/25 16:50:51 keil
+ * Fix bugs which cause 2.3.14 hangs (waitqueue init)
+ *
+ * Revision 1.7 1999/07/01 08:11:17 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.6 1998/09/30 22:21:56 keil
* cosmetics
*
@@ -32,48 +38,124 @@
#include "hisax.h"
#include "isdnl1.h"
#include "isac.h"
+#include "arcofi.h"
-int
-send_arcofi(struct IsdnCardState *cs, const u_char *msg, int bc, int receive) {
+#define ARCOFI_TIMER_VALUE 20
+
+static void
+add_arcofi_timer(struct IsdnCardState *cs) {
+ if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
+ del_timer(&cs->dc.isac.arcofitimer);
+ }
+ init_timer(&cs->dc.isac.arcofitimer);
+ cs->dc.isac.arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ)/1000);
+ add_timer(&cs->dc.isac.arcofitimer);
+}
+
+static void
+send_arcofi(struct IsdnCardState *cs) {
u_char val;
- long flags;
- int cnt=30;
- cs->mon_txp = 0;
- cs->mon_txc = msg[0];
- memcpy(cs->mon_tx, &msg[1], cs->mon_txc);
- switch(bc) {
+ add_arcofi_timer(cs);
+ cs->dc.isac.mon_txp = 0;
+ cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len;
+ memcpy(cs->dc.isac.mon_tx, cs->dc.isac.arcofi_list->msg, cs->dc.isac.mon_txc);
+ switch(cs->dc.isac.arcofi_bc) {
case 0: break;
- case 1: cs->mon_tx[1] |= 0x40;
+ case 1: cs->dc.isac.mon_tx[1] |= 0x40;
break;
default: break;
}
- cs->mocr &= 0x0f;
- cs->mocr |= 0xa0;
- test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags);
- if (receive)
- test_and_clear_bit(HW_MON1_RX_END, &cs->HW_Flags);
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ cs->dc.isac.mocr &= 0x0f;
+ cs->dc.isac.mocr |= 0xa0;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.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--;
- udelay(500);
+ cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
+ cs->dc.isac.mocr |= 0x10;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+}
+
+int
+arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
+ if (cs->debug & L1_DEB_MONITOR) {
+ debugl1(cs, "arcofi state %d event %d", cs->dc.isac.arcofi_state, event);
}
- if (receive) {
- while (cnt && !test_bit(HW_MON1_RX_END, &cs->HW_Flags)) {
- cnt--;
- udelay(500);
- }
+ if (event == ARCOFI_TIMEOUT) {
+ cs->dc.isac.arcofi_state = ARCOFI_NOP;
+ test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags);
+ wake_up_interruptible(&cs->dc.isac.arcofi_wait);
+ return(1);
}
- restore_flags(flags);
- if (cnt <= 0) {
- printk(KERN_WARNING"HiSax arcofi monitor timed out\n");
- debugl1(cs, "HiSax arcofi monitor timed out");
+ switch (cs->dc.isac.arcofi_state) {
+ case ARCOFI_NOP:
+ if (event == ARCOFI_START) {
+ cs->dc.isac.arcofi_list = data;
+ cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
+ send_arcofi(cs);
+ }
+ break;
+ case ARCOFI_TRANSMIT:
+ if (event == ARCOFI_TX_END) {
+ if (cs->dc.isac.arcofi_list->receive) {
+ add_arcofi_timer(cs);
+ cs->dc.isac.arcofi_state = ARCOFI_RECEIVE;
+ } else {
+ if (cs->dc.isac.arcofi_list->next) {
+ cs->dc.isac.arcofi_list =
+ cs->dc.isac.arcofi_list->next;
+ send_arcofi(cs);
+ } else {
+ if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
+ del_timer(&cs->dc.isac.arcofitimer);
+ }
+ cs->dc.isac.arcofi_state = ARCOFI_NOP;
+ wake_up_interruptible(&cs->dc.isac.arcofi_wait);
+ }
+ }
+ }
+ break;
+ case ARCOFI_RECEIVE:
+ if (event == ARCOFI_RX_END) {
+ if (cs->dc.isac.arcofi_list->next) {
+ cs->dc.isac.arcofi_list =
+ cs->dc.isac.arcofi_list->next;
+ cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
+ send_arcofi(cs);
+ } else {
+ if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
+ del_timer(&cs->dc.isac.arcofitimer);
+ }
+ cs->dc.isac.arcofi_state = ARCOFI_NOP;
+ wake_up_interruptible(&cs->dc.isac.arcofi_wait);
+ }
+ }
+ break;
+ default:
+ debugl1(cs, "Arcofi unknown state %x", cs->dc.isac.arcofi_state);
+ return(2);
}
- return(cnt);
+ return(0);
+}
+
+static void
+arcofi_timer(struct IsdnCardState *cs) {
+ arcofi_fsm(cs, ARCOFI_TIMEOUT, NULL);
+}
+
+void
+clear_arcofi(struct IsdnCardState *cs) {
+ if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
+ del_timer(&cs->dc.isac.arcofitimer);
+ }
+}
+
+void
+init_arcofi(struct IsdnCardState *cs) {
+ cs->dc.isac.arcofitimer.function = (void *) arcofi_timer;
+ cs->dc.isac.arcofitimer.data = (long) cs;
+ init_timer(&cs->dc.isac.arcofitimer);
+#ifdef COMPAT_HAS_NEW_WAITQ
+ init_waitqueue_head(&cs->dc.isac.arcofi_wait);
+#endif
+ test_and_set_bit(HW_ARCOFI, &cs->HW_Flags);
}
diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h
index be1097d15..86617d6a1 100644
--- a/drivers/isdn/hisax/arcofi.h
+++ b/drivers/isdn/hisax/arcofi.h
@@ -1,4 +1,4 @@
-/* $Id: arcofi.h,v 1.3 1998/05/25 12:57:39 keil Exp $
+/* $Id: arcofi.h,v 1.4 1999/07/01 08:11:18 keil Exp $
* arcofi.h Ansteuerung ARCOFI 2165
*
@@ -7,6 +7,9 @@
*
*
* $Log: arcofi.h,v $
+ * Revision 1.4 1999/07/01 08:11:18 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.3 1998/05/25 12:57:39 keil
* HiSax golden code from certification, Don't use !!!
* No leased lines, no X75, but many changes.
@@ -21,4 +24,16 @@
#define ARCOFI_USE 1
-extern int send_arcofi(struct IsdnCardState *cs, const u_char *msg, int bc, int receive);
+/* states */
+#define ARCOFI_NOP 0
+#define ARCOFI_TRANSMIT 1
+#define ARCOFI_RECEIVE 2
+/* events */
+#define ARCOFI_START 1
+#define ARCOFI_TX_END 2
+#define ARCOFI_RX_END 3
+#define ARCOFI_TIMEOUT 4
+
+extern int arcofi_fsm(struct IsdnCardState *cs, int event, void *data);
+extern void init_arcofi(struct IsdnCardState *cs);
+extern void clear_arcofi(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
index eeaad83f5..06d8b59d0 100644
--- a/drivers/isdn/hisax/asuscom.c
+++ b/drivers/isdn/hisax/asuscom.c
@@ -1,4 +1,4 @@
-/* $Id: asuscom.c,v 1.5 1998/11/15 23:54:19 keil Exp $
+/* $Id: asuscom.c,v 1.7 1999/07/12 21:04:53 keil Exp $
* asuscom.c low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
*
@@ -8,6 +8,13 @@
*
*
* $Log: asuscom.c,v $
+ * Revision 1.7 1999/07/12 21:04:53 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.6 1999/07/01 08:11:18 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.5 1998/11/15 23:54:19 keil
* changes from 2.0
*
@@ -32,7 +39,7 @@
extern const char *CardType[];
-const char *Asuscom_revision = "$Revision: 1.5 $";
+const char *Asuscom_revision = "$Revision: 1.7 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -181,7 +188,7 @@ static void
asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
if (!cs) {
printk(KERN_WARNING "ISDNLink: Spurious interrupt!\n");
@@ -189,16 +196,12 @@ asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
- if (val) {
+ 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) {
+ 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)
@@ -211,23 +214,19 @@ asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
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);
- }
+ 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.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0);
+ 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);
}
static void
asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char ista, val, icnt = 20;
+ u_char ista, val, icnt = 5;
if (!cs) {
printk(KERN_WARNING "ISDNLink: Spurious interrupt!\n");
@@ -290,13 +289,13 @@ reset_asuscom(struct IsdnCardState *cs)
save_flags(flags);
sti();
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout((10*HZ)/1000);
if (cs->subtyp == ASUS_IPAC)
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
else
byteout(cs->hw.asus.adr, 0); /* Reset Off */
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout((10*HZ)/1000);
if (cs->subtyp == ASUS_IPAC) {
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff);
@@ -317,13 +316,6 @@ Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
case CARD_RELEASE:
release_io_asuscom(cs);
return(0);
- case CARD_SETIRQ:
- if (cs->subtyp == ASUS_IPAC)
- return(request_irq(cs->irq, &asuscom_interrupt_ipac,
- I4L_IRQ_FLAG, "HiSax", cs));
- else
- return(request_irq(cs->irq, &asuscom_interrupt,
- I4L_IRQ_FLAG, "HiSax", cs));
case CARD_INIT:
cs->debug |= L1_DEB_IPAC;
inithscxisac(cs, 3);
@@ -334,7 +326,7 @@ Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __init
setup_asuscom(struct IsdnCard *card)
{
int bytecnt;
@@ -378,6 +370,7 @@ setup_asuscom(struct IsdnCard *card)
cs->writeisac = &WriteISAC_IPAC;
cs->readisacfifo = &ReadISACfifo_IPAC;
cs->writeisacfifo = &WriteISACfifo_IPAC;
+ cs->irq_func = &asuscom_interrupt_ipac;
printk(KERN_INFO "Asus: IPAC version %x\n", val);
} else {
cs->subtyp = ASUS_ISACHSCX;
@@ -390,6 +383,7 @@ setup_asuscom(struct IsdnCard *card)
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
+ cs->irq_func = &asuscom_interrupt;
ISACVersion(cs, "ISDNLink:");
if (HscxVersion(cs, "ISDNLink:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c
index e782708fb..f96db3675 100644
--- a/drivers/isdn/hisax/avm_a1.c
+++ b/drivers/isdn/hisax/avm_a1.c
@@ -1,4 +1,4 @@
-/* $Id: avm_a1.c,v 2.10 1998/11/15 23:54:21 keil Exp $
+/* $Id: avm_a1.c,v 2.11 1999/07/12 21:04:54 keil Exp $
* avm_a1.c low level stuff for AVM A1 (Fritz) isdn cards
*
@@ -6,6 +6,10 @@
*
*
* $Log: avm_a1.c,v $
+ * Revision 2.11 1999/07/12 21:04:54 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
* Revision 2.10 1998/11/15 23:54:21 keil
* changes from 2.0
*
@@ -66,7 +70,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-static const char *avm_revision = "$Revision: 2.10 $";
+static const char *avm_revision = "$Revision: 2.11 $";
#define AVM_A1_STAT_ISAC 0x01
#define AVM_A1_STAT_HSCX 0x02
@@ -153,7 +157,7 @@ static void
avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char val, sval, stat = 0;
+ u_char val, sval;
if (!cs) {
printk(KERN_WARNING "AVM A1: Spurious interrupt!\n");
@@ -167,29 +171,21 @@ avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
debugl1(cs, "avm IntStatus %x", sval);
if (!(sval & AVM_A1_STAT_HSCX)) {
val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
- if (val) {
+ if (val)
hscx_int_main(cs, val);
- stat |= 1;
- }
}
if (!(sval & AVM_A1_STAT_ISAC)) {
val = readreg(cs->hw.avm.isac, ISAC_ISTA);
- if (val) {
+ if (val)
isac_interrupt(cs, val);
- stat |= 2;
- }
}
}
- if (stat & 1) {
- 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(cs->hw.avm.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.avm.isac, ISAC_MASK, 0x0);
- }
+ writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF);
+ writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF);
+ writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.avm.isac, ISAC_MASK, 0x0);
+ writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0);
+ writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0);
}
inline static void
@@ -219,9 +215,6 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
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:
inithscxisac(cs, 1);
byteout(cs->hw.avm.cfg_reg, 0x16);
@@ -234,7 +227,7 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __init
setup_avm_a1(struct IsdnCard *card)
{
u_char val;
@@ -378,6 +371,7 @@ setup_avm_a1(struct IsdnCard *card)
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &AVM_card_msg;
+ cs->irq_func = &avm_a1_interrupt;
ISACVersion(cs, "AVM A1:");
if (HscxVersion(cs, "AVM A1:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c
index c11ac41e4..862829ab3 100644
--- a/drivers/isdn/hisax/avm_a1p.c
+++ b/drivers/isdn/hisax/avm_a1p.c
@@ -1,4 +1,4 @@
-/* $Id: avm_a1p.c,v 2.3 1998/11/15 23:54:22 keil Exp $
+/* $Id: avm_a1p.c,v 2.4 1999/07/12 21:04:55 keil Exp $
*
* avm_a1p.c low level stuff for the following AVM cards:
* A1 PCMCIA
@@ -8,6 +8,10 @@
* Author Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: avm_a1p.c,v $
+ * Revision 2.4 1999/07/12 21:04:55 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
* Revision 2.3 1998/11/15 23:54:22 keil
* changes from 2.0
*
@@ -67,7 +71,7 @@
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
-static const char *avm_revision = "$Revision: 2.3 $";
+static const char *avm_revision = "$Revision: 2.4 $";
static inline u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
@@ -195,7 +199,7 @@ static void
avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char val, sval, stat = 0;
+ u_char val, sval;
if (!cs) {
printk(KERN_WARNING "AVM A1 PCMCIA: Spurious interrupt!\n");
@@ -206,35 +210,26 @@ avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs)
debugl1(cs, "avm IntStatus %x", sval);
if (sval & ASL0_R_HSCX) {
val = ReadHSCX(cs, 1, HSCX_ISTA);
- if (val) {
+ if (val)
hscx_int_main(cs, val);
- stat |= 1;
- }
}
if (sval & ASL0_R_ISAC) {
val = ReadISAC(cs, ISAC_ISTA);
- if (val) {
+ if (val)
isac_interrupt(cs, val);
- stat |= 2;
- }
}
}
- if (stat & 1) {
- WriteHSCX(cs, 0, HSCX_MASK, 0xff);
- WriteHSCX(cs, 1, HSCX_MASK, 0xff);
- WriteHSCX(cs, 0, HSCX_MASK, 0x00);
- WriteHSCX(cs, 1, HSCX_MASK, 0x00);
- }
- if (stat & 2) {
- WriteISAC(cs, ISAC_MASK, 0xff);
- WriteISAC(cs, ISAC_MASK, 0x00);
- }
+ WriteHSCX(cs, 0, HSCX_MASK, 0xff);
+ WriteHSCX(cs, 1, HSCX_MASK, 0xff);
+ WriteISAC(cs, ISAC_MASK, 0xff);
+ WriteISAC(cs, ISAC_MASK, 0x00);
+ WriteHSCX(cs, 0, HSCX_MASK, 0x00);
+ WriteHSCX(cs, 1, HSCX_MASK, 0x00);
}
static int
AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- int ret;
switch (mt) {
case CARD_RESET:
byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
@@ -249,15 +244,6 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
/* free_irq(cs->irq, cs); */
return 0;
- case CARD_SETIRQ:
- ret = request_irq(cs->irq, &avm_a1p_interrupt,
- I4L_IRQ_FLAG, "HiSax", cs);
- if (ret)
- return ret;
- byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,
- ASL0_W_TDISABLE|ASL0_W_TRESET|ASL0_W_IRQENABLE);
- return 0;
-
case CARD_INIT:
clear_pending_isac_ints(cs);
clear_pending_hscx_ints(cs);
@@ -276,8 +262,8 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return 0;
}
-__initfunc(int
-setup_avm_a1_pcmcia(struct IsdnCard *card))
+int __init
+setup_avm_a1_pcmcia(struct IsdnCard *card)
{
u_char model, vers;
struct IsdnCardState *cs = card->cs;
@@ -323,6 +309,7 @@ setup_avm_a1_pcmcia(struct IsdnCard *card))
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &AVM_card_msg;
+ cs->irq_func = &avm_a1p_interrupt;
ISACVersion(cs, "AVM A1 PCMCIA:");
if (HscxVersion(cs, "AVM A1 PCMCIA:")) {
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index c0f04f91c..cd293f147 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -1,4 +1,4 @@
-/* $Id: avm_pci.c,v 1.7 1999/02/22 18:26:30 keil Exp $
+/* $Id: avm_pci.c,v 1.11 1999/08/11 21:01:18 keil Exp $
* avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
* Thanks to AVM, Berlin for informations
@@ -7,6 +7,19 @@
*
*
* $Log: avm_pci.c,v $
+ * Revision 1.11 1999/08/11 21:01:18 keil
+ * new PCI codefix
+ *
+ * Revision 1.10 1999/08/10 16:01:44 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 1.9 1999/07/12 21:04:57 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.8 1999/07/01 08:11:19 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.7 1999/02/22 18:26:30 keil
* Argh ! ISAC address was only set with PCI
*
@@ -37,10 +50,13 @@
#include "isac.h"
#include "isdnl1.h"
#include <linux/pci.h>
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
#include <linux/interrupt.h>
extern const char *CardType[];
-static const char *avm_pci_rev = "$Revision: 1.7 $";
+static const char *avm_pci_rev = "$Revision: 1.11 $";
#define AVM_FRITZ_PCI 1
#define AVM_FRITZ_PNP 2
@@ -466,7 +482,7 @@ HDLC_irq(struct BCState *bcs, u_int stat) {
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hdlc.count);
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->hw.hdlc.count = 0;
bcs->tx_skb = NULL;
}
@@ -593,7 +609,7 @@ close_hdlcstate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
@@ -687,7 +703,7 @@ static void
avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
u_char sval;
if (!cs) {
@@ -701,15 +717,12 @@ avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs)
if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
val = ReadISAC(cs, ISAC_ISTA);
isac_interrupt(cs, val);
- stat |= 2;
}
if (!(sval & AVM_STATUS0_IRQ_HDLC)) {
HDLC_irq_main(cs);
}
- if (stat & 2) {
- WriteISAC(cs, ISAC_MASK, 0xFF);
- WriteISAC(cs, ISAC_MASK, 0x0);
- }
+ WriteISAC(cs, ISAC_MASK, 0xFF);
+ WriteISAC(cs, ISAC_MASK, 0x0);
}
static void
@@ -733,8 +746,6 @@ reset_avmpcipnp(struct IsdnCardState *cs)
static int
AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- u_int irq_flag;
-
switch (mt) {
case CARD_RESET:
reset_avmpcipnp(cs);
@@ -743,13 +754,6 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
outb(0, cs->hw.avm.cfg_reg + 2);
release_region(cs->hw.avm.cfg_reg, 32);
return(0);
- case CARD_SETIRQ:
- if (cs->subtyp == AVM_FRITZ_PCI)
- irq_flag = I4L_IRQ_FLAG | SA_SHIRQ;
- else
- irq_flag = I4L_IRQ_FLAG;
- return(request_irq(cs->irq, &avm_pcipnp_interrupt,
- irq_flag, "HiSax", cs));
case CARD_INIT:
clear_pending_isac_ints(cs);
initisac(cs);
@@ -769,10 +773,14 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
+#ifdef COMPAT_HAS_NEW_PCI
static struct pci_dev *dev_avm __initdata = NULL;
+#else
+static int pci_index __initdata = 0;
+#endif
-__initfunc(int
-setup_avm_pcipnp(struct IsdnCard *card))
+int __init
+setup_avm_pcipnp(struct IsdnCard *card)
{
u_int val, ver;
struct IsdnCardState *cs = card->cs;
@@ -788,6 +796,7 @@ setup_avm_pcipnp(struct IsdnCard *card))
cs->subtyp = AVM_FRITZ_PNP;
} else {
#if CONFIG_PCI
+#ifdef COMPAT_HAS_NEW_PCI
if (!pci_present()) {
printk(KERN_ERR "FritzPCI: no PCI bus present\n");
return(0);
@@ -799,7 +808,7 @@ setup_avm_pcipnp(struct IsdnCard *card))
printk(KERN_WARNING "FritzPCI: No IRQ for PCI card found\n");
return(0);
}
- cs->hw.avm.cfg_reg = dev_avm->base_address[1] &
+ cs->hw.avm.cfg_reg = get_pcibase(dev_avm, 1) &
PCI_BASE_ADDRESS_IO_MASK;
if (!cs->hw.avm.cfg_reg) {
printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n");
@@ -811,6 +820,37 @@ setup_avm_pcipnp(struct IsdnCard *card))
return(0);
}
#else
+ for (; pci_index < 255; pci_index++) {
+ unsigned char pci_bus, pci_device_fn;
+ unsigned int ioaddr;
+ unsigned char irq;
+
+ if (pcibios_find_device (PCI_VENDOR_AVM,
+ PCI_FRITZPCI_ID, 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);
+ cs->irq = irq;
+ cs->hw.avm.cfg_reg = ioaddr & PCI_BASE_ADDRESS_IO_MASK;
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ cs->subtyp = AVM_FRITZ_PCI;
+ break;
+ }
+ if (pci_index == 255) {
+ printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+ return(0);
+ }
+ pci_index++;
+#endif /* COMPAT_HAS_NEW_PCI */
+ cs->irq_flags |= SA_SHIRQ;
+#else
printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
return (0);
#endif /* CONFIG_PCI */
@@ -846,8 +886,6 @@ setup_avm_pcipnp(struct IsdnCard *card))
break;
default:
printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp);
- outb(0, cs->hw.avm.cfg_reg + 2);
- release_region(cs->hw.avm.cfg_reg, 32);
return(0);
}
printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n",
@@ -860,6 +898,7 @@ setup_avm_pcipnp(struct IsdnCard *card))
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Send_Data = &fill_hdlc;
cs->cardmsg = &AVM_card_msg;
+ cs->irq_func = &avm_pcipnp_interrupt;
ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
return (1);
}
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
new file mode 100644
index 000000000..57d99b436
--- /dev/null
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -0,0 +1,410 @@
+/* $Id: bkm_a4t.c,v 1.7 1999/08/22 20:26:55 calle Exp $
+ * bkm_a4t.c low level stuff for T-Berkom A4T
+ * derived from the original file sedlbauer.c
+ * derived from the original file niccy.c
+ * derived from the original file netjet.c
+ *
+ * Author Roland Klabunde (R.Klabunde@Berkom.de)
+ *
+ * $Log: bkm_a4t.c,v $
+ * Revision 1.7 1999/08/22 20:26:55 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.6 1999/08/11 21:01:22 keil
+ * new PCI codefix
+ *
+ * Revision 1.5 1999/08/10 16:01:46 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 1.4 1999/07/14 11:43:14 keil
+ * correct PCI_SUBSYSTEM_VENDOR_ID
+ *
+ * Revision 1.3 1999/07/12 21:04:58 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.2 1999/07/01 08:07:53 keil
+ * Initial version
+ *
+ *
+ */
+
+#define __NO_VERSION__
+
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "jade.h"
+#include "isdnl1.h"
+#include "bkm_ax.h"
+#include <linux/pci.h>
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
+
+extern const char *CardType[];
+
+const char *bkm_a4t_revision = "$Revision: 1.7 $";
+
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+ register u_int ret;
+ long flags;
+ unsigned int *po = (unsigned int *) adr; /* Postoffice */
+ save_flags(flags);
+ cli();
+ *po = (GCS_2 | PO_WRITE | off);
+ __WAITI20__(po);
+ *po = (ale | PO_READ);
+ __WAITI20__(po);
+ ret = *po;
+ restore_flags(flags);
+ return ((unsigned char) 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 */
+ int i;
+ for (i = 0; i < size; i++)
+ *data++ = readreg(ale, adr, off);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+ long flags;
+ unsigned int *po = (unsigned int *) adr; /* Postoffice */
+ save_flags(flags);
+ cli();
+ *po = (GCS_2 | PO_WRITE | off);
+ __WAITI20__(po);
+ *po = (ale | PO_WRITE | data);
+ __WAITI20__(po);
+ 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 */
+ int i;
+
+ for (i = 0; i < size; i++)
+ writereg(ale, adr, off, *data++);
+}
+
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
+}
+
+static u_char
+ReadJADE(struct IsdnCardState *cs, int jade, u_char offset)
+{
+ return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80))));
+}
+
+static void
+WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value)
+{
+ writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value);
+}
+
+/*
+ * fast interrupt JADE stuff goes here
+ */
+
+#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale,\
+ cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)))
+#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale,\
+ cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data)
+
+#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale,\
+ cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
+#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo( cs->hw.ax.jade_ale,\
+ cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
+
+#include "jade_irq.c"
+
+static void
+bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val = 0;
+ I20_REGISTER_FILE *pI20_Regs;
+
+ if (!cs) {
+ printk(KERN_WARNING "HiSax: Telekom A4T: Spurious interrupt!\n");
+ return;
+ }
+ pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
+
+ /* ISDN interrupt pending? */
+ if (pI20_Regs->i20IntStatus & intISDN) {
+ /* Reset the ISDN interrupt */
+ pI20_Regs->i20IntStatus = intISDN;
+ /* Disable ISDN interrupt */
+ pI20_Regs->i20IntCtrl &= ~intISDN;
+ /* Channel A first */
+ val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80);
+ if (val) {
+ jade_int_main(cs, val, 0);
+ }
+ /* Channel B */
+ val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0);
+ if (val) {
+ jade_int_main(cs, val, 1);
+ }
+ /* D-Channel */
+ val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA);
+ if (val) {
+ isac_interrupt(cs, val);
+ }
+ /* Reenable ISDN interrupt */
+ pI20_Regs->i20IntCtrl |= intISDN;
+ }
+}
+
+void
+release_io_bkm(struct IsdnCardState *cs)
+{
+ if (cs->hw.ax.base) {
+ iounmap((void *) cs->hw.ax.base);
+ cs->hw.ax.base = 0;
+ }
+}
+
+static void
+enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
+{
+ if (cs->typ == ISDN_CTYPE_BKM_A4T) {
+ I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
+ if (bEnable)
+ pI20_Regs->i20IntCtrl |= (intISDN | intPCI);
+ else
+ /* CAUTION: This disables the video capture driver too */
+ pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI);
+ }
+}
+
+static void
+reset_bkm(struct IsdnCardState *cs)
+{
+ long flags;
+
+ if (cs->typ == ISDN_CTYPE_BKM_A4T) {
+ I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
+ save_flags(flags);
+ sti();
+ /* Issue the I20 soft reset */
+ pI20_Regs->i20SysControl = 0xFF; /* all in */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((10 * HZ) / 1000);
+ /* Remove the soft reset */
+ pI20_Regs->i20SysControl = sysRESET | 0xFF;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((10 * HZ) / 1000);
+ /* Set our configuration */
+ pI20_Regs->i20SysControl = sysRESET | sysCFG;
+ /* Issue ISDN reset */
+ pI20_Regs->i20GuestControl = guestWAIT_CFG |
+ g_A4T_JADE_RES |
+ g_A4T_ISAR_RES |
+ g_A4T_ISAC_RES |
+ g_A4T_JADE_BOOTR |
+ g_A4T_ISAR_BOOTR;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((10 * HZ) / 1000);
+
+ /* Remove RESET state from ISDN */
+ pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
+ g_A4T_JADE_RES |
+ g_A4T_ISAR_RES);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((10 * HZ) / 1000);
+ restore_flags(flags);
+ }
+}
+
+static int
+BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ /* Disable ints */
+ enable_bkm_int(cs, 0);
+ reset_bkm(cs);
+ return (0);
+ case CARD_RELEASE:
+ /* Sanity */
+ enable_bkm_int(cs, 0);
+ reset_bkm(cs);
+ release_io_bkm(cs);
+ return (0);
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ clear_pending_jade_ints(cs);
+ initisac(cs);
+ initjade(cs);
+ /* Enable ints */
+ enable_bkm_int(cs, 1);
+ return (0);
+ case CARD_TEST:
+ return (0);
+ }
+ return (0);
+}
+
+#ifdef COMPAT_HAS_NEW_PCI
+static struct pci_dev *dev_a4t __initdata = NULL;
+#else
+static int pci_index __initdata = 0;
+#endif
+
+int __init
+ setup_bkm_a4t(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ u_int pci_memaddr = 0, found = 0;
+ I20_REGISTER_FILE *pI20_Regs;
+#if CONFIG_PCI
+#ifndef COMPAT_HAS_NEW_PCI
+ u_char pci_bus, pci_device_fn, pci_irq = 0;
+#endif
+#endif
+
+ strcpy(tmp, bkm_a4t_revision);
+ printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ == ISDN_CTYPE_BKM_A4T) {
+ cs->subtyp = BKM_A4T;
+ } else
+ return (0);
+
+#if CONFIG_PCI
+#ifdef COMPAT_HAS_NEW_PCI
+ if (!pci_present()) {
+ printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
+ return (0);
+ }
+ if ((dev_a4t = pci_find_device(I20_VENDOR_ID, I20_DEVICE_ID, dev_a4t))) {
+ u_int sub_sys_id = 0;
+
+ pci_read_config_dword(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID,
+ &sub_sys_id);
+ if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) {
+ found = 1;
+ pci_memaddr = get_pcibase(dev_a4t, 0);
+ cs->irq = dev_a4t->irq;
+ }
+ }
+#else
+ for (; pci_index < 0xff; pci_index++) {
+ if (pcibios_find_device(I20_VENDOR_ID,
+ I20_DEVICE_ID,
+ pci_index,
+ &pci_bus,
+ &pci_device_fn) == PCIBIOS_SUCCESSFUL) {
+ u_int sub_sys_id = 0;
+
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_SUBSYSTEM_VENDOR_ID, &sub_sys_id);
+ if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) {
+ found = 1;
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq);
+ cs->irq = pci_irq;
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_memaddr);
+ break;
+ }
+ }
+ }
+#endif /* COMPAT_HAS_NEW_PCI */
+ if (!found) {
+ printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]);
+ return (0);
+ }
+#ifndef COMPAT_HAS_NEW_PCI
+ pci_index++;
+#endif
+ if (!cs->irq) { /* IRQ range check ?? */
+ printk(KERN_WARNING "HiSax: %s: No IRQ\n", CardType[card->typ]);
+ return (0);
+ }
+ if (!pci_memaddr) {
+ printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]);
+ return (0);
+ }
+ pci_memaddr &= PCI_BASE_ADDRESS_MEM_MASK;
+ cs->hw.ax.base = (u_int) ioremap(pci_memaddr, 4096);
+ /* Check suspecious address */
+ pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
+ if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) {
+ printk(KERN_WARNING "HiSax: %s address %x-%x suspecious\n",
+ CardType[card->typ], cs->hw.ax.base, cs->hw.ax.base + 4096);
+ iounmap((void *) cs->hw.ax.base);
+ cs->hw.ax.base = 0;
+ return (0);
+ }
+ cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET;
+ cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
+ cs->hw.ax.isac_ale = GCS_1;
+ cs->hw.ax.jade_ale = GCS_3;
+#else
+ printk(KERN_WARNING "HiSax: %s: NO_PCI_BIOS\n", CardType[card->typ]);
+ printk(KERN_WARNING "HiSax: %s: unable to configure\n", CardType[card->typ]);
+ return (0);
+#endif /* CONFIG_PCI */
+ printk(KERN_INFO "HiSax: %s: Card configured at 0x%X IRQ %d\n",
+ CardType[card->typ], cs->hw.ax.base, cs->irq);
+
+ reset_bkm(cs);
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->BC_Read_Reg = &ReadJADE;
+ cs->BC_Write_Reg = &WriteJADE;
+ cs->BC_Send_Data = &jade_fill_fifo;
+ cs->cardmsg = &BKM_card_msg;
+ cs->irq_func = &bkm_interrupt;
+ cs->irq_flags |= SA_SHIRQ;
+ ISACVersion(cs, "Telekom A4T:");
+ /* Jade version */
+ JadeVersion(cs, "Telekom A4T:");
+ return (1);
+}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
new file mode 100644
index 000000000..e32c4544a
--- /dev/null
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -0,0 +1,536 @@
+/* $Id: bkm_a8.c,v 1.7 1999/08/22 20:26:58 calle Exp $
+ * bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive)
+ * derived from the original file sedlbauer.c
+ * derived from the original file niccy.c
+ * derived from the original file netjet.c
+ *
+ * Author Roland Klabunde (R.Klabunde@Berkom.de)
+ *
+ * $Log: bkm_a8.c,v $
+ * Revision 1.7 1999/08/22 20:26:58 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.6 1999/08/11 21:01:24 keil
+ * new PCI codefix
+ *
+ * Revision 1.5 1999/08/10 16:01:48 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 1.4 1999/07/14 11:43:15 keil
+ * correct PCI_SUBSYSTEM_VENDOR_ID
+ *
+ * Revision 1.3 1999/07/12 21:04:59 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.2 1999/07/01 08:07:54 keil
+ * Initial version
+ *
+ *
+ */
+#define __NO_VERSION__
+
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "ipac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include "bkm_ax.h"
+#include <linux/pci.h>
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
+
+#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
+
+extern const char *CardType[];
+
+const char sct_quadro_revision[] = "$Revision: 1.7 $";
+
+/* To survive the startup phase */
+typedef struct {
+ u_int active; /* true/false */
+ u_int base; /* ipac base address */
+} IPAC_STATE;
+
+static IPAC_STATE ipac_state[4 + 1] __initdata =
+{
+ {0, 0}, /* dummy */
+ {0, 0}, /* SCT_1 */
+ {0, 0}, /* SCT_2 */
+ {0, 0}, /* SCT_3 */
+ {0, 0} /* SCT_4 */
+};
+
+static const char *sct_quadro_subtypes[] =
+{
+ "",
+ "#1",
+ "#2",
+ "#3",
+ "#4"
+};
+
+
+#define wordout(addr,val) outw(val,addr)
+#define wordin(addr) inw(addr)
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+ register u_char ret;
+ long flags;
+ save_flags(flags);
+ cli();
+ wordout(ale, off);
+ ret = wordin(adr) & 0xFF;
+ 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 */
+ int i;
+ wordout(ale, off);
+ for (i = 0; i < size; i++)
+ data[i] = wordin(adr) & 0xFF;
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+ long flags;
+ save_flags(flags);
+ cli();
+ wordout(ale, off);
+ wordout(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 */
+ int i;
+ wordout(ale, off);
+ for (i = 0; i < size; i++)
+ wordout(adr, data[i]);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
+}
+
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+ return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+ writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
+}
+
+/* Check whether the specified ipac is already active or not */
+static int
+is_ipac_active(u_int ipac_nr)
+{
+ return (ipac_state[ipac_nr].active);
+}
+
+/* Set the specific ipac to active */
+static void
+set_ipac_active(u_int ipac_nr, u_int active)
+{
+ /* set activation state */
+ ipac_state[ipac_nr].active = active;
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \
+ cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \
+ cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \
+ cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \
+ cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char ista, val, icnt = 5;
+ int i;
+ if (!cs) {
+ printk(KERN_WARNING "HiSax: Scitel Quadro: Spurious interrupt!\n");
+ return;
+ }
+ ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
+
+ Start_IPAC:
+ if (cs->debug & L1_DEB_IPAC)
+ debugl1(cs, "IPAC ISTA %02X", ista);
+ if (ista & 0x0f) {
+ val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, 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.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80);
+ if (val) {
+ isac_interrupt(cs, val);
+ }
+ }
+ if (ista & 0x10) {
+ val = 0x01;
+ isac_interrupt(cs, val);
+ }
+ ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
+ if ((ista & 0x3f) && icnt) {
+ icnt--;
+ goto Start_IPAC;
+ }
+ if (!icnt)
+ printk(KERN_WARNING "HiSax: %s (%s) IRQ LOOP\n",
+ CardType[cs->typ],
+ sct_quadro_subtypes[cs->subtyp]);
+ writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
+ writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
+
+ /* Read out all interrupt sources from currently not active ipacs */
+ /* "Handle" all interrupts from currently not active ipac by reading the regs */
+ for (i = SCT_1; i <= SCT_4; i++)
+ if (!is_ipac_active(i)) {
+ u_int base = ipac_state[i].base;
+ if (readreg(base, base + 4, 0xC1)) {
+ readreg(base, base + 4, 0xA0);
+ readreg(base, base + 4, 0xA4);
+ readreg(base, base + 4, 0x20);
+ readreg(base, base + 4, 0x24);
+ readreg(base, base + 4, 0x60);
+ readreg(base, base + 4, 0x64);
+ readreg(base, base + 4, 0xC1);
+ readreg(base, base + 4, ISAC_CIR0 + 0x80);
+ }
+ }
+}
+
+
+void
+release_io_sct_quadro(struct IsdnCardState *cs)
+{
+ /* ?? */
+}
+
+static void
+enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
+{
+ if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
+ if (bEnable)
+ wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
+ else
+ /* Issue general di only if no ipac is active */
+ if (!is_ipac_active(SCT_1) &&
+ !is_ipac_active(SCT_2) &&
+ !is_ipac_active(SCT_3) &&
+ !is_ipac_active(SCT_4))
+ wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
+ }
+}
+
+static void
+reset_bkm(struct IsdnCardState *cs)
+{
+ long flags;
+
+ if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
+ if (!is_ipac_active(SCT_1) &&
+ !is_ipac_active(SCT_2) &&
+ !is_ipac_active(SCT_3) &&
+ !is_ipac_active(SCT_4)) {
+ /* Issue total reset only if no ipac is active */
+ wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
+
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((10 * HZ) / 1000);
+
+ /* Remove the soft reset */
+ wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((10 * HZ) / 1000);
+ restore_flags(flags);
+ }
+ }
+}
+
+static int
+BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ /* Disable ints */
+ set_ipac_active(cs->subtyp, 0);
+ enable_bkm_int(cs, 0);
+ reset_bkm(cs);
+ return (0);
+ case CARD_RELEASE:
+ /* Sanity */
+ set_ipac_active(cs->subtyp, 0);
+ enable_bkm_int(cs, 0);
+ reset_bkm(cs);
+ release_io_sct_quadro(cs);
+ return (0);
+ case CARD_INIT:
+ cs->debug |= L1_DEB_IPAC;
+ set_ipac_active(cs->subtyp, 1);
+ inithscxisac(cs, 3);
+ /* Enable ints */
+ enable_bkm_int(cs, 1);
+ return (0);
+ case CARD_TEST:
+ return (0);
+ }
+ return (0);
+}
+
+#ifdef COMPAT_HAS_NEW_PCI
+static struct pci_dev *dev_a8 __initdata = NULL;
+#else
+static int pci_index __initdata = 0;
+#endif
+
+int __init
+ setup_sct_quadro(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+#if CONFIG_PCI
+ u_char pci_bus = 0, pci_device_fn = 0, pci_irq = 0, pci_rev_id;
+ u_int found = 0;
+ u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
+#endif
+
+ strcpy(tmp, sct_quadro_revision);
+ printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
+ cs->subtyp = SCT_1; /* Preset */
+ } else
+ return (0);
+
+ /* Identify subtype by para[0] */
+ if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
+ cs->subtyp = card->para[0];
+ else
+ printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n",
+ CardType[card->typ]);
+#if CONFIG_PCI
+#ifdef COMPAT_HAS_NEW_PCI
+ if (!pci_present()) {
+ printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
+ return (0);
+ }
+ if ((dev_a8 = pci_find_device(PLX_VENDOR_ID, PLX_DEVICE_ID, dev_a8))) {
+ u_int sub_sys_id = 0;
+
+ pci_read_config_dword(dev_a8, PCI_SUBSYSTEM_VENDOR_ID,
+ &sub_sys_id);
+ if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) {
+ found = 1;
+ pci_ioaddr1 = get_pcibase(dev_a8, 1);
+ pci_irq = dev_a8->irq;
+ pci_bus = dev_a8->bus->number;
+ pci_device_fn = dev_a8->devfn;
+ }
+ }
+#else
+ for (; pci_index < 0xff; pci_index++) {
+ if (pcibios_find_device(
+ PLX_VENDOR_ID,
+ PLX_DEVICE_ID,
+ pci_index,
+ &pci_bus,
+ &pci_device_fn) == PCIBIOS_SUCCESSFUL) {
+
+ u_int sub_sys_id = 0;
+
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_SUBSYSTEM_VENDOR_ID, &sub_sys_id);
+ if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) {
+ found = 1;
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, &pci_ioaddr1);
+ cs->irq = pci_irq;
+ break;
+ }
+ }
+ }
+#endif /* COMPAT_HAS_NEW_PCI */
+ if (!found) {
+ printk(KERN_WARNING "HiSax: %s (%s): Card not found\n",
+ CardType[card->typ],
+ sct_quadro_subtypes[cs->subtyp]);
+ return (0);
+ }
+#ifndef COMPAT_HAS_NEW_PCI
+ pci_index++; /* need for more as one card */
+#endif
+ if (!pci_irq) { /* IRQ range check ?? */
+ printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n",
+ CardType[card->typ],
+ sct_quadro_subtypes[cs->subtyp]);
+ return (0);
+ }
+#ifdef ATTEMPT_PCI_REMAPPING
+/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
+ pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_REVISION_ID, &pci_rev_id);
+ if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) {
+ printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n",
+ CardType[card->typ],
+ sct_quadro_subtypes[cs->subtyp]);
+ /* Restart PCI negotiation */
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, (u_int) - 1);
+ /* Move up by 0x80 byte */
+ pci_ioaddr1 += 0x80;
+ pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, pci_ioaddr1);
+#ifdef COMPAT_HAS_NEW_PCI
+ get_pcibase(dev_a8, 1) = pci_ioaddr1;
+#endif /* COMPAT_HAS_NEW_PCI */
+ }
+/* End HACK */
+#endif
+ pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
+ pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
+ pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
+ pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_4, &pci_ioaddr4);
+ pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_5, &pci_ioaddr5);
+ if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) {
+ printk(KERN_WARNING "HiSax: %s (%s): No IO base address(es)\n",
+ CardType[card->typ],
+ sct_quadro_subtypes[cs->subtyp]);
+ return (0);
+ }
+ pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
+ pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK;
+ pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK;
+ pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK;
+ pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK;
+ /* Take over */
+ cs->irq = pci_irq;
+ cs->irq_flags |= SA_SHIRQ;
+ /* pci_ioaddr1 is unique to all subdevices */
+ /* pci_ioaddr2 is for the fourth subdevice only */
+ /* pci_ioaddr3 is for the third subdevice only */
+ /* pci_ioaddr4 is for the second subdevice only */
+ /* pci_ioaddr5 is for the first subdevice only */
+ cs->hw.ax.plx_adr = pci_ioaddr1;
+ /* Enter all ipac_base addresses */
+ ipac_state[SCT_1].base = pci_ioaddr5 + 0x00;
+ ipac_state[SCT_2].base = pci_ioaddr4 + 0x08;
+ ipac_state[SCT_3].base = pci_ioaddr3 + 0x10;
+ ipac_state[SCT_4].base = pci_ioaddr2 + 0x20;
+ /* For isac and hscx control path */
+ cs->hw.ax.base = ipac_state[cs->subtyp].base;
+ /* For isac and hscx data path */
+ cs->hw.ax.data_adr = cs->hw.ax.base + 4;
+#else
+ printk(KERN_WARNING "HiSax: %s (%s): NO_PCI_BIOS\n",
+ CardType[card->typ],
+ sct_quadro_subtypes[cs->subtyp]);
+ printk(KERN_WARNING "HiSax: %s (%s): Unable to configure\n",
+ CardType[card->typ],
+ sct_quadro_subtypes[cs->subtyp]);
+ return (0);
+#endif /* CONFIG_PCI */
+ printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4X, 0x%.4X, 0x%.4X and IRQ %d\n",
+ CardType[card->typ],
+ sct_quadro_subtypes[cs->subtyp],
+ cs->hw.ax.plx_adr,
+ cs->hw.ax.base,
+ cs->hw.ax.data_adr,
+ cs->irq);
+
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+
+ /* Disable all currently not active ipacs */
+ if (!is_ipac_active(SCT_1))
+ set_ipac_active(SCT_1, 0);
+ if (!is_ipac_active(SCT_2))
+ set_ipac_active(SCT_2, 0);
+ if (!is_ipac_active(SCT_3))
+ set_ipac_active(SCT_3, 0);
+ if (!is_ipac_active(SCT_4))
+ set_ipac_active(SCT_4, 0);
+
+ /* Perfom general reset (if possible) */
+ reset_bkm(cs);
+
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+
+ cs->BC_Read_Reg = &ReadHSCX;
+ cs->BC_Write_Reg = &WriteHSCX;
+ cs->BC_Send_Data = &hscx_fill_fifo;
+ cs->cardmsg = &BKM_card_msg;
+ cs->irq_func = &bkm_interrupt_ipac;
+
+ printk(KERN_INFO "HiSax: %s (%s): IPAC Version %d\n",
+ CardType[card->typ],
+ sct_quadro_subtypes[cs->subtyp],
+ readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
+ return (1);
+}
diff --git a/drivers/isdn/hisax/bkm_ax.h b/drivers/isdn/hisax/bkm_ax.h
new file mode 100644
index 000000000..e2d5fa70e
--- /dev/null
+++ b/drivers/isdn/hisax/bkm_ax.h
@@ -0,0 +1,133 @@
+/* $Id: bkm_ax.h,v 1.2 1999/07/01 08:07:55 keil Exp $
+ * bkm_ax.h low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive)
+ *
+ * Author Roland Klabunde (R.Klabunde@Berkom.de)
+ *
+ * $Log: bkm_ax.h,v $
+ * Revision 1.2 1999/07/01 08:07:55 keil
+ * Initial version
+ *
+ *
+ *
+ */
+
+#ifndef __BKM_AX_H__
+#define __BKM_AX_H__
+
+/* Supported boards (subtypes) */
+#define SCT_1 1
+#define SCT_2 2
+#define SCT_3 3
+#define SCT_4 4
+#define BKM_A4T 5
+
+
+/* A4T */
+#define I20_DEVICE_ID 0x6120 /* I20 PCI device ID */
+#define I20_VENDOR_ID 0x11DE /* I20 PCI vendor ID */
+#define A4T_SUBVEN_ID 0x0871
+#define A4T_SUBSYS_ID 0xFFA4
+/* Scitel Quadro */
+#define PLX_DEVICE_ID 0x9050 /* Scitel Quadro PLX */
+#define PLX_VENDOR_ID 0x10B5
+#define SCT_SUBVEN_ID 0x0871
+#define SCT_SUBSYS_ID 0xFFA8
+
+
+#define PLX_ADDR_PLX 0x14 /* Addr PLX configuration */
+#define PLX_ADDR_ISAC 0x18 /* Addr ISAC */
+#define PLX_ADDR_HSCX 0x1C /* Addr HSCX */
+#define PLX_ADDR_ALE 0x20 /* Addr ALE */
+#define PLX_ADDR_ALEPLUS 0x24 /* Next Addr behind ALE */
+
+#define PLX_SUBVEN 0x2C /* Offset SubVendor */
+#define PLX_SUBSYS 0x2E /* Offset SubSystem */
+
+
+/* Application specific registers I20 (Siemens SZB6120H) */
+typedef struct {
+ /* Video front end horizontal configuration register */
+ volatile u_int i20VFEHorzCfg; /* Offset 00 */
+ /* Video front end vertical configuration register */
+ volatile u_int i20VFEVertCfg; /* Offset 04 */
+ /* Video front end scaler and pixel format register */
+ volatile u_int i20VFEScaler; /* Offset 08 */
+ /* Video display top register */
+ volatile u_int i20VDispTop; /* Offset 0C */
+ /* Video display bottom register */
+ volatile u_int i20VDispBottom; /* Offset 10 */
+ /* Video stride, status and frame grab register */
+ volatile u_int i20VidFrameGrab;/* Offset 14 */
+ /* Video display configuration register */
+ volatile u_int i20VDispCfg; /* Offset 18 */
+ /* Video masking map top */
+ volatile u_int i20VMaskTop; /* Offset 1C */
+ /* Video masking map bottom */
+ volatile u_int i20VMaskBottom; /* Offset 20 */
+ /* Overlay control register */
+ volatile u_int i20OvlyControl; /* Offset 24 */
+ /* System, PCI and general purpose pins control register */
+ volatile u_int i20SysControl; /* Offset 28 */
+#define sysRESET 0x01000000 /* bit 24:Softreset (Low) */
+ /* GPIO 4...0: Output fixed for our cfg! */
+#define sysCFG 0x000000E0 /* GPIO 7,6,5: Input */
+ /* General purpose pins and guest bus control register */
+ volatile u_int i20GuestControl;/* Offset 2C */
+#define guestWAIT_CFG 0x00005555 /* 4 PCI waits for all */
+#define guestISDN_INT_E 0x01000000 /* ISDN Int en (low) */
+#define guestVID_INT_E 0x02000000 /* Video interrupt en (low) */
+#define guestADI1_INT_R 0x04000000 /* ADI #1 int req (low) */
+#define guestADI2_INT_R 0x08000000 /* ADI #2 int req (low) */
+#define guestISDN_RES 0x10000000 /* ISDN reset bit (high) */
+#define guestADI1_INT_S 0x20000000 /* ADI #1 int pending (low) */
+#define guestADI2_INT_S 0x40000000 /* ADI #2 int pending (low) */
+#define guestISDN_INT_S 0x80000000 /* ISAC int pending (low) */
+
+#define g_A4T_JADE_RES 0x01000000 /* JADE Reset (High) */
+#define g_A4T_ISAR_RES 0x02000000 /* ISAR Reset (High) */
+#define g_A4T_ISAC_RES 0x04000000 /* ISAC Reset (High) */
+#define g_A4T_JADE_BOOTR 0x08000000 /* JADE enable boot SRAM (Low) NOT USED */
+#define g_A4T_ISAR_BOOTR 0x10000000 /* ISAR enable boot SRAM (Low) NOT USED */
+#define g_A4T_JADE_INT_S 0x20000000 /* JADE interrupt pnd (Low) */
+#define g_A4T_ISAR_INT_S 0x40000000 /* ISAR interrupt pnd (Low) */
+#define g_A4T_ISAC_INT_S 0x80000000 /* ISAC interrupt pnd (Low) */
+
+ volatile u_int i20CodeSource; /* Offset 30 */
+ volatile u_int i20CodeXferCtrl;/* Offset 34 */
+ volatile u_int i20CodeMemPtr; /* Offset 38 */
+
+ volatile u_int i20IntStatus; /* Offset 3C */
+ volatile u_int i20IntCtrl; /* Offset 40 */
+#define intISDN 0x40000000 /* GIRQ1En (ISAC/ADI) (High) */
+#define intVID 0x20000000 /* GIRQ0En (VSYNC) (High) */
+#define intCOD 0x10000000 /* CodRepIrqEn (High) */
+#define intPCI 0x01000000 /* PCI IntA enable (High) */
+
+ volatile u_int i20I2CCtrl; /* Offset 44 */
+} I20_REGISTER_FILE, *PI20_REGISTER_FILE;
+
+/*
+ * Postoffice structure for A4T
+ *
+ */
+#define PO_OFFSET 0x00000200 /* Postoffice offset from base */
+
+#define GCS_0 0x00000000 /* Guest bus chip selects */
+#define GCS_1 0x00100000
+#define GCS_2 0x00200000
+#define GCS_3 0x00300000
+
+#define PO_READ 0x00000000 /* R/W from/to guest bus */
+#define PO_WRITE 0x00800000
+
+#define PO_PEND 0x02000000
+
+#define POSTOFFICE(postoffice) *(volatile unsigned int*)(postoffice)
+
+/* Wait unlimited (don't worry) */
+#define __WAITI20__(postoffice) \
+do { \
+ while ((POSTOFFICE(postoffice) & PO_PEND)) ; \
+} while (0)
+
+#endif /* __BKM_AX_H__ */
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index bf09acd20..ce0428a46 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.25 1999/01/02 11:17:20 keil Exp $
+/* $Id: callc.c,v 2.34 1999/08/25 20:02:34 werner Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -11,6 +11,39 @@
* Fritz Elfert
*
* $Log: callc.c,v $
+ * Revision 2.34 1999/08/25 20:02:34 werner
+ * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts
+ * with existing software definitions. (PtP incomplete called party number)
+ *
+ * Revision 2.33 1999/08/25 17:00:09 keil
+ * Make ISAR V32bis modem running
+ * Make LL->HL interface open for additional commands
+ *
+ * Revision 2.32 1999/08/22 20:27:01 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 2.31 1999/08/05 20:43:10 keil
+ * ISAR analog modem support
+ *
+ * Revision 2.30 1999/07/25 16:24:04 keil
+ * Fixed TEI now working again
+ *
+ * Revision 2.29 1999/07/13 21:05:41 werner
+ * Modified set_channel_limit to use new callback ISDN_STAT_DISCH.
+ *
+ * Revision 2.28 1999/07/09 08:30:02 keil
+ * cosmetics
+ *
+ * Revision 2.27 1999/07/05 23:51:38 werner
+ * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl
+ * hisaxctrl id 10 <nr. of chans 0-2>
+ *
+ * Revision 2.26 1999/07/01 08:11:21 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.25 1999/01/02 11:17:20 keil
* Changes for 2.2
*
@@ -112,10 +145,15 @@
#include "../avmb1/capicmd.h" /* this should be moved in a common place */
#ifdef MODULE
+#ifdef COMPAT_HAS_NEW_SYMTAB
#define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
-#endif /* MODULE */
+#else
+extern long mod_use_count_;
+#define MOD_USE_COUNT mod_use_count_
+#endif /* COMPAT_HAS_NEW_SYMTAB */
+#endif /* MODULE */
-const char *lli_revision = "$Revision: 2.25 $";
+const char *lli_revision = "$Revision: 2.34 $";
extern struct IsdnCard cards[];
extern int nrcards;
@@ -146,28 +184,7 @@ static int chancount = 0;
/* 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
-#define FLG_RESUME 16
-
-/*
- * Because of callback it's a good idea to delay the shutdown of the d-channel
- */
-#define DREL_TIMER_VALUE 40000
+#define FLG_START_B 0
/*
* Find card with given driverId
@@ -192,7 +209,7 @@ discard_queue(struct sk_buff_head *q)
int ret=0;
while ((skb = skb_dequeue(q))) {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
ret++;
}
return(ret);
@@ -211,44 +228,40 @@ link_debug(struct Channel *chanp, int direction, char *fmt, ...)
va_end(args);
}
-
enum {
- ST_NULL, /* 0 inactive */
- ST_OUT_WAIT_D, /* 1 outgoing, awaiting d-channel establishment */
- ST_IN_WAIT_D, /* 2 incoming, awaiting d-channel establishment */
- ST_OUT_DIAL, /* 3 outgoing, SETUP send; awaiting confirm */
- ST_IN_WAIT_LL, /* 4 incoming call received; wait for LL confirm */
- ST_IN_ALERT_SEND, /* 5 incoming call received; ALERT send */
- ST_IN_WAIT_CONN_ACK, /* 6 incoming CONNECT send; awaiting CONN_ACK */
- ST_WAIT_BCONN, /* 7 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */
- ST_ACTIVE, /* 8 active, b channel prot. established */
- ST_WAIT_BRELEASE, /* 9 call clear. (initiator), awaiting b channel prot. rel. */
- ST_WAIT_BREL_DISC, /* 10 call clear. (receiver), DISCONNECT req. received */
- ST_WAIT_DCOMMAND, /* 11 call clear. (receiver), awaiting DCHANNEL message */
- ST_WAIT_DRELEASE, /* 12 DISCONNECT sent, awaiting RELEASE */
- ST_WAIT_D_REL_CNF, /* 13 RELEASE sent, awaiting RELEASE confirm */
- ST_WAIT_DSHUTDOWN, /* 14 awaiting d-channel shutdown */
+ ST_NULL, /* 0 inactive */
+ ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */
+ ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */
+ ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */
+ ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */
+ ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */
+ ST_ACTIVE, /* 6 active, b channel prot. established */
+ ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */
+ ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */
+ ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */
+ ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */
+ ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */
+ ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */
};
-
-#define STATE_COUNT (ST_WAIT_DSHUTDOWN +1)
-
-static char *strState[] =
-{
- "ST_NULL",
- "ST_OUT_WAIT_D",
- "ST_IN_WAIT_D",
- "ST_OUT_DIAL",
- "ST_IN_WAIT_LL",
- "ST_IN_ALERT_SEND",
- "ST_IN_WAIT_CONN_ACK",
- "ST_WAIT_BCONN",
- "ST_ACTIVE",
+
+
+#define STATE_COUNT (ST_IN_PROCEED_SEND + 1)
+
+ static char *strState[] =
+ {
+ "ST_NULL",
+ "ST_OUT_DIAL",
+ "ST_IN_WAIT_LL",
+ "ST_IN_ALERT_SENT",
+ "ST_IN_WAIT_CONN_ACK",
+ "ST_WAIT_BCONN",
+ "ST_ACTIVE",
"ST_WAIT_BRELEASE",
"ST_WAIT_BREL_DISC",
"ST_WAIT_DCOMMAND",
"ST_WAIT_DRELEASE",
"ST_WAIT_D_REL_CNF",
- "ST_WAIT_DSHUTDOWN",
+ "ST_IN_PROCEED_SEND",
};
enum {
@@ -256,29 +269,28 @@ enum {
EV_SETUP_CNF, /* 1 */
EV_ACCEPTB, /* 2 */
EV_DISCONNECT_IND, /* 3 */
- EV_RELEASE_CNF, /* 4 */
- EV_DLEST, /* 5 */
- EV_DLRL, /* 6 */
+ EV_RELEASE, /* 4 */
+ EV_LEASED, /* 5 */
+ EV_LEASED_REL, /* 6 */
EV_SETUP_IND, /* 7 */
- EV_RELEASE_IND, /* 8 */
- EV_ACCEPTD, /* 9 */
- EV_SETUP_CMPL_IND, /* 10 */
- EV_BC_EST, /* 11 */
- EV_WRITEBUF, /* 12 */
- EV_ESTABLISH, /* 13 */
- EV_HANGUP, /* 14 */
- EV_BC_REL, /* 15 */
- EV_CINF, /* 16 */
- EV_SUSPEND, /* 17 */
- EV_RESUME, /* 18 */
- EV_SHUTDOWN_D, /* 19 */
- EV_NOSETUP_RSP, /* 20 */
- EV_SETUP_ERR, /* 21 */
- EV_CONNECT_ERR, /* 22 */
- EV_RELEASE_ERR, /* 23 */
+ EV_ACCEPTD, /* 8 */
+ EV_SETUP_CMPL_IND, /* 9 */
+ EV_BC_EST, /* 10 */
+ EV_WRITEBUF, /* 11 */
+ EV_HANGUP, /* 12 */
+ EV_BC_REL, /* 13 */
+ EV_CINF, /* 14 */
+ EV_SUSPEND, /* 15 */
+ EV_RESUME, /* 16 */
+ EV_NOSETUP_RSP, /* 17 */
+ EV_SETUP_ERR, /* 18 */
+ EV_CONNECT_ERR, /* 19 */
+ EV_PROCEED, /* 20 */
+ EV_ALERT, /* 21 */
+ EV_REDIR, /* 22 */
};
-#define EVENT_COUNT (EV_RELEASE_ERR +1)
+#define EVENT_COUNT (EV_REDIR + 1)
static char *strEvent[] =
{
@@ -286,150 +298,152 @@ static char *strEvent[] =
"EV_SETUP_CNF",
"EV_ACCEPTB",
"EV_DISCONNECT_IND",
- "EV_RELEASE_CNF",
- "EV_DLEST",
- "EV_DLRL",
+ "EV_RELEASE",
+ "EV_LEASED",
+ "EV_LEASED_REL",
"EV_SETUP_IND",
- "EV_RELEASE_IND",
"EV_ACCEPTD",
"EV_SETUP_CMPL_IND",
"EV_BC_EST",
"EV_WRITEBUF",
- "EV_ESTABLISH",
"EV_HANGUP",
"EV_BC_REL",
"EV_CINF",
"EV_SUSPEND",
"EV_RESUME",
- "EV_SHUTDOWN_D",
"EV_NOSETUP_RSP",
"EV_SETUP_ERR",
"EV_CONNECT_ERR",
- "EV_RELEASE_ERR",
+ "EV_PROCEED",
+ "EV_ALERT",
+ "EV_REDIR",
};
+
+static inline void
+HL_LL(struct Channel *chanp, int command)
+{
+ isdn_ctrl ic;
+
+ ic.driver = chanp->cs->myid;
+ ic.command = command;
+ ic.arg = chanp->chan;
+ chanp->cs->iif.statcallb(&ic);
+}
+
static inline void
-lli_deliver_cause(struct Channel *chanp, isdn_ctrl *ic)
+lli_deliver_cause(struct Channel *chanp)
{
- if (chanp->proc->para.cause < 0)
+ isdn_ctrl ic;
+
+ if (chanp->proc->para.cause == NO_CAUSE)
return;
- ic->driver = chanp->cs->myid;
- ic->command = ISDN_STAT_CAUSE;
- ic->arg = chanp->chan;
+ ic.driver = chanp->cs->myid;
+ ic.command = ISDN_STAT_CAUSE;
+ ic.arg = chanp->chan;
if (chanp->cs->protocol == ISDN_PTYPE_EURO)
- sprintf(ic->parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f,
+ 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->proc->para.loc & 0x7f,
+ sprintf(ic.parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f,
chanp->proc->para.cause & 0x7f);
- chanp->cs->iif.statcallb(ic);
+ chanp->cs->iif.statcallb(&ic);
}
-static void
-lli_d_established(struct FsmInst *fi, int event, void *arg)
+static inline void
+lli_close(struct FsmInst *fi)
{
- struct Channel *chanp = fi->userdata;
-
- test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
- if (chanp->leased) {
- isdn_ctrl ic;
- int ret;
+ struct Channel *chanp = fi->userdata;
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
- FsmChangeState(fi, ST_IN_WAIT_LL);
- test_and_set_bit(FLG_CALL_REC, &chanp->Flags);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_ICALL_LEASED");
- 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)
- link_debug(chanp, 1, "statcallb ret=%d", ret);
- if (!ret) {
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
- FsmChangeState(fi, ST_NULL);
- }
- } else if (fi->state == ST_WAIT_DSHUTDOWN)
- FsmChangeState(fi, ST_NULL);
+ FsmChangeState(fi, ST_NULL);
+ chanp->Flags = 0;
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
}
-static void
-lli_d_released(struct FsmInst *fi, int event, void *arg)
+ static void
+lli_leased_in(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
-
- test_and_clear_bit(FLG_START_D, &chanp->Flags);
+ struct Channel *chanp = fi->userdata;
+
+ isdn_ctrl ic;
+ int ret;
+
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
+ FsmChangeState(fi, ST_IN_WAIT_LL);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_ICALL_LEASED");
+ ic.driver = chanp->cs->myid;
+ ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW);
+ 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)
+ link_debug(chanp, 1, "statcallb ret=%d", ret);
+
+ if (!ret) {
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
+ FsmChangeState(fi, ST_NULL);
+ }
}
+
/*
* Dial out
*/
static void
+lli_init_bchan_out(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_WAIT_BCONN);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_DCONN");
+ HL_LL(chanp, ISDN_STAT_DCONN);
+ init_b_st(chanp, 0);
+ chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
+}
+
+static void
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;
- if (test_bit(FLG_ESTAB_D, &chanp->Flags)) {
- FsmEvent(fi, EV_DLEST, NULL);
- } else {
- chanp->Flags = 0;
- if (EV_RESUME == event)
- test_and_set_bit(FLG_RESUME, &chanp->Flags);
- test_and_set_bit(FLG_START_D, &chanp->Flags);
- chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
- }
-}
-static void
-lli_do_dialout(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- int ev;
-
- FsmChangeState(fi, ST_OUT_DIAL);
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
- if (test_and_clear_bit(FLG_RESUME, &chanp->Flags))
- ev = CC_RESUME | REQUEST;
- else
- ev = CC_SETUP | REQUEST;
- if (chanp->leased) {
- FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
- } else {
- test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
- chanp->d_st->lli.l4l3(chanp->d_st, ev, chanp);
- test_and_set_bit(FLG_CALL_SEND, &chanp->Flags);
- }
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
+ if (chanp->leased) {
+ lli_init_bchan_out(fi, event, arg);
+ } else {
+ FsmChangeState(fi, ST_OUT_DIAL);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp);
+ }
}
static void
-lli_init_bchan_out(struct FsmInst *fi, int event, void *arg)
+lli_resume(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
- FsmChangeState(fi, ST_WAIT_BCONN);
- test_and_set_bit(FLG_LL_DCONN, &chanp->Flags);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DCONN");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_DCONN;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- init_b_st(chanp, 0);
- test_and_set_bit(FLG_START_B, &chanp->Flags);
- chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
+ FsmDelTimer(&chanp->drel_timer, 60);
+ FsmDelTimer(&chanp->dial_timer, 73);
+ chanp->l2_active_protocol = chanp->l2_protocol;
+ chanp->incoming = 0;
+
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
+ if (chanp->leased) {
+ lli_init_bchan_out(fi, event, arg);
+ } else {
+ FsmChangeState(fi, ST_OUT_DIAL);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp);
+ }
}
static void
@@ -438,12 +452,15 @@ 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;
- test_and_set_bit(FLG_CONNECT_B, &chanp->Flags);
+ if (chanp->bcs->conmsg)
+ strcpy(ic.parm.num, chanp->bcs->conmsg);
+ else
+ ic.parm.num[0] = 0;
if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BCONN");
- test_and_set_bit(FLG_LL_BCONN, &chanp->Flags);
+ link_debug(chanp, 0, "STAT_BCONN %s", ic.parm.num);
ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BCONN;
ic.arg = chanp->chan;
@@ -451,6 +468,7 @@ lli_go_active(struct FsmInst *fi, int event, void *arg)
chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan);
}
+
/*
* RESUME
*/
@@ -458,27 +476,6 @@ lli_go_active(struct FsmInst *fi, int event, void *arg)
/* incomming call */
static void
-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 (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 if (!test_and_set_bit(FLG_START_D, &chanp->Flags))
- chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
-}
-
-static void
lli_deliver_call(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
@@ -493,11 +490,11 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
*/
if (1) { /* for only one TEI */
FsmChangeState(fi, ST_IN_WAIT_LL);
- test_and_set_bit(FLG_CALL_REC, &chanp->Flags);
if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_ICALL");
+ link_debug(chanp, 0, (chanp->chan < 2) ? "STAT_ICALL" : "STAT_ICALLW");
ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_ICALL;
+ ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW);
+
ic.arg = chanp->chan;
/*
* No need to return "unknown" for calls without OAD,
@@ -507,118 +504,95 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
ret = chanp->cs->iif.statcallb(&ic);
if (chanp->debug & 1)
link_debug(chanp, 1, "statcallb ret=%d", ret);
+
switch (ret) {
- case 1: /* OK, anybody likes this call */
+ case 1: /* OK, someone likes this call */
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 | REQUEST, 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);
- chanp->d_st->lli.l4l3(chanp->d_st,
- DL_ESTABLISH | REQUEST, NULL);
- }
+ FsmChangeState(fi, ST_IN_ALERT_SENT);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+ break;
+ case 5: /* direct redirect */
+ case 4: /* Proceeding desired */
+ FsmDelTimer(&chanp->drel_timer, 61);
+ FsmChangeState(fi, ST_IN_PROCEED_SEND);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
+ if (ret == 5)
+ { chanp->setup = ic.parm.setup;
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
+ }
break;
case 2: /* Rejecting Call */
- test_and_clear_bit(FLG_CALL_REC, &chanp->Flags);
break;
case 0: /* OK, nobody likes this call */
default: /* statcallb problems */
chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
FsmChangeState(fi, ST_NULL);
- if (test_bit(FLG_ESTAB_D, &chanp->Flags) &&
- !test_bit(FLG_PTP, &chanp->d_st->l2.flag))
- FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61);
break;
}
} else {
chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
- FsmChangeState(fi, ST_NULL);
- if (test_bit(FLG_ESTAB_D, &chanp->Flags) &&
- !test_bit(FLG_PTP, &chanp->d_st->l2.flag))
- FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62);
}
}
static void
-lli_establish_d(struct FsmInst *fi, int event, void *arg)
+lli_send_dconnect(struct FsmInst *fi, int event, void *arg)
{
- /* This establish the D-channel for pending L3 messages
- * without blocking the 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);
- chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
+ FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
}
static void
-lli_do_action(struct FsmInst *fi, int event, void *arg)
+lli_send_alert(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 | RESPONSE, 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 | REQUEST, 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 | REQUEST, chanp->proc);
- test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
- }
+ FsmChangeState(fi, ST_IN_ALERT_SENT);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
}
static void
-lli_send_dconnect(struct FsmInst *fi, int event, void *arg)
+lli_send_redir(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
- chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
}
static void
lli_init_bchan_in(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
FsmChangeState(fi, ST_WAIT_BCONN);
- test_and_set_bit(FLG_LL_DCONN, &chanp->Flags);
if (chanp->debug & 1)
link_debug(chanp, 0, "STAT_DCONN");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_DCONN;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
+ HL_LL(chanp, ISDN_STAT_DCONN);
chanp->l2_active_protocol = chanp->l2_protocol;
chanp->incoming = !0;
init_b_st(chanp, !0);
- test_and_set_bit(FLG_START_B, &chanp->Flags);
chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
}
+static void
+lli_setup_rsp(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ if (chanp->leased) {
+ lli_init_bchan_in(fi, event, arg);
+ } else {
+ FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
+#ifdef WANT_ALERT
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+#endif
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
+ }
+}
+
/* Call suspend */
static void
@@ -632,82 +606,52 @@ lli_suspend(struct FsmInst *fi, int event, void *arg)
/* Call clearing */
static void
-lli_cancel_call(struct FsmInst *fi, int event, void *arg)
+lli_disconnect_req(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
FsmChangeState(fi, ST_WAIT_DRELEASE);
- if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_BHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- }
- if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
- release_b_st(chanp);
- chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
+ chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
- test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
}
static void
-lli_shutdown_d(struct FsmInst *fi, int event, void *arg)
+lli_disconnect_reject(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- FsmDelTimer(&chanp->drel_timer, 62);
- if (test_bit(FLG_PTP, &chanp->d_st->l2.flag)) {
- 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);
- chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL);
- }
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
+ chanp->proc->para.cause = 0x15; /* Call Rejected */
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
}
static void
-lli_timeout_d(struct FsmInst *fi, int event, void *arg)
+lli_dhup_close(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- lli_deliver_cause(chanp, &ic);
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- FsmChangeState(fi, ST_NULL);
- chanp->Flags = 0;
- test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
- if (!test_bit(FLG_PTP, &chanp->d_st->l2.flag))
- FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60);
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
+ struct Channel *chanp = fi->userdata;
+
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_DHUP");
+ lli_deliver_cause(chanp);
+ HL_LL(chanp, ISDN_STAT_DHUP);
+
+ lli_close(fi);
}
static void
-lli_go_null(struct FsmInst *fi, int event, void *arg)
+lli_reject_req(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 *) (long)chanp->chan);
+ struct Channel *chanp = fi->userdata;
+
+#ifndef ALERT_REJECT
+ chanp->proc->para.cause = 0x15; /* Call Rejected */
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
+ lli_dhup_close(fi, event, arg);
+#else
+ FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63);
+ FsmChangeState(fi, ST_IN_ALERT_SENT);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc);
+#endif
}
static void
@@ -717,30 +661,15 @@ lli_disconn_bchan(struct FsmInst *fi, int event, void *arg)
chanp->data_open = 0;
FsmChangeState(fi, ST_WAIT_BRELEASE);
- test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags);
chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
}
static void
-lli_send_d_disc(struct FsmInst *fi, int event, void *arg)
+lli_start_disc(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
isdn_ctrl ic;
- if (test_bit(FLG_DISC_REC, &chanp->Flags) ||
- test_bit(FLG_REL_REC, &chanp->Flags))
- return;
- FsmChangeState(fi, ST_WAIT_DRELEASE);
- if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_BHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- }
- 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;
@@ -748,43 +677,46 @@ lli_send_d_disc(struct FsmInst *fi, int event, void *arg)
chanp->cs->iif.statcallb(&ic);
if (chanp->debug & 1)
link_debug(chanp, 0, "STAT_DHUP");
- 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);
- chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL);
+ HL_LL(chanp, ISDN_STAT_DHUP);
+ lli_close(fi);
} 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 | REQUEST, chanp->proc);
- test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
+ lli_disconnect_req(fi, event, arg);
}
}
static void
-lli_released_bchan(struct FsmInst *fi, int event, void *arg)
+lli_rel_b_disc(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
+ struct Channel *chanp = fi->userdata;
+
+ release_b_st(chanp);
+ lli_start_disc(fi, event, arg);
+}
- FsmChangeState(fi, ST_WAIT_DCOMMAND);
- chanp->data_open = 0;
- if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_BHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- }
- release_b_st(chanp);
- test_and_clear_bit(FLG_START_B, &chanp->Flags);
+static void
+lli_bhup_disc(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+
+ lli_rel_b_disc(fi, event, arg);
}
+static void
+lli_bhup_rel_b(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_WAIT_DCOMMAND);
+ chanp->data_open = 0;
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+ release_b_st(chanp);
+}
static void
lli_release_bchan(struct FsmInst *fi, int event, void *arg)
@@ -792,117 +724,74 @@ lli_release_bchan(struct FsmInst *fi, int event, void *arg)
struct Channel *chanp = fi->userdata;
chanp->data_open = 0;
- test_and_set_bit(FLG_DISC_REC, &chanp->Flags);
FsmChangeState(fi, ST_WAIT_BREL_DISC);
- test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags);
chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
}
+
static void
-lli_received_d_rel(struct FsmInst *fi, int event, void *arg)
+lli_rel_b_dhup(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
+ struct Channel *chanp = fi->userdata;
- chanp->data_open = 0;
- FsmChangeState(fi, ST_NULL);
- test_and_set_bit(FLG_REL_REC, &chanp->Flags);
- if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
- }
- if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_BHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- }
- if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
- release_b_st(chanp);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- lli_deliver_cause(chanp, &ic);
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- 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);
+ release_b_st(chanp);
+ lli_dhup_close(fi, event, arg);
}
static void
-lli_received_d_relcnf(struct FsmInst *fi, int event, void *arg)
+lli_bhup_dhup(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
+ struct Channel *chanp = fi->userdata;
- chanp->data_open = 0;
- FsmChangeState(fi, ST_NULL);
- if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
- }
- if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_BHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- }
- if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
- release_b_st(chanp);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- lli_deliver_cause(chanp, &ic);
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- 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);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+
+ lli_rel_b_dhup(fi, event, arg);
}
static void
-lli_received_d_disc(struct FsmInst *fi, int event, void *arg)
+lli_abort(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
+ struct Channel *chanp = fi->userdata;
- chanp->data_open = 0;
- FsmChangeState(fi, ST_WAIT_D_REL_CNF);
- 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, 0, "STAT_BHUP");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_BHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- }
- if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
- release_b_st(chanp);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- lli_deliver_cause(chanp, &ic);
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- 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 | REQUEST, chanp->proc);
+ chanp->data_open = 0;
+ chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+
+ lli_bhup_dhup(fi, event, arg);
+}
+
+static void
+lli_release_req(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_WAIT_D_REL_CNF);
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST, chanp->proc);
+}
+
+static void
+lli_rel_b_release_req(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ release_b_st(chanp);
+ lli_release_req(fi, event, arg);
+}
+
+static void
+lli_bhup_release_req(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+
+ lli_rel_b_release_req(fi, event, arg);
}
+
/* processing charge info */
static void
lli_charge_info(struct FsmInst *fi, int event, void *arg)
@@ -920,259 +809,150 @@ lli_charge_info(struct FsmInst *fi, int event, void *arg)
/* error procedures */
static void
-lli_no_dchan(struct FsmInst *fi, int event, void *arg)
+lli_dchan_not_ready(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_NODCH");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_NODCH;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- chanp->Flags = 0;
- FsmChangeState(fi, ST_NULL);
- chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL);
+ link_debug(chanp, 0, "STAT_DHUP");
+ HL_LL(chanp, ISDN_STAT_DHUP);
}
static void
-lli_no_dchan_ready(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;
if (chanp->debug & 1)
link_debug(chanp, 0, "STAT_DHUP");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
+ HL_LL(chanp, ISDN_STAT_DHUP);
+ lli_close(fi);
}
static void
-lli_no_dchan_in(struct FsmInst *fi, int event, void *arg)
+lli_error(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- 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 | REQUEST, chanp->proc);
- chanp->Flags = 0;
- FsmChangeState(fi, ST_NULL);
- chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL);
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
}
static void
-lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
+lli_failure_l(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- FsmChangeState(fi, ST_NULL);
- test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- lli_shutdown_d(fi, event, arg);
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ FsmChangeState(fi, ST_NULL);
+ 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);
+ HL_LL(chanp, ISDN_STAT_DHUP);
+ chanp->Flags = 0;
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
}
static void
-lli_setup_err(struct FsmInst *fi, int event, void *arg)
+lli_rel_b_fail(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
+ struct Channel *chanp = fi->userdata;
- FsmChangeState(fi, ST_WAIT_DRELEASE);
- test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- lli_deliver_cause(chanp, &ic);
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */
+ release_b_st(chanp);
+ lli_failure_l(fi, event, arg);
}
static void
-lli_connect_err(struct FsmInst *fi, int event, void *arg)
+lli_bhup_fail(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
+ struct Channel *chanp = fi->userdata;
- FsmChangeState(fi, ST_WAIT_DRELEASE);
- test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- lli_deliver_cause(chanp, &ic);
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+
+ lli_rel_b_fail(fi, event, arg);
}
static void
-lli_got_dlrl(struct FsmInst *fi, int event, void *arg)
+lli_failure_a(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
+ struct Channel *chanp = fi->userdata;
- chanp->data_open = 0;
- FsmChangeState(fi, ST_NULL);
- if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
- }
- if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- ic.driver = chanp->cs->myid;
- ic.command = ISDN_STAT_BHUP;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&ic);
- }
- 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->cs->iif.statcallb(&ic);
- chanp->Flags = 0;
- } else {
- test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- 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);
- 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 | REQUEST, chanp->proc);
- chanp->Flags = 0;
- chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL);
- }
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
-}
-
-/* *INDENT-OFF* */
-static struct FsmNode fnlist[] HISAX_INITDATA =
-{
- {ST_NULL, EV_DIAL, lli_prep_dialout},
- {ST_NULL, EV_RESUME, 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_SUSPEND, lli_suspend},
- {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_RESUME, lli_prep_dialout},
- {ST_WAIT_DSHUTDOWN, EV_SETUP_IND, lli_deliver_call},
+ chanp->data_open = 0;
+ chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
+
+ lli_bhup_fail(fi, event, arg);
+}
+
+ /* *INDENT-OFF* */
+ static struct FsmNode fnlist[] HISAX_INITDATA =
+ {
+ {ST_NULL, EV_DIAL, lli_prep_dialout},
+ {ST_NULL, EV_RESUME, lli_resume},
+ {ST_NULL, EV_SETUP_IND, lli_deliver_call},
+ {ST_NULL, EV_LEASED, lli_leased_in},
+ {ST_OUT_DIAL, EV_SETUP_CNF, lli_init_bchan_out},
+ {ST_OUT_DIAL, EV_HANGUP, lli_disconnect_req},
+ {ST_OUT_DIAL, EV_DISCONNECT_IND, lli_release_req},
+ {ST_OUT_DIAL, EV_RELEASE, lli_dhup_close},
+ {ST_OUT_DIAL, EV_NOSETUP_RSP, lli_no_setup_rsp},
+ {ST_OUT_DIAL, EV_SETUP_ERR, lli_error},
+ {ST_IN_WAIT_LL, EV_LEASED_REL, lli_failure_l},
+ {ST_IN_WAIT_LL, EV_ACCEPTD, lli_setup_rsp},
+ {ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req},
+ {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req},
+ {ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close},
+ {ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in},
+ {ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect},
+ {ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject},
+ {ST_IN_ALERT_SENT, EV_DISCONNECT_IND, lli_release_req},
+ {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close},
+ {ST_IN_ALERT_SENT, EV_REDIR, lli_send_redir},
+ {ST_IN_PROCEED_SEND, EV_REDIR, lli_send_redir},
+ {ST_IN_PROCEED_SEND, EV_ALERT, lli_send_alert},
+ {ST_IN_PROCEED_SEND, EV_ACCEPTD, lli_send_dconnect},
+ {ST_IN_PROCEED_SEND, EV_HANGUP, lli_disconnect_reject},
+ {ST_IN_PROCEED_SEND, EV_DISCONNECT_IND, lli_dhup_close},
+ {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close},
+ {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, lli_init_bchan_in},
+ {ST_IN_WAIT_CONN_ACK, EV_HANGUP, lli_disconnect_req},
+ {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, lli_release_req},
+ {ST_IN_WAIT_CONN_ACK, EV_RELEASE, lli_dhup_close},
+ {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, lli_error},
+ {ST_WAIT_BCONN, EV_BC_EST, lli_go_active},
+ {ST_WAIT_BCONN, EV_BC_REL, lli_rel_b_disc},
+ {ST_WAIT_BCONN, EV_HANGUP, lli_rel_b_disc},
+ {ST_WAIT_BCONN, EV_DISCONNECT_IND, lli_rel_b_release_req},
+ {ST_WAIT_BCONN, EV_RELEASE, lli_rel_b_dhup},
+ {ST_WAIT_BCONN, EV_LEASED_REL, lli_rel_b_fail},
+ {ST_WAIT_BCONN, EV_CINF, lli_charge_info},
+ {ST_ACTIVE, EV_CINF, lli_charge_info},
+ {ST_ACTIVE, EV_BC_REL, lli_bhup_rel_b},
+ {ST_ACTIVE, EV_SUSPEND, lli_suspend},
+ {ST_ACTIVE, EV_HANGUP, lli_disconn_bchan},
+ {ST_ACTIVE, EV_DISCONNECT_IND, lli_release_bchan},
+ {ST_ACTIVE, EV_RELEASE, lli_abort},
+ {ST_ACTIVE, EV_LEASED_REL, lli_failure_a},
+ {ST_WAIT_BRELEASE, EV_BC_REL, lli_bhup_disc},
+ {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, lli_bhup_release_req},
+ {ST_WAIT_BRELEASE, EV_RELEASE, lli_bhup_dhup},
+ {ST_WAIT_BRELEASE, EV_LEASED_REL, lli_bhup_fail},
+ {ST_WAIT_BREL_DISC, EV_BC_REL, lli_bhup_release_req},
+ {ST_WAIT_BREL_DISC, EV_RELEASE, lli_bhup_dhup},
+ {ST_WAIT_DCOMMAND, EV_HANGUP, lli_start_disc},
+ {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, lli_release_req},
+ {ST_WAIT_DCOMMAND, EV_RELEASE, lli_dhup_close},
+ {ST_WAIT_DCOMMAND, EV_LEASED_REL, lli_failure_l},
+ {ST_WAIT_DRELEASE, EV_RELEASE, lli_dhup_close},
+ {ST_WAIT_DRELEASE, EV_DIAL, lli_dchan_not_ready},
+ /* ETS 300-104 16.1 */
+ {ST_WAIT_D_REL_CNF, EV_RELEASE, lli_dhup_close},
+ {ST_WAIT_D_REL_CNF, EV_DIAL, lli_dchan_not_ready},
};
-/* *INDENT-ON* */
+ /* *INDENT-ON* */
-#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
+ #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
HISAX_INITFUNC(void
CallcNew(void))
@@ -1195,21 +975,24 @@ release_b_st(struct Channel *chanp)
{
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);
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_TRANS):
-// case (ISDN_PROTO_L2_MODEM):
- releasestack_transl2(st);
- break;
- }
+ if(test_and_clear_bit(FLG_START_B, &chanp->Flags)) {
+ chanp->bcs->BC_Close(chanp->bcs);
+ switch (chanp->l2_active_protocol) {
+ case (ISDN_PROTO_L2_X75I):
+ releasestack_isdnl2(st);
+ break;
+ case (ISDN_PROTO_L2_HDLC):
+ case (ISDN_PROTO_L2_TRANS):
+ case (ISDN_PROTO_L2_MODEM):
+ case (ISDN_PROTO_L2_FAX):
+ releasestack_transl2(st);
+ break;
+ }
+ }
}
struct Channel
-*selectfreechannel(struct PStack *st)
+*selectfreechannel(struct PStack *st, int bch)
{
struct IsdnCardState *cs = st->l1.hardware;
struct Channel *chanp = st->lli.userdata;
@@ -1219,74 +1002,60 @@ struct Channel
i=1;
else
i=0;
- while (i<2) {
+
+ if (!bch)
+ { i = 2; /* virtual channel */
+ chanp += 2;
+ }
+
+ while (i < ((bch) ? cs->chanlimit : (2 + MAX_WAITING_CALLS))) {
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);
+ if (bch) /* number of channels is limited */
+ { i = 2; /* virtual channel */
+ chanp = st->lli.userdata;
+ chanp += i;
+ while (i < (2 + MAX_WAITING_CALLS)) {
+ if (chanp->fi.state == ST_NULL)
+ return (chanp);
chanp++;
i++;
- }
- return (0);
+ }
+ }
+ return (NULL);
}
+static void stat_redir_result(struct IsdnCardState *cs, int chan, ulong result)
+{ isdn_ctrl ic;
+
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_REDIR;
+ ic.arg = chan;
+ (ulong)(ic.parm.num[0]) = result;
+ cs->iif.statcallb(&ic);
+} /* stat_redir_result */
+
static void
dchan_l3l4(struct PStack *st, int pr, void *arg)
{
struct l3_process *pc = arg;
- struct IsdnCardState *cs = st->l1.hardware;
+ struct IsdnCardState *cs = st->l1.hardware;
struct Channel *chanp;
- int event;
- switch (pr) {
- case (DL_ESTABLISH | INDICATION):
- event = EV_DLEST;
- break;
- case (DL_RELEASE | INDICATION):
- event = EV_DLRL;
- break;
- default:
- event = -1;
- break;
- }
- if (event >= 0) {
- int i;
-
- chanp = st->lli.userdata;
- if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
- i = 1;
- else
- i = 0;
- while (i < 2) {
- FsmEvent(&chanp->fi, event, NULL);
- chanp++;
- i++;
- }
- return;
- } else if (pr == (CC_SETUP | INDICATION)) {
- if (!(chanp = selectfreechannel(pc->st))) {
- pc->st->lli.l4l3(pc->st, CC_DLRL | REQUEST, pc);
- } else {
- chanp->proc = pc;
- pc->chan = chanp;
+ if(!pc)
+ return;
+
+ if (pr == (CC_SETUP | INDICATION)) {
+ if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) {
+ pc->para.cause = 0x11; /* User busy */
+ pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc);
+ } else {
+ chanp->proc = pc;
+ pc->chan = chanp;
FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
}
return;
@@ -1299,19 +1068,19 @@ dchan_l3l4(struct PStack *st, int pr, void *arg)
FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
break;
case (CC_RELEASE | CONFIRM):
- FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
+ FsmEvent(&chanp->fi, EV_RELEASE, NULL);
break;
case (CC_SUSPEND | CONFIRM):
- FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
+ FsmEvent(&chanp->fi, EV_RELEASE, NULL);
break;
case (CC_RESUME | CONFIRM):
FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
break;
case (CC_RESUME_ERR):
- FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
+ FsmEvent(&chanp->fi, EV_RELEASE, NULL);
break;
case (CC_RELEASE | INDICATION):
- FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
+ FsmEvent(&chanp->fi, EV_RELEASE, NULL);
break;
case (CC_SETUP_COMPL | INDICATION):
FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
@@ -1332,15 +1101,21 @@ dchan_l3l4(struct PStack *st, int pr, void *arg)
FsmEvent(&chanp->fi, EV_CONNECT_ERR, NULL);
break;
case (CC_RELEASE_ERR):
- FsmEvent(&chanp->fi, EV_RELEASE_ERR, NULL);
+ FsmEvent(&chanp->fi, EV_RELEASE, NULL);
break;
+ case (CC_PROCEED_SEND | INDICATION):
case (CC_PROCEEDING | INDICATION):
case (CC_ALERTING | INDICATION):
+ case (CC_PROGRESS | INDICATION):
+ case (CC_NOTIFY | INDICATION):
break;
+ case (CC_REDIR | INDICATION):
+ stat_redir_result(cs, chanp->chan, pc->redir_result);
+ break;
default:
if (chanp->debug & 0x800) {
HiSax_putstatus(chanp->cs, "Ch",
- "%d L3->L4 unknown primitiv %x",
+ "%d L3->L4 unknown primitiv %#x",
chanp->chan, pr);
}
}
@@ -1406,6 +1181,7 @@ init_PStack(struct PStack **stp) {
(*stp)->l2.l2l1 = dummy_pstack;
(*stp)->l2.l2l3 = dummy_pstack;
(*stp)->l3.l3l2 = dummy_pstack;
+ (*stp)->l3.l3ml3 = dummy_pstack;
(*stp)->l3.l3l4 = dummy_pstack;
(*stp)->lli.l4l3 = dummy_pstack;
(*stp)->ma.layer = dummy_pstack;
@@ -1446,14 +1222,19 @@ init_chan(int chan, struct IsdnCardState *csta)
int
CallcNewChan(struct IsdnCardState *csta)
-{
+{ int i;
+
chancount += 2;
init_chan(0, csta);
init_chan(1, csta);
printk(KERN_INFO "HiSax: 2 channels added\n");
+
+ for (i = 0; i < MAX_WAITING_CALLS; i++)
+ init_chan(i+2,csta);
+ printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n");
+
if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) {
printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
- test_and_set_bit(FLG_START_D, &csta->channel->Flags);
csta->channel->d_st->lli.l4l3(csta->channel->d_st,
DL_ESTABLISH | REQUEST, NULL);
}
@@ -1482,14 +1263,13 @@ CallcFreeChan(struct IsdnCardState *csta)
for (i = 0; i < 2; i++) {
FsmDelTimer(&csta->channel[i].drel_timer, 74);
FsmDelTimer(&csta->channel[i].dial_timer, 75);
- 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
+ if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags))
+ release_d_st(csta->channel + i);
+ if (csta->channel[i].b_st) {
+ 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 (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
release_d_st(csta->channel + i);
@@ -1509,7 +1289,7 @@ lldata_handler(struct PStack *st, int pr, void *arg)
if (chanp->data_open)
chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
else {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
}
break;
case (DL_ESTABLISH | INDICATION):
@@ -1521,7 +1301,7 @@ lldata_handler(struct PStack *st, int pr, void *arg)
FsmEvent(&chanp->fi, EV_BC_REL, NULL);
break;
default:
- printk(KERN_WARNING "lldata_handler unknown primitive %x\n",
+ printk(KERN_WARNING "lldata_handler unknown primitive %#x\n",
pr);
break;
}
@@ -1539,7 +1319,7 @@ lltrans_handler(struct PStack *st, int pr, void *arg)
chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
else {
link_debug(chanp, 0, "channel not open");
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
}
break;
case (PH_ACTIVATE | INDICATION):
@@ -1551,7 +1331,7 @@ lltrans_handler(struct PStack *st, int pr, void *arg)
FsmEvent(&chanp->fi, EV_BC_REL, NULL);
break;
default:
- printk(KERN_WARNING "lltrans_handler unknown primitive %x\n",
+ printk(KERN_WARNING "lltrans_handler unknown primitive %#x\n",
pr);
break;
}
@@ -1566,7 +1346,7 @@ ll_writewakeup(struct PStack *st, int len)
ic.driver = chanp->cs->myid;
ic.command = ISDN_STAT_BSENT;
ic.arg = chanp->chan;
-// ic.parm.length = len;
+ ic.parm.length = len;
chanp->cs->iif.statcallb(&ic);
}
@@ -1590,12 +1370,14 @@ init_b_st(struct Channel *chanp, int incoming)
case (ISDN_PROTO_L2_TRANS):
st->l1.mode = L1_MODE_TRANS;
break;
-#if 0
case (ISDN_PROTO_L2_MODEM):
- st->l1.mode = L1_MODE_MODEM;
+ st->l1.mode = L1_MODE_V32;
+ break;
+ case (ISDN_PROTO_L2_FAX):
+ st->l1.mode = L1_MODE_FAX;
break;
-#endif
}
+ chanp->bcs->conmsg = NULL;
if (chanp->bcs->BC_SetStack(st, chanp->bcs))
return (-1);
st->l2.flag = 0;
@@ -1622,7 +1404,8 @@ init_b_st(struct Channel *chanp, int incoming)
break;
case (ISDN_PROTO_L2_HDLC):
case (ISDN_PROTO_L2_TRANS):
-// case (ISDN_PROTO_L2_MODEM):
+ case (ISDN_PROTO_L2_MODEM):
+ case (ISDN_PROTO_L2_FAX):
st->l1.l1l2 = lltrans_handler;
st->lli.userdata = chanp;
st->lli.l1writewakeup = ll_writewakeup;
@@ -1630,6 +1413,7 @@ init_b_st(struct Channel *chanp, int incoming)
setstack_l3bc(st, chanp);
break;
}
+ test_and_set_bit(FLG_START_B, &chanp->Flags);
return (0);
}
@@ -1642,7 +1426,7 @@ leased_l4l3(struct PStack *st, int pr, void *arg)
switch (pr) {
case (DL_DATA | REQUEST):
link_debug(chanp, 0, "leased line d-channel DATA");
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
break;
case (DL_ESTABLISH | REQUEST):
st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
@@ -1650,7 +1434,7 @@ leased_l4l3(struct PStack *st, int pr, void *arg)
case (DL_RELEASE | REQUEST):
break;
default:
- printk(KERN_WARNING "transd_l4l3 unknown primitive %x\n",
+ printk(KERN_WARNING "transd_l4l3 unknown primitive %#x\n",
pr);
break;
}
@@ -1661,16 +1445,16 @@ leased_l1l2(struct PStack *st, int pr, void *arg)
{
struct Channel *chanp = (struct Channel *) st->lli.userdata;
struct sk_buff *skb = arg;
- int i,event = EV_DLRL;
+ int i,event = EV_LEASED_REL;
switch (pr) {
case (PH_DATA | INDICATION):
link_debug(chanp, 0, "leased line d-channel DATA");
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
break;
case (PH_ACTIVATE | INDICATION):
case (PH_ACTIVATE | CONFIRM):
- event = EV_DLEST;
+ event = EV_LEASED;
case (PH_DEACTIVATE | INDICATION):
case (PH_DEACTIVATE | CONFIRM):
if (test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags))
@@ -1685,7 +1469,7 @@ leased_l1l2(struct PStack *st, int pr, void *arg)
break;
default:
printk(KERN_WARNING
- "transd_l1l2 unknown primitive %x\n", pr);
+ "transd_l1l2 unknown primitive %#x\n", pr);
break;
}
}
@@ -1701,7 +1485,7 @@ distr_debug(struct IsdnCardState *csta, int debugflags)
int i;
struct Channel *chanp = csta->channel;
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < (2 + MAX_WAITING_CALLS) ; i++) {
chanp[i].debug = debugflags;
chanp[i].fi.debug = debugflags & 2;
chanp[i].d_st->l2.l2m.debug = debugflags & 8;
@@ -1774,14 +1558,43 @@ lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *
}
}
+
+/***************************************************************/
+/* Limit the available number of channels for the current card */
+/***************************************************************/
+static int
+set_channel_limit(struct IsdnCardState *cs, int chanmax)
+{
+ isdn_ctrl ic;
+ int i, ii;
+
+ if ((chanmax < 0) || (chanmax > 2))
+ return(-EINVAL);
+ cs->chanlimit = 0;
+ for (ii = 0; ii < 2; ii++) {
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_DISCH;
+ ic.arg = ii;
+ if (ii >= chanmax)
+ ic.parm.num[0] = 0; /* disabled */
+ else
+ ic.parm.num[0] = 1; /* enabled */
+ i = cs->iif.statcallb(&ic);
+ if (i) return(-EINVAL);
+ if (ii < chanmax)
+ cs->chanlimit++;
+ }
+ return(0);
+} /* set_channel_limit */
+
int
HiSax_command(isdn_ctrl * ic)
{
struct IsdnCardState *csta = hisax_findcard(ic->driver);
+ struct PStack *st;
struct Channel *chanp;
int i;
u_int num;
- u_long adr;
if (!csta) {
printk(KERN_ERR
@@ -1789,12 +1602,10 @@ HiSax_command(isdn_ctrl * ic)
ic->command, ic->driver);
return -ENODEV;
}
-
switch (ic->command) {
case (ISDN_CMD_SETEAZ):
chanp = csta->channel + ic->arg;
break;
-
case (ISDN_CMD_SETL2):
chanp = csta->channel + (ic->arg & 0xff);
if (chanp->debug & 1)
@@ -1868,7 +1679,7 @@ HiSax_command(isdn_ctrl * ic)
HiSax_mod_inc_use_count();
#ifdef MODULE
if (csta->channel[0].debug & 0x400)
- HiSax_putstatus(csta, " LOCK ", "modcnt %x",
+ HiSax_putstatus(csta, " LOCK ", "modcnt %lx",
MOD_USE_COUNT);
#endif /* MODULE */
break;
@@ -1876,7 +1687,7 @@ HiSax_command(isdn_ctrl * ic)
HiSax_mod_dec_use_count();
#ifdef MODULE
if (csta->channel[0].debug & 0x400)
- HiSax_putstatus(csta, " UNLOCK ", "modcnt %x",
+ HiSax_putstatus(csta, " UNLOCK ", "modcnt %lx",
MOD_USE_COUNT);
#endif /* MODULE */
break;
@@ -1949,8 +1760,6 @@ HiSax_command(isdn_ctrl * ic)
HiSax_putstatus(csta, "set card ", "in PTP mode");
printk(KERN_DEBUG "HiSax: set card in PTP mode\n");
printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
- test_and_set_bit(FLG_START_D, &csta->channel[0].Flags);
- test_and_set_bit(FLG_START_D, &csta->channel[1].Flags);
csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st,
DL_ESTABLISH | REQUEST, NULL);
} else {
@@ -1969,16 +1778,12 @@ HiSax_command(isdn_ctrl * ic)
HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num);
printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
num);
- break;
- case (9): /* load firmware */
- memcpy(&adr, ic->parm.num, sizeof(ulong));
- csta->cardmsg(csta, CARD_LOAD_FIRM,
- (void *) adr);
+ chanp->d_st->lli.l4l3(chanp->d_st,
+ DL_ESTABLISH | REQUEST, NULL);
break;
#ifdef MODULE
case (55):
- while ( MOD_USE_COUNT > 0)
- MOD_DEC_USE_COUNT;
+ MOD_USE_COUNT = 0;
HiSax_mod_inc_use_count();
break;
#endif /* MODULE */
@@ -2001,16 +1806,52 @@ HiSax_command(isdn_ctrl * ic)
printk(KERN_DEBUG "HiSax: l3 debugging flags card %d set to %x\n",
csta->cardnr + 1, *(unsigned int *) ic->parm.num);
break;
+ case (10):
+ i = *(unsigned int *) ic->parm.num;
+ return(set_channel_limit(csta, i));
default:
+ if (csta->auxcmd)
+ return(csta->auxcmd(csta, ic));
printk(KERN_DEBUG "HiSax: invalid ioclt %d\n",
(int) ic->arg);
return (-EINVAL);
}
break;
- default:
+
+ case (ISDN_CMD_PROCEED):
+ chanp = csta->channel + ic->arg;
+ if (chanp->debug & 1)
+ link_debug(chanp, 1, "PROCEED");
+ FsmEvent(&chanp->fi, EV_PROCEED, NULL);
+ break;
+
+ case (ISDN_CMD_ALERT):
+ chanp = csta->channel + ic->arg;
+ if (chanp->debug & 1)
+ link_debug(chanp, 1, "ALERT");
+ FsmEvent(&chanp->fi, EV_ALERT, NULL);
break;
- }
+ case (ISDN_CMD_REDIR):
+ chanp = csta->channel + ic->arg;
+ if (chanp->debug & 1)
+ link_debug(chanp, 1, "REDIR");
+ chanp->setup = ic->parm.setup;
+ FsmEvent(&chanp->fi, EV_REDIR, NULL);
+ break;
+
+ /* protocol specific io commands */
+ case (ISDN_CMD_PROT_IO):
+ for (st = csta->stlist; st; st = st->next)
+ if (st->protocol == (ic->arg & 0xFF))
+ return(st->lli.l4l3_proto(st, ic));
+ return(-EINVAL);
+ break;
+ default:
+ if (csta->auxcmd)
+ return(csta->auxcmd(csta, ic));
+ return(-EINVAL);
+ }
return (0);
}
@@ -2049,7 +1890,8 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
if (chanp->debug & 0x800)
link_debug(chanp, 1, "writebuf: no buffers for %d bytes", len);
return 0;
- }
+ } else if (chanp->debug & 0x800)
+ link_debug(chanp, 1, "writebuf %d/%d/%d", len, chanp->bcs->tx_cnt,MAX_DATA_MEM);
save_flags(flags);
cli();
nskb = skb_clone(skb, GFP_ATOMIC);
@@ -2062,7 +1904,7 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
chanp->bcs->tx_cnt += len;
st->l2.l2l1(st, PH_DATA | REQUEST, nskb);
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_WRITE);
} else
len = 0;
restore_flags(flags);
diff --git a/drivers/isdn/hisax/cert.c b/drivers/isdn/hisax/cert.c
index a76736b60..03f416d5b 100644
--- a/drivers/isdn/hisax/cert.c
+++ b/drivers/isdn/hisax/cert.c
@@ -1,4 +1,4 @@
-/* $Id: cert.c,v 2.1 1998/11/15 23:51:15 keil Exp $
+/* $Id: cert.c,v 2.2 1999/08/07 17:35:05 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
*
@@ -7,6 +7,9 @@
* ../../../Documentation/isdn/HiSax.cert
*
* $Log: cert.c,v $
+ * Revision 2.2 1999/08/07 17:35:05 keil
+ * approval for Eicon Technology Diva 2.01 PCI
+ *
* Revision 2.1 1998/11/15 23:51:15 keil
* certification stuff
*
@@ -29,6 +32,7 @@ certification_check(int output) {
printk(KERN_INFO "HiSax: Approval registration numbers:\n");
printk(KERN_INFO "HiSax: German D133361J CETECOM ICT Services GmbH\n");
printk(KERN_INFO "HiSax: EU (D133362J) CETECOM ICT Services GmbH\n");
+ printk(KERN_INFO "HiSax: Approved with Eicon Technology Diva 2.01 PCI cards\n");
}
return(0);
#endif
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index d3bf31d90..dc0fa46a0 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1,10 +1,42 @@
-/* $Id: config.c,v 2.23 1999/02/17 10:53:02 cpetig Exp $
+/* $Id: config.c,v 2.33 1999/08/30 11:57:52 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
*
*
* $Log: config.c,v $
+ * Revision 2.33 1999/08/30 11:57:52 keil
+ * Fix broken avm pcmcia
+ *
+ * Revision 2.32 1999/08/28 22:11:10 keil
+ * __setup function should be static
+ *
+ * Revision 2.31 1999/08/25 16:47:43 keil
+ * Support new __setup; allow to add FEATURES after register_isdn
+ *
+ * Revision 2.30 1999/08/05 20:43:14 keil
+ * ISAR analog modem support
+ *
+ * Revision 2.29 1999/07/21 14:46:00 keil
+ * changes from EICON certification
+ *
+ * Revision 2.28 1999/07/14 12:38:36 werner
+ * Added changes for echo channel handling
+ *
+ * Revision 2.27 1999/07/12 21:05:00 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 2.26 1999/07/08 21:27:17 keil
+ * version 3.2
+ *
+ * Revision 2.25 1999/07/05 23:51:44 werner
+ * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl
+ * hisaxctrl id 10 <nr. of chans 0-2>
+ *
+ * Revision 2.24 1999/07/01 08:11:26 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.23 1999/02/17 10:53:02 cpetig
* Added Hisax_closecard to exported symbols.
* As indicated by Oliver Schoett <os@sdm.de>.
@@ -94,6 +126,10 @@
#include <linux/stddef.h>
#include <linux/timer.h>
#include <linux/config.h>
+#include <linux/isdn_compat.h>
+#ifdef COMPAT_HAS_NEW_SETUP
+#include <linux/init.h>
+#endif
#include "hisax.h"
#include <linux/module.h>
#include <linux/kernel_stat.h>
@@ -139,7 +175,13 @@
* 26 AVM A1 PCMCIA (Fritz) p0=irq p1=iobase
* 27 AVM PnP/PCI p0=irq p1=iobase (PCI no parameter)
* 28 Sedlbauer Speed Fax+ p0=irq p1=iobase (from isapnp setup)
- *
+ * 29 Siemens I-Surf p0=irq p1=iobase p2=memory (from isapnp setup)
+ * 30 ACER P10 p0=irq p1=iobase (from isapnp setup)
+ * 31 HST Saphir p0=irq p1=iobase
+ * 32 Telekom A4T none
+ * 33 Scitel Quadro p0=subcontroller (4*S0, subctrl 1...4)
+ * 34 Gazel ISDN cards
+ * 35 HFC 2BDS0 PCI none
* protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
*
*
@@ -152,15 +194,27 @@ const char *CardType[] =
"Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI",
"Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)",
"AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
- "Sedlbauer Speed Fax +"
+ "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir",
+ "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI",
};
+void HiSax_closecard(int cardnr);
+
#ifdef CONFIG_HISAX_ELSA
#define DEFAULT_CARD ISDN_CTYPE_ELSA
#define DEFAULT_CFG {0,0,0,0}
int elsa_init_pcmcia(void*, int, int*, int);
+#ifdef COMPAT_HAS_NEW_SYMTAB
EXPORT_SYMBOL(elsa_init_pcmcia);
-#endif
+#else
+static struct symbol_table hisax_syms_elsa = {
+#include <linux/symtab_begin.h>
+ X(elsa_init_pcmcia),
+#include <linux/symtab_end.h>
+};
+#endif /* COMPAT_HAS_NEW_SYMTAB */
+#endif /* CONFIG_HISAX_ELSA */
+
#ifdef CONFIG_HISAX_AVM_A1
#undef DEFAULT_CARD
#undef DEFAULT_CFG
@@ -174,8 +228,18 @@ EXPORT_SYMBOL(elsa_init_pcmcia);
#define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA
#define DEFAULT_CFG {11,0x170,0,0}
int avm_a1_init_pcmcia(void*, int, int*, int);
+#ifdef COMPAT_HAS_NEW_SYMTAB
EXPORT_SYMBOL(avm_a1_init_pcmcia);
-#endif
+EXPORT_SYMBOL(HiSax_closecard);
+#else
+static struct symbol_table hisax_syms_avm_a1= {
+#include <linux/symtab_begin.h>
+ X(avm_a1_init_pcmcia),
+ X(HiSax_closecard),
+#include <linux/symtab_end.h>
+};
+#endif /* COMPAT_HAS_NEW_SYMTAB */
+#endif /* CONFIG_HISAX_AVM_A1_PCMCIA */
#ifdef CONFIG_HISAX_FRITZPCI
#undef DEFAULT_CARD
@@ -190,12 +254,14 @@ EXPORT_SYMBOL(avm_a1_init_pcmcia);
#define DEFAULT_CARD ISDN_CTYPE_16_3
#define DEFAULT_CFG {15,0x180,0,0}
#endif
+
#ifdef CONFIG_HISAX_S0BOX
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_S0BOX
#define DEFAULT_CFG {7,0x378,0,0}
#endif
+
#ifdef CONFIG_HISAX_16_0
#undef DEFAULT_CARD
#undef DEFAULT_CFG
@@ -244,8 +310,16 @@ EXPORT_SYMBOL(avm_a1_init_pcmcia);
#define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER
#define DEFAULT_CFG {11,0x270,0,0}
int sedl_init_pcmcia(void*, int, int*, int);
+#ifdef COMPAT_HAS_NEW_SYMTAB
EXPORT_SYMBOL(sedl_init_pcmcia);
-#endif
+#else
+static struct symbol_table hisax_syms_sedl= {
+#include <linux/symtab_begin.h>
+ X(sedl_init_pcmcia),
+#include <linux/symtab_end.h>
+};
+#endif /* COMPAT_HAS_NEW_SYMTAB */
+#endif /* CONFIG_HISAX_SEDLBAUER */
#ifdef CONFIG_HISAX_SPORTSTER
#undef DEFAULT_CARD
@@ -268,13 +342,21 @@ EXPORT_SYMBOL(sedl_init_pcmcia);
#define DEFAULT_CFG {0,0,0,0}
#endif
-#ifdef CONFIG_HISAX_TELES3C
+#ifdef CONFIG_HISAX_HFCS
#undef DEFAULT_CARD
#undef DEFAULT_CFG
#define DEFAULT_CARD ISDN_CTYPE_TELES3C
#define DEFAULT_CFG {5,0x500,0,0}
#endif
+#ifdef CONFIG_HISAX_HFC_PCI
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_HFC_PCI
+#define DEFAULT_CFG {0,0,0,0}
+#endif
+
+
#ifdef CONFIG_HISAX_AMD7930
#undef DEFAULT_CARD
#undef DEFAULT_CFG
@@ -289,6 +371,41 @@ EXPORT_SYMBOL(sedl_init_pcmcia);
#define DEFAULT_CFG {0,0x0,0,0}
#endif
+#ifdef CONFIG_HISAX_ISURF
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_ISURF
+#define DEFAULT_CFG {5,0x100,0xc8000,0}
+#endif
+
+#ifdef CONFIG_HISAX_HSTSAPHIR
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_HSTSAPHIR
+#define DEFAULT_CFG {5,0x250,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_BKM_A4T
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_BKM_A4T
+#define DEFAULT_CFG {0,0x0,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_SCT_QUADRO
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_SCT_QUADRO
+#define DEFAULT_CFG {1,0x0,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_GAZEL
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_GAZEL
+#define DEFAULT_CFG {15,0x180,0,0}
+#endif
+
#ifdef CONFIG_HISAX_1TR6
#define DEFAULT_PROTO ISDN_PTYPE_1TR6
#define DEFAULT_PROTO_NAME "1TR6"
@@ -366,6 +483,7 @@ static int mem[] HISAX_INITDATA =
{0, 0, 0, 0, 0, 0, 0, 0};
static char *id HISAX_INITDATA = HiSaxID;
+#ifdef COMPAT_HAS_NEW_SYMTAB
MODULE_AUTHOR("Karsten Keil");
MODULE_PARM(type, "1-8i");
MODULE_PARM(protocol, "1-8i");
@@ -377,7 +495,7 @@ MODULE_PARM(id, "s");
MODULE_PARM(io0, "1-8i");
MODULE_PARM(io1, "1-8i");
#endif /* CONFIG_HISAX_16_3 */
-
+#endif /* COMPAT_HAS_NEW_SYMTAB */
#endif /* MODULE */
int nrcards;
@@ -410,9 +528,9 @@ HiSaxVersion(void))
printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
#ifdef MODULE
- printk(KERN_INFO "HiSax: Version 3.1a (module)\n");
+ printk(KERN_INFO "HiSax: Version 3.3a (module)\n");
#else
- printk(KERN_INFO "HiSax: Version 3.1a (kernel)\n");
+ printk(KERN_INFO "HiSax: Version 3.3a (kernel)\n");
#endif
strcpy(tmp, l1_revision);
printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
@@ -442,12 +560,24 @@ HiSax_mod_inc_use_count(void)
#ifdef MODULE
#define HiSax_init init_module
#else
-void __init
-HiSax_setup(char *str, int *ints)
+#ifdef COMPAT_HAS_NEW_SETUP
+#define MAX_ARG (HISAX_MAX_CARDS*5)
+static int __init
+HiSax_setup(char *line)
{
int i, j, argc;
+ int ints[MAX_ARG + 1];
+ char *str;
+ str = get_options(line, MAX_ARG, ints);
+#else
+void __init
+HiSax_setup(char *str, int *ints)
+{
+ int i, j, argc;
+#endif
argc = ints[0];
+ printk(KERN_DEBUG"HiSax_setup: argc(%d) str(%s)\n", argc, str);
i = 0;
j = 1;
while (argc && (i < HISAX_MAX_CARDS)) {
@@ -485,8 +615,15 @@ HiSax_setup(char *str, int *ints)
strcpy(HiSaxID, "HiSax");
HiSax_id = HiSaxID;
}
+#ifdef COMPAT_HAS_NEW_SETUP
+ return(1);
}
-#endif
+
+__setup("hisax=", HiSax_setup);
+#else
+}
+#endif /* COMPAT_HAS_NEW_SETUP */
+#endif /* MODULES */
#if CARD_TELES0
extern int setup_teles0(struct IsdnCard *card);
@@ -552,8 +689,12 @@ extern int setup_mic(struct IsdnCard *card);
extern int setup_netjet(struct IsdnCard *card);
#endif
-#if CARD_TELES3C
-extern int setup_t163c(struct IsdnCard *card);
+#if CARD_HFCS
+extern int setup_hfcs(struct IsdnCard *card);
+#endif
+
+#if CARD_HFC_PCI
+extern int setup_hfcpci(struct IsdnCard *card);
#endif
#if CARD_AMD7930
@@ -564,6 +705,30 @@ extern int setup_amd7930(struct IsdnCard *card);
extern int setup_niccy(struct IsdnCard *card);
#endif
+#if CARD_ISURF
+extern int setup_isurf(struct IsdnCard *card);
+#endif
+
+#if CARD_HSTSAPHIR
+extern int setup_saphir(struct IsdnCard *card);
+#endif
+
+#if CARD_TESTEMU
+extern int setup_testemu(struct IsdnCard *card);
+#endif
+
+#if CARD_BKM_A4T
+extern int setup_bkm_a4t(struct IsdnCard *card);
+#endif
+
+#if CARD_SCT_QUADRO
+extern int setup_sct_quadro(struct IsdnCard *card);
+#endif
+
+#if CARD_GAZEL
+extern int setup_gazel(struct IsdnCard *card);
+#endif
+
/*
* Find card with given driverId
*/
@@ -579,6 +744,18 @@ static inline struct IsdnCardState
return (NULL);
}
+/*
+ * Find card with given card number
+ */
+struct IsdnCardState
+*hisax_get_card(int cardnr)
+{
+ if ((cardnr <= nrcards) && (cardnr>0))
+ if (cards[cardnr-1].cs)
+ return (cards[cardnr-1].cs);
+ return (NULL);
+}
+
int
HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
{
@@ -731,7 +908,7 @@ HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
}
int
-ll_run(struct IsdnCardState *cs)
+ll_run(struct IsdnCardState *cs, int addfeatures)
{
long flags;
isdn_ctrl ic;
@@ -740,6 +917,7 @@ ll_run(struct IsdnCardState *cs)
cli();
ic.driver = cs->myid;
ic.command = ISDN_STAT_RUN;
+ cs->iif.features |= addfeatures;
cs->iif.statcallb(&ic);
restore_flags(flags);
return 0;
@@ -782,23 +960,18 @@ closecard(int cardnr)
csta->bcs->BC_Close(csta->bcs);
}
+ discard_queue(&csta->rq);
+ discard_queue(&csta->sq);
if (csta->rcvbuf) {
kfree(csta->rcvbuf);
csta->rcvbuf = NULL;
}
- discard_queue(&csta->rq);
- discard_queue(&csta->sq);
if (csta->tx_skb) {
- dev_kfree_skb(csta->tx_skb);
+ idev_kfree_skb(csta->tx_skb, FREE_WRITE);
csta->tx_skb = NULL;
}
- if (csta->mon_rx) {
- kfree(csta->mon_rx);
- csta->mon_rx = NULL;
- }
- if (csta->mon_tx) {
- kfree(csta->mon_tx);
- csta->mon_tx = NULL;
+ if (csta->DC_Close != NULL) {
+ csta->DC_Close(csta);
}
csta->cardmsg(csta, CARD_RELEASE, NULL);
if (csta->dbusytimer.function != NULL)
@@ -811,12 +984,14 @@ HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
int irq_cnt, cnt = 3;
long flags;
+ if (!cs->irq)
+ return(cs->cardmsg(cs, CARD_INIT, NULL));
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)) {
+ if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) {
printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
cs->irq);
restore_flags(flags);
@@ -827,7 +1002,7 @@ HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
sti();
current->state = TASK_INTERRUPTIBLE;
/* Timeout 10ms */
- schedule_timeout((10 * HZ) / 1000);
+ schedule_timeout((10*HZ)/1000);
restore_flags(flags);
printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
cs->irq, kstat_irqs(cs->irq));
@@ -871,198 +1046,228 @@ checkcard(int cardnr, char *id, int *busy_flag))
}
memset(cs, 0, sizeof(struct IsdnCardState));
card->cs = cs;
+ cs->chanlimit = 2; /* maximum B-channel number */
+ cs->logecho = 0; /* No echo logging */
cs->cardnr = cardnr;
cs->debug = L1_DEB_WARN;
cs->HW_Flags = 0;
cs->busy_flag = busy_flag;
+ cs->irq_flags = I4L_IRQ_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)) {
+ if ((card->typ > 0) && (card->typ <= ISDN_CTYPE_COUNT)) {
+ if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
- "HiSax: Support for %s Card not selected\n",
- CardType[card->typ]);
+ "HiSax: No memory for dlog(card %d)\n",
+ cardnr + 1);
restore_flags(flags);
return (0);
}
- } else {
- printk(KERN_WARNING
- "HiSax: Card Type %d out of range\n",
- card->typ);
- restore_flags(flags);
- return (0);
- }
- if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for dlog(card %d)\n",
- cardnr + 1);
- restore_flags(flags);
- return (0);
- }
- if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for status_buf(card %d)\n",
- cardnr + 1);
- kfree(cs->dlog);
- restore_flags(flags);
- return (0);
- }
- cs->stlist = NULL;
- cs->mon_tx = NULL;
- cs->mon_rx = NULL;
- cs->status_read = cs->status_buf;
- cs->status_write = cs->status_buf;
- cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
- cs->typ = card->typ;
- strcpy(cs->iif.id, id);
- cs->iif.channels = 2;
- cs->iif.maxbufsize = MAX_DATA_SIZE;
- cs->iif.hl_hdrlen = MAX_HEADER_LEN;
- cs->iif.features =
- ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L2_MODEM |
- ISDN_FEATURE_L2_TRANS |
- ISDN_FEATURE_L3_TRANS |
+ if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for status_buf(card %d)\n",
+ cardnr + 1);
+ kfree(cs->dlog);
+ restore_flags(flags);
+ return (0);
+ }
+ cs->stlist = NULL;
+ cs->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 |
+ ISDN_FEATURE_L3_TRANS |
#ifdef CONFIG_HISAX_1TR6
- ISDN_FEATURE_P_1TR6 |
+ ISDN_FEATURE_P_1TR6 |
#endif
#ifdef CONFIG_HISAX_EURO
- ISDN_FEATURE_P_EURO |
-#endif
-#ifdef CONFIG_HISAX_NI1
- ISDN_FEATURE_P_NI1 |
-#endif
- 0;
-
- cs->iif.command = HiSax_command;
- cs->iif.writecmd = NULL;
- cs->iif.writebuf_skb = HiSax_writebuf_skb;
- cs->iif.readstat = HiSax_readstatus;
- register_isdn(&cs->iif);
- cs->myid = cs->iif.channels;
- printk(KERN_INFO
- "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
- (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
- (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
- (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
- (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
- "NONE", cs->iif.id, cs->myid);
- switch (card->typ) {
+ ISDN_FEATURE_P_EURO |
+#endif
+#ifdef CONFIG_HISAX_NI1
+ ISDN_FEATURE_P_NI1 |
+#endif
+ 0;
+
+ cs->iif.command = HiSax_command;
+ cs->iif.writecmd = NULL;
+ cs->iif.writebuf_skb = HiSax_writebuf_skb;
+ cs->iif.readstat = HiSax_readstatus;
+ register_isdn(&cs->iif);
+ cs->myid = cs->iif.channels;
+ printk(KERN_INFO
+ "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
+ (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
+ (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
+ (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
+ (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
+ "NONE", cs->iif.id, cs->myid);
+ switch (card->typ) {
#if CARD_TELES0
- case ISDN_CTYPE_16_0:
- case ISDN_CTYPE_8_0:
- ret = setup_teles0(card);
- break;
+ case ISDN_CTYPE_16_0:
+ case ISDN_CTYPE_8_0:
+ ret = setup_teles0(card);
+ break;
#endif
#if CARD_TELES3
- case ISDN_CTYPE_16_3:
- case ISDN_CTYPE_PNP:
- case ISDN_CTYPE_TELESPCMCIA:
- case ISDN_CTYPE_COMPAQ_ISA:
- ret = setup_teles3(card);
- break;
+ case ISDN_CTYPE_16_3:
+ case ISDN_CTYPE_PNP:
+ case ISDN_CTYPE_TELESPCMCIA:
+ case ISDN_CTYPE_COMPAQ_ISA:
+ ret = setup_teles3(card);
+ break;
#endif
#if CARD_S0BOX
- case ISDN_CTYPE_S0BOX:
- ret = setup_s0box(card);
- break;
+ case ISDN_CTYPE_S0BOX:
+ ret = setup_s0box(card);
+ break;
#endif
#if CARD_TELESPCI
- case ISDN_CTYPE_TELESPCI:
- ret = setup_telespci(card);
- break;
+ case ISDN_CTYPE_TELESPCI:
+ ret = setup_telespci(card);
+ break;
#endif
#if CARD_AVM_A1
- case ISDN_CTYPE_A1:
- ret = setup_avm_a1(card);
- break;
+ case ISDN_CTYPE_A1:
+ ret = setup_avm_a1(card);
+ break;
#endif
#if CARD_AVM_A1_PCMCIA
- case ISDN_CTYPE_A1_PCMCIA:
- ret = setup_avm_a1_pcmcia(card);
- break;
+ case ISDN_CTYPE_A1_PCMCIA:
+ ret = setup_avm_a1_pcmcia(card);
+ break;
#endif
#if CARD_FRITZPCI
- case ISDN_CTYPE_FRITZPCI:
- ret = setup_avm_pcipnp(card);
- break;
+ case ISDN_CTYPE_FRITZPCI:
+ ret = setup_avm_pcipnp(card);
+ break;
#endif
#if CARD_ELSA
- case ISDN_CTYPE_ELSA:
- case ISDN_CTYPE_ELSA_PNP:
- case ISDN_CTYPE_ELSA_PCMCIA:
- case ISDN_CTYPE_ELSA_PCI:
- ret = setup_elsa(card);
- break;
+ case ISDN_CTYPE_ELSA:
+ case ISDN_CTYPE_ELSA_PNP:
+ case ISDN_CTYPE_ELSA_PCMCIA:
+ case ISDN_CTYPE_ELSA_PCI:
+ ret = setup_elsa(card);
+ break;
#endif
#if CARD_IX1MICROR2
- case ISDN_CTYPE_IX1MICROR2:
- ret = setup_ix1micro(card);
- break;
+ case ISDN_CTYPE_IX1MICROR2:
+ ret = setup_ix1micro(card);
+ break;
#endif
#if CARD_DIEHLDIVA
- case ISDN_CTYPE_DIEHLDIVA:
- ret = setup_diva(card);
- break;
+ case ISDN_CTYPE_DIEHLDIVA:
+ ret = setup_diva(card);
+ break;
#endif
#if CARD_ASUSCOM
- case ISDN_CTYPE_ASUSCOM:
- ret = setup_asuscom(card);
- break;
+ case ISDN_CTYPE_ASUSCOM:
+ ret = setup_asuscom(card);
+ break;
#endif
#if CARD_TELEINT
- case ISDN_CTYPE_TELEINT:
- ret = setup_TeleInt(card);
- break;
+ case ISDN_CTYPE_TELEINT:
+ ret = setup_TeleInt(card);
+ break;
#endif
#if CARD_SEDLBAUER
- case ISDN_CTYPE_SEDLBAUER:
- case ISDN_CTYPE_SEDLBAUER_PCMCIA:
- case ISDN_CTYPE_SEDLBAUER_FAX:
- ret = setup_sedlbauer(card);
- break;
+ case ISDN_CTYPE_SEDLBAUER:
+ case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+ case ISDN_CTYPE_SEDLBAUER_FAX:
+ ret = setup_sedlbauer(card);
+ break;
#endif
#if CARD_SPORTSTER
- case ISDN_CTYPE_SPORTSTER:
- ret = setup_sportster(card);
- break;
+ case ISDN_CTYPE_SPORTSTER:
+ ret = setup_sportster(card);
+ break;
#endif
#if CARD_MIC
- case ISDN_CTYPE_MIC:
- ret = setup_mic(card);
- break;
+ case ISDN_CTYPE_MIC:
+ ret = setup_mic(card);
+ break;
#endif
#if CARD_NETJET
- case ISDN_CTYPE_NETJET:
- ret = setup_netjet(card);
- break;
+ case ISDN_CTYPE_NETJET:
+ ret = setup_netjet(card);
+ break;
#endif
-#if CARD_TELES3C
- case ISDN_CTYPE_TELES3C:
- ret = setup_t163c(card);
- break;
+#if CARD_HFCS
+ case ISDN_CTYPE_TELES3C:
+ case ISDN_CTYPE_ACERP10:
+ ret = setup_hfcs(card);
+ break;
+#endif
+#if CARD_HFC_PCI
+ case ISDN_CTYPE_HFC_PCI:
+ ret = setup_hfcpci(card);
+ break;
#endif
#if CARD_NICCY
- case ISDN_CTYPE_NICCY:
- ret = setup_niccy(card);
- break;
+ case ISDN_CTYPE_NICCY:
+ ret = setup_niccy(card);
+ break;
#endif
#if CARD_AMD7930
- case ISDN_CTYPE_AMD7930:
- ret = setup_amd7930(card);
+ case ISDN_CTYPE_AMD7930:
+ ret = setup_amd7930(card);
+ break;
+#endif
+#if CARD_ISURF
+ case ISDN_CTYPE_ISURF:
+ ret = setup_isurf(card);
+ break;
+#endif
+#if CARD_HSTSAPHIR
+ case ISDN_CTYPE_HSTSAPHIR:
+ ret = setup_saphir(card);
+ break;
+#endif
+#if CARD_TESTEMU
+ case ISDN_CTYPE_TESTEMU:
+ ret = setup_testemu(card);
+ break;
+#endif
+#if CARD_BKM_A4T
+ case ISDN_CTYPE_BKM_A4T:
+ ret = setup_bkm_a4t(card);
+ break;
+#endif
+#if CARD_SCT_QUADRO
+ case ISDN_CTYPE_SCT_QUADRO:
+ ret = setup_sct_quadro(card);
break;
#endif
+#if CARD_GAZEL
+ case ISDN_CTYPE_GAZEL:
+ ret = setup_gazel(card);
+ break;
+#endif
default:
- printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n",
- card->typ);
+ printk(KERN_WARNING
+ "HiSax: Support for %s Card not selected\n",
+ CardType[card->typ]);
ll_unload(cs);
restore_flags(flags);
return (0);
+ }
+ } else {
+ printk(KERN_WARNING
+ "HiSax: Card Type %d out of range\n",
+ card->typ);
+ restore_flags(flags);
+ return (0);
}
if (!ret) {
ll_unload(cs);
@@ -1097,7 +1302,7 @@ checkcard(int cardnr, char *id, int *busy_flag))
CallcNewChan(cs);
/* ISAR needs firmware download first */
if (!test_bit(HW_ISAR, &cs->HW_Flags))
- ll_run(cs);
+ ll_run(cs, 0);
restore_flags(flags);
return (1);
}
@@ -1168,7 +1373,8 @@ HiSax_closecard(int cardnr)
ll_stop(cards[cardnr].cs);
release_tei(cards[cardnr].cs);
closecard(cardnr);
- free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
+ if (cards[cardnr].cs->irq)
+ free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
kfree((void *) cards[cardnr].cs);
cards[cardnr].cs = NULL;
}
@@ -1180,8 +1386,6 @@ HiSax_closecard(int cardnr)
nrcards--;
}
-EXPORT_SYMBOL(HiSax_closecard);
-
void
HiSax_reportcard(int cardnr)
{
@@ -1202,11 +1406,13 @@ HiSax_reportcard(int cardnr)
cs->bcs[0].mode, cs->bcs[0].channel);
printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n",
cs->bcs[1].mode, cs->bcs[1].channel);
+ printk(KERN_DEBUG "HiSax: cs setstack_d 0x%lX\n", (ulong) cs->setstack_d);
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: dst%d l1.l1hw 0x%lX\n", i, (ulong) stptr->l1.l1hw);
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);
@@ -1236,7 +1442,7 @@ HiSax_reportcard(int cardnr)
}
-int __init
+int __init
HiSax_init(void)
{
int i;
@@ -1246,18 +1452,27 @@ HiSax_init(void)
#ifdef CONFIG_HISAX_ELSA
if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) {
/* we have exported and return in this case */
+#ifndef COMPAT_HAS_NEW_SYMTAB
+ register_symtab(&hisax_syms_elsa);
+#endif
return 0;
}
#endif
#ifdef CONFIG_HISAX_SEDLBAUER
if (type[0] == ISDN_CTYPE_SEDLBAUER_PCMCIA) {
/* we have to export and return in this case */
+#ifndef COMPAT_HAS_NEW_SYMTAB
+ register_symtab(&hisax_syms_sedl);
+#endif
return 0;
}
#endif
#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
if (type[0] == ISDN_CTYPE_A1_PCMCIA) {
/* we have to export and return in this case */
+#ifndef COMPAT_HAS_NEW_SYMTAB
+ register_symtab(&hisax_syms_avm_a1);
+#endif
return 0;
}
#endif
@@ -1318,16 +1533,29 @@ HiSax_init(void)
case ISDN_CTYPE_SPORTSTER:
case ISDN_CTYPE_MIC:
case ISDN_CTYPE_TELES3C:
+ case ISDN_CTYPE_ACERP10:
case ISDN_CTYPE_S0BOX:
case ISDN_CTYPE_FRITZPCI:
+ case ISDN_CTYPE_HSTSAPHIR:
+ case ISDN_CTYPE_GAZEL:
+ cards[i].para[0] = irq[i];
+ cards[i].para[1] = io[i];
+ break;
+ case ISDN_CTYPE_ISURF:
cards[i].para[0] = irq[i];
cards[i].para[1] = io[i];
+ cards[i].para[2] = mem[i];
break;
case ISDN_CTYPE_ELSA_PCI:
case ISDN_CTYPE_NETJET:
case ISDN_CTYPE_AMD7930:
case ISDN_CTYPE_TELESPCI:
break;
+ case ISDN_CTYPE_BKM_A4T:
+ break;
+ case ISDN_CTYPE_SCT_QUADRO:
+ cards[i].para[0] = irq[i];
+ break;
}
}
if (!nzproto) {
@@ -1353,11 +1581,13 @@ HiSax_init(void)
Isdnl1New();
if (HiSax_inithardware(NULL)) {
/* Install only, if at least one card found */
- /* No symbols to export, hide all symbols */
-
#ifdef MODULE
+#ifndef COMPAT_HAS_NEW_SYMTAB
+ /* No symbols to export, hide all symbols */
+ register_symtab(NULL);
printk(KERN_INFO "HiSax: module installed\n");
-#endif
+#endif /* COMPAT_HAS_NEW_SYMTAB */
+#endif /* MODULE */
return (0);
} else {
Isdnl1Free();
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 9774b2218..8ec1a536c 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -1,13 +1,36 @@
-/* $Id: diva.c,v 1.10 1998/11/15 23:54:31 keil Exp $
+/* $Id: diva.c,v 1.16 1999/08/11 21:01:25 keil Exp $
* diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards
*
* Author Karsten Keil (keil@isdn4linux.de)
*
- * Thanks to Eicon Technology Diehl GmbH & Co. oHG for documents and informations
+ * This file is (c) under GNU PUBLIC LICENSE
+ * For changes and modifications please read
+ * ../../../Documentation/isdn/HiSax.cert
+ *
+ * Thanks to Eicon Technology for documents and informations
*
*
* $Log: diva.c,v $
+ * Revision 1.16 1999/08/11 21:01:25 keil
+ * new PCI codefix
+ *
+ * Revision 1.15 1999/08/10 16:01:49 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 1.14 1999/08/07 17:35:08 keil
+ * approval for Eicon Technology Diva 2.01 PCI
+ *
+ * Revision 1.13 1999/07/21 14:46:07 keil
+ * changes from EICON certification
+ *
+ * Revision 1.12 1999/07/12 21:05:04 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.11 1999/07/01 08:11:29 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.10 1998/11/15 23:54:31 keil
* changes from 2.0
*
@@ -51,10 +74,13 @@
#include "ipac.h"
#include "isdnl1.h"
#include <linux/pci.h>
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
extern const char *CardType[];
-const char *Diva_revision = "$Revision: 1.10 $";
+const char *Diva_revision = "$Revision: 1.16 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -75,6 +101,7 @@ const char *Diva_revision = "$Revision: 1.10 $";
#define DIVA_ISA 1
#define DIVA_PCI 2
#define DIVA_IPAC_ISA 3
+#define DIVA_IPAC_PCI 4
/* PCI stuff */
#define PCI_VENDOR_EICON_DIEHL 0x1133
@@ -82,10 +109,12 @@ const char *Diva_revision = "$Revision: 1.10 $";
#define PCI_DIVA20_ID 0xe002
#define PCI_DIVA20PRO_U_ID 0xe003
#define PCI_DIVA20_U_ID 0xe004
+#define PCI_DIVA_201 0xe005
/* CTRL (Read) */
#define DIVA_IRQ_STAT 0x01
#define DIVA_EEPROM_SDA 0x02
+
/* CTRL (Write) */
#define DIVA_IRQ_REQ 0x01
#define DIVA_RESET 0x08
@@ -96,6 +125,13 @@ const char *Diva_revision = "$Revision: 1.10 $";
#define DIVA_ISA_LED_B 0x40
#define DIVA_IRQ_CLR 0x80
+/* Siemens PITA */
+#define PITA_MISC_REG 0x1c
+#define PITA_PARA_SOFTRESET 0x01000000
+#define PITA_PARA_MPX_MODE 0x04000000
+#define PITA_INT0_ENABLE 0x00020000
+#define PITA_INT0_STATUS 0x00000002
+
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
@@ -140,6 +176,22 @@ writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size
outsb(adr, data, size);
}
+static inline u_char
+memreadreg(unsigned long adr, u_char off)
+{
+ return(0xff & *((unsigned int *)
+ (((unsigned int *)adr) + off)));
+}
+
+static inline void
+memwritereg(unsigned long adr, u_char off, u_char data)
+{
+ register u_char *p;
+
+ p = (unsigned char *)(((unsigned int *)adr) + off);
+ *p = data;
+}
+
/* Interface functions */
static u_char
@@ -204,6 +256,44 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value);
}
+static u_char
+MemReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
+{
+ return (memreadreg(cs->hw.diva.cfg_reg, offset+0x80));
+}
+
+static void
+MemWriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ memwritereg(cs->hw.diva.cfg_reg, offset|0x80, value);
+}
+
+static void
+MemReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
+{
+ while(size--)
+ *data++ = memreadreg(cs->hw.diva.cfg_reg, 0x80);
+}
+
+static void
+MemWriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
+{
+ while(size--)
+ memwritereg(cs->hw.diva.cfg_reg, 0x80, *data++);
+}
+
+static u_char
+MemReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+ return(memreadreg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+MemWriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+ memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value);
+}
+
/*
* fast interrupt HSCX stuff goes here
*/
@@ -225,8 +315,8 @@ 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;
+ u_char val, sval;
+ int cnt=5;
if (!cs) {
printk(KERN_WARNING "Diva: Spurious interrupt!\n");
@@ -234,44 +324,36 @@ diva_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
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) {
+ if (val)
hscx_int_main(cs, val);
- stat |= 1;
- }
val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA);
- if (val) {
+ 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);
- }
+ 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.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0);
+ 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);
}
static void
-diva_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+diva_irq_ipac_isa(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char ista,val;
- int icnt=20;
+ int icnt=5;
if (!cs) {
printk(KERN_WARNING "Diva: Spurious interrupt!\n");
return;
}
ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA);
-Start_IPAC:
+Start_IPACISA:
if (cs->debug & L1_DEB_IPAC)
debugl1(cs, "IPAC ISTA %02X", ista);
if (ista & 0x0f) {
@@ -298,7 +380,7 @@ Start_IPAC:
ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA);
if ((ista & 0x3f) && icnt) {
icnt--;
- goto Start_IPAC;
+ goto Start_IPACISA;
}
if (!icnt)
printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n");
@@ -306,13 +388,348 @@ Start_IPAC:
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0);
}
+static inline void
+MemwaitforCEC(struct IsdnCardState *cs, int hscx)
+{
+ int to = 50;
+
+ while ((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
+}
+
+
+static inline void
+MemwaitforXFW(struct IsdnCardState *cs, int hscx)
+{
+ int to = 50;
+
+ while ((!(MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
+}
+
+static inline void
+MemWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ MemwaitforCEC(cs, hscx);
+ MemWriteHSCX(cs, hscx, HSCX_CMDR, data);
+ restore_flags(flags);
+}
+
+static void
+Memhscx_empty_fifo(struct BCState *bcs, int count)
+{
+ u_char *ptr;
+ struct IsdnCardState *cs = bcs->cs;
+ long flags;
+ int cnt;
+
+ 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");
+ MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
+ bcs->hw.hscx.rcvidx = 0;
+ return;
+ }
+ save_flags(flags);
+ cli();
+ ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+ cnt = count;
+ while (cnt--)
+ *ptr++ = memreadreg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0);
+ MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
+ ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+ bcs->hw.hscx.rcvidx += count;
+ restore_flags(flags);
+ if (cs->debug & L1_DEB_HSCX_FIFO) {
+ char *t = bcs->blog;
+
+ t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+ bcs->hw.hscx.hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(cs, bcs->blog);
+ }
+}
+
+static void
+Memhscx_fill_fifo(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int more, count, cnt;
+ int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
+ u_char *ptr,*p;
+ long flags;
+
+
+ if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+ debugl1(cs, "hscx_fill_fifo");
+
+ if (!bcs->tx_skb)
+ return;
+ if (bcs->tx_skb->len <= 0)
+ return;
+
+ more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+ if (bcs->tx_skb->len > fifo_size) {
+ more = !0;
+ count = fifo_size;
+ } else
+ count = bcs->tx_skb->len;
+ cnt = count;
+ MemwaitforXFW(cs, bcs->hw.hscx.hscx);
+ save_flags(flags);
+ cli();
+ p = ptr = bcs->tx_skb->data;
+ skb_pull(bcs->tx_skb, count);
+ bcs->tx_cnt -= count;
+ bcs->hw.hscx.count += count;
+ while(cnt--)
+ memwritereg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0,
+ *p++);
+ MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (cs->debug & L1_DEB_HSCX_FIFO) {
+ char *t = bcs->blog;
+
+ t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+ bcs->hw.hscx.hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(cs, bcs->blog);
+ }
+}
+
+static inline void
+Memhscx_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;
+
+ if (!test_bit(BC_FLG_INIT, &bcs->Flag))
+ return;
+
+ if (val & 0x80) { /* RME */
+ r = MemReadHSCX(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)
+ debugl1(cs, "HSCX RDO mode=%d",
+ bcs->mode);
+ if (!(r & 0x20))
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "HSCX CRC error");
+ MemWriteHSCXCMDR(cs, hscx, 0x80);
+ } else {
+ count = MemReadHSCX(cs, hscx, HSCX_RBCL) & (
+ test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
+ if (count == 0)
+ count = fifo_size;
+ Memhscx_empty_fifo(bcs, count);
+ if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+ if (cs->debug & L1_DEB_HSCX_FIFO)
+ debugl1(cs, "HX Frame %d", count);
+ if (!(skb = dev_alloc_skb(count)))
+ printk(KERN_WARNING "HSCX: receive out of memory\n");
+ else {
+ SET_SKB_FREE(skb);
+ 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 */
+ Memhscx_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 {
+ SET_SKB_FREE(skb);
+ 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->tx_skb) {
+ if (bcs->tx_skb->len) {
+ Memhscx_fill_fifo(bcs);
+ return;
+ } else {
+ if (bcs->st->lli.l1writewakeup &&
+ (PACKET_NOACK != bcs->tx_skb->pkt_type))
+ bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
+ bcs->hw.hscx.count = 0;
+ bcs->tx_skb = NULL;
+ }
+ }
+ if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+ bcs->hw.hscx.count = 0;
+ test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+ Memhscx_fill_fifo(bcs);
+ } else {
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ hscx_sched_event(bcs, B_XMTBUFREADY);
+ }
+ }
+}
+
+static inline void
+Memhscx_int_main(struct IsdnCardState *cs, u_char val)
+{
+
+ u_char exval;
+ struct BCState *bcs;
+
+ if (val & 0x01) {
+ bcs = cs->bcs + 1;
+ exval = MemReadHSCX(cs, 1, HSCX_EXIR);
+ if (exval & 0x40) {
+ if (bcs->mode == 1)
+ Memhscx_fill_fifo(bcs);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (bcs->tx_skb) {
+ skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+ bcs->tx_cnt += bcs->hw.hscx.count;
+ bcs->hw.hscx.count = 0;
+ }
+ MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
+ }
+ } else if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX B EXIR %x", exval);
+ }
+ if (val & 0xf8) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX B interrupt %x", val);
+ Memhscx_interrupt(cs, val, 1);
+ }
+ if (val & 0x02) {
+ bcs = cs->bcs;
+ exval = MemReadHSCX(cs, 0, HSCX_EXIR);
+ if (exval & 0x40) {
+ if (bcs->mode == L1_MODE_TRANS)
+ Memhscx_fill_fifo(bcs);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (bcs->tx_skb) {
+ skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+ bcs->tx_cnt += bcs->hw.hscx.count;
+ bcs->hw.hscx.count = 0;
+ }
+ MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
+ }
+ } else if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX A EXIR %x", exval);
+ }
+ if (val & 0x04) {
+ exval = MemReadHSCX(cs, 0, HSCX_ISTA);
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX A interrupt %x", exval);
+ Memhscx_interrupt(cs, exval, 0);
+ }
+}
+
+static void
+diva_irq_ipac_pci(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char ista,val;
+ int icnt=5;
+ u_char *cfg;
+
+ if (!cs) {
+ printk(KERN_WARNING "Diva: Spurious interrupt!\n");
+ return;
+ }
+ cfg = (u_char *) cs->hw.diva.pci_cfg;
+ val = *cfg;
+ if (!(val & PITA_INT0_STATUS))
+ return; /* other shared IRQ */
+ *cfg = PITA_INT0_STATUS; /* Reset pending INT0 */
+ ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA);
+Start_IPACPCI:
+ if (cs->debug & L1_DEB_IPAC)
+ debugl1(cs, "IPAC ISTA %02X", ista);
+ if (ista & 0x0f) {
+ val = memreadreg(cs->hw.diva.cfg_reg, HSCX_ISTA + 0x40);
+ if (ista & 0x01)
+ val |= 0x01;
+ if (ista & 0x04)
+ val |= 0x02;
+ if (ista & 0x08)
+ val |= 0x04;
+ if (val)
+ Memhscx_int_main(cs, val);
+ }
+ if (ista & 0x20) {
+ val = 0xfe & memreadreg(cs->hw.diva.cfg_reg, ISAC_ISTA + 0x80);
+ if (val) {
+ isac_interrupt(cs, val);
+ }
+ }
+ if (ista & 0x10) {
+ val = 0x01;
+ isac_interrupt(cs, val);
+ }
+ ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA);
+ if ((ista & 0x3f) && icnt) {
+ icnt--;
+ goto Start_IPACPCI;
+ }
+ if (!icnt)
+ printk(KERN_WARNING "DIVA IPAC PCI IRQ LOOP\n");
+ memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xFF);
+ memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0);
+}
void
release_io_diva(struct IsdnCardState *cs)
{
int bytecnt;
- if (cs->subtyp != DIVA_IPAC_ISA) {
+ if (cs->subtyp == DIVA_IPAC_PCI) {
+ u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg;
+
+ *cfg = 0; /* disable INT0/1 */
+ *cfg = 2; /* reset pending INT0 */
+ iounmap((void *)cs->hw.diva.cfg_reg);
+ iounmap((void *)cs->hw.diva.pci_cfg);
+ return;
+ } else if (cs->subtyp != DIVA_IPAC_ISA) {
del_timer(&cs->hw.diva.tl);
if (cs->hw.diva.cfg_reg)
byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */
@@ -336,24 +753,37 @@ reset_diva(struct IsdnCardState *cs)
if (cs->subtyp == DIVA_IPAC_ISA) {
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+ schedule_timeout((10*HZ)/1000);
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+ schedule_timeout((10*HZ)/1000);
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0);
- } else {
+ } else if (cs->subtyp == DIVA_IPAC_PCI) {
+ unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
+ PITA_MISC_REG);
+ *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((10*HZ)/1000);
+ *ireg = PITA_PARA_MPX_MODE;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((10*HZ)/1000);
+ memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
+ } else { /* DIVA 2.0 */
cs->hw.diva.ctrl_reg = 0; /* Reset On */
byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+ schedule_timeout((10*HZ)/1000);
cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */
byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+ schedule_timeout((10*HZ)/1000);
if (cs->subtyp == DIVA_ISA)
cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
- else
+ else {
+ /* Workaround PCI9060 */
+ byteout(cs->hw.diva.pci_cfg + 0x69, 9);
cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A;
+ }
byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
}
restore_flags(flags);
@@ -366,7 +796,7 @@ diva_led_handler(struct IsdnCardState *cs)
{
int blink = 0;
- if (cs->subtyp == DIVA_IPAC_ISA)
+ if ((cs->subtyp == DIVA_IPAC_ISA) || (cs->subtyp == DIVA_IPAC_PCI))
return;
del_timer(&cs->hw.diva.tl);
if (cs->hw.diva.status & DIVA_ASSIGN)
@@ -399,7 +829,7 @@ diva_led_handler(struct IsdnCardState *cs)
static int
Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- u_int irq_flag = I4L_IRQ_FLAG;
+ u_int *ireg;
switch (mt) {
case CARD_RESET:
@@ -408,17 +838,11 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
case CARD_RELEASE:
release_io_diva(cs);
return(0);
- case CARD_SETIRQ:
- if (cs->subtyp == DIVA_PCI)
- irq_flag |= SA_SHIRQ;
- if (cs->subtyp == DIVA_IPAC_ISA) {
- return(request_irq(cs->irq, &diva_interrupt_ipac,
- irq_flag, "HiSax", cs));
- } else {
- return(request_irq(cs->irq, &diva_interrupt,
- irq_flag, "HiSax", cs));
- }
case CARD_INIT:
+ if (cs->subtyp == DIVA_IPAC_PCI) {
+ ireg = (unsigned int *)cs->hw.diva.pci_cfg;
+ *ireg = PITA_INT0_ENABLE;
+ }
inithscxisac(cs, 3);
return(0);
case CARD_TEST:
@@ -451,15 +875,20 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
break;
}
- if (cs->subtyp != DIVA_IPAC_ISA)
+ if ((cs->subtyp != DIVA_IPAC_ISA) && (cs->subtyp != DIVA_IPAC_PCI))
diva_led_handler(cs);
return(0);
}
+#ifdef COMPAT_HAS_NEW_PCI
static struct pci_dev *dev_diva __initdata = NULL;
static struct pci_dev *dev_diva_u __initdata = NULL;
+static struct pci_dev *dev_diva201 __initdata = NULL;
+#else
+static int pci_index __initdata = 0;
+#endif
-int __init
+int __init
setup_diva(struct IsdnCard *card)
{
int bytecnt;
@@ -478,7 +907,7 @@ setup_diva(struct IsdnCard *card)
val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
printk(KERN_INFO "Diva: IPAC version %x\n", val);
- if (val == 1) {
+ if ((val == 1) || (val==2)) {
cs->subtyp = DIVA_IPAC_ISA;
cs->hw.diva.ctrl = 0;
cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
@@ -498,6 +927,7 @@ setup_diva(struct IsdnCard *card)
bytecnt = 8;
} else {
#if CONFIG_PCI
+#ifdef COMPAT_HAS_NEW_PCI
if (!pci_present()) {
printk(KERN_ERR "Diva: no PCI bus present\n");
return(0);
@@ -506,20 +936,26 @@ setup_diva(struct IsdnCard *card)
cs->subtyp = 0;
if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL,
PCI_DIVA20_ID, dev_diva))) {
- cs->subtyp = DIVA_PCI;
- /* get IRQ */
+ cs->subtyp = DIVA_PCI;
cs->irq = dev_diva->irq;
- /* get IO address */
- cs->hw.diva.cfg_reg = dev_diva->base_address[2]
+ cs->hw.diva.cfg_reg = get_pcibase(dev_diva, 2)
& PCI_BASE_ADDRESS_IO_MASK;
} else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL,
PCI_DIVA20_U_ID, dev_diva_u))) {
- cs->subtyp = DIVA_PCI;
- /* get IRQ */
+ cs->subtyp = DIVA_PCI;
cs->irq = dev_diva_u->irq;
- /* get IO address */
- cs->hw.diva.cfg_reg = dev_diva_u->base_address[2]
+ cs->hw.diva.cfg_reg = get_pcibase(dev_diva_u, 2)
& PCI_BASE_ADDRESS_IO_MASK;
+ } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_EICON_DIEHL,
+ PCI_DIVA_201, dev_diva201))) {
+ cs->subtyp = DIVA_IPAC_PCI;
+ cs->irq = dev_diva201->irq;
+ cs->hw.diva.pci_cfg =
+ (ulong) ioremap((get_pcibase(dev_diva201, 0)
+ & PCI_BASE_ADDRESS_IO_MASK), 4096);
+ cs->hw.diva.cfg_reg =
+ (ulong) ioremap((get_pcibase(dev_diva201, 1)
+ & PCI_BASE_ADDRESS_IO_MASK), 4096);
} else {
printk(KERN_WARNING "Diva: No PCI card found\n");
return(0);
@@ -534,35 +970,112 @@ setup_diva(struct IsdnCard *card)
printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
return(0);
}
- cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
- cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
- cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
- cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
- bytecnt = 32;
+#else
+ 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_U_ID, pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL)
+ cs->subtyp = DIVA_PCI;
+ else if (pcibios_find_device(PCI_VENDOR_EICON_DIEHL,
+ PCI_DIVA_201, pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL)
+ cs->subtyp = DIVA_IPAC_PCI;
+ else
+ break;
+ /* get IRQ */
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq);
+
+ /* get IO address */
+ if (cs->subtyp == DIVA_IPAC_PCI) {
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ cs->hw.diva.pci_cfg = (ulong) ioremap(pci_ioaddr,
+ 4096);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, &pci_ioaddr);
+ cs->hw.diva.cfg_reg = (ulong) ioremap(pci_ioaddr,
+ 4096);
+ } else {
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, &pci_ioaddr);
+ cs->hw.diva.pci_cfg = pci_ioaddr & ~3;
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_2, &pci_ioaddr);
+ cs->hw.diva.cfg_reg = pci_ioaddr & ~3;
+ }
+ if (cs->subtyp)
+ break;
+ }
+ if (!cs->subtyp) {
+ printk(KERN_WARNING "Diva: No PCI card found\n");
+ return(0);
+ }
+ pci_index++;
+ 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);
+ }
+ cs->irq = pci_irq;
+#endif /* COMPAT_HAS_NEW_PCI */
+ cs->irq_flags |= SA_SHIRQ;
#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 */
+ if (cs->subtyp == DIVA_IPAC_PCI) {
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac = 0;
+ cs->hw.diva.hscx = 0;
+ cs->hw.diva.isac_adr = 0;
+ cs->hw.diva.hscx_adr = 0;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ bytecnt = 0;
+ } else {
+ cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+ cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+ cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+ cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
+ bytecnt = 32;
+ }
}
printk(KERN_INFO
- "Diva: %s card configured at 0x%x IRQ %d\n",
+ "Diva: %s card configured at %#lx IRQ %d\n",
(cs->subtyp == DIVA_PCI) ? "PCI" :
- (cs->subtyp == DIVA_ISA) ? "ISA" : "IPAC",
+ (cs->subtyp == DIVA_ISA) ? "ISA" :
+ (cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" : "IPAC 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");
+ if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_PCI))
+ printk(KERN_INFO "Diva: %s PCI space at %#lx\n",
+ (cs->subtyp == DIVA_PCI) ? "PCI" : "IPAC PCI",
+ cs->hw.diva.pci_cfg);
+ if (cs->subtyp != DIVA_IPAC_PCI) {
+ if (check_region(cs->hw.diva.cfg_reg, bytecnt)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %lx-%lx 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->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
@@ -573,9 +1086,21 @@ setup_diva(struct IsdnCard *card)
cs->writeisac = &WriteISAC_IPAC;
cs->readisacfifo = &ReadISACfifo_IPAC;
cs->writeisacfifo = &WriteISACfifo_IPAC;
+ cs->irq_func = &diva_irq_ipac_isa;
val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ID);
printk(KERN_INFO "Diva: IPAC version %x\n", val);
- } else {
+ } else if (cs->subtyp == DIVA_IPAC_PCI) {
+ cs->readisac = &MemReadISAC_IPAC;
+ cs->writeisac = &MemWriteISAC_IPAC;
+ cs->readisacfifo = &MemReadISACfifo_IPAC;
+ cs->writeisacfifo = &MemWriteISACfifo_IPAC;
+ cs->BC_Read_Reg = &MemReadHSCX;
+ cs->BC_Write_Reg = &MemWriteHSCX;
+ cs->BC_Send_Data = &Memhscx_fill_fifo;
+ cs->irq_func = &diva_irq_ipac_pci;
+ val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID);
+ printk(KERN_INFO "Diva: IPAC version %x\n", val);
+ } else { /* DIVA 2.0 */
cs->hw.diva.tl.function = (void *) diva_led_handler;
cs->hw.diva.tl.data = (long) cs;
init_timer(&cs->hw.diva.tl);
@@ -583,6 +1108,7 @@ setup_diva(struct IsdnCard *card)
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
+ cs->irq_func = &diva_interrupt;
ISACVersion(cs, "Diva:");
if (HscxVersion(cs, "Diva:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 50f9df9c0..c2d6cf2d3 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -1,4 +1,4 @@
-/* $Id: elsa.c,v 2.12 1998/11/15 23:54:35 keil Exp $
+/* $Id: elsa.c,v 2.18 1999/08/25 16:50:54 keil Exp $
* elsa.c low level stuff for Elsa isdn cards
*
@@ -13,8 +13,29 @@
* Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE)
* for ELSA PCMCIA support
*
- *
* $Log: elsa.c,v $
+ * Revision 2.18 1999/08/25 16:50:54 keil
+ * Fix bugs which cause 2.3.14 hangs (waitqueue init)
+ *
+ * Revision 2.17 1999/08/11 20:57:40 keil
+ * bugfix IPAC version 1.1
+ * new PCI codefix
+ *
+ * Revision 2.16 1999/08/10 16:01:51 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 2.15 1999/08/09 19:25:21 keil
+ * Support (alpha version) for the '98 model of ELSA Microlink ISDN/MC
+ * by Christer Weinigel, Cendio Systems AB <wingel@cendio.se>
+ * Add support for IPAC 1.2
+ *
+ * Revision 2.14 1999/07/12 21:05:07 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 2.13 1999/07/01 08:11:31 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.12 1998/11/15 23:54:35 keil
* changes from 2.0
*
@@ -70,16 +91,19 @@
#include "hscx.h"
#include "isdnl1.h"
#include <linux/pci.h>
-
-//#define KDEBUG_DEF
-//#include "../kdebug.h"
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
extern const char *CardType[];
-static const char *Elsa_revision = "$Revision: 2.12 $";
+const char *Elsa_revision = "$Revision: 2.18 $";
const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
- "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI"};
+ "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI",
+ "PCMCIA-IPAC" };
const char *ITACVer[] =
{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2",
@@ -109,6 +133,7 @@ const char *ITACVer[] =
#define ELSA_QS3000 8
#define ELSA_QS1000PCI 9
#define ELSA_QS3000PCI 10
+#define ELSA_PCMCIA_IPAC 11
/* PCI stuff */
#define PCI_VENDOR_ELSA 0x1048
@@ -158,22 +183,32 @@ const char *ITACVer[] =
#define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */
#define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */
-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,0xe9,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 UP */
-const u_char ARCOFI_XOP_F[] = {2,0xa1,0x3f}; /* Normal OP */
-const u_char ARCOFI_SOP_F[] = {10,0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12};
+#if ARCOFI_USE
+static struct arcofi_msg ARCOFI_XOP_F =
+ {NULL,0,2,{0xa1,0x3f,0,0,0,0,0,0,0,0}}; /* Normal OP */
+static struct arcofi_msg ARCOFI_XOP_1 =
+ {&ARCOFI_XOP_F,0,2,{0xa1,0x31,0,0,0,0,0,0,0,0}}; /* PWR UP */
+static struct arcofi_msg ARCOFI_SOP_F =
+ {&ARCOFI_XOP_1,0,10,{0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12}};
+static struct arcofi_msg ARCOFI_COP_9 =
+ {&ARCOFI_SOP_F,0,10,{0xa1,0x29,0x80,0xcb,0xe9,0x88,0x00,0xc8,0xd8,0x80}}; /* RX */
+static struct arcofi_msg ARCOFI_COP_8 =
+ {&ARCOFI_COP_9,0,10,{0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}}; /* TX */
+static struct arcofi_msg ARCOFI_COP_7 =
+ {&ARCOFI_COP_8,0,4,{0xa1,0x27,0x80,0x80,0,0,0,0,0,0}}; /* GZ */
+static struct arcofi_msg ARCOFI_COP_6 =
+ {&ARCOFI_COP_7,0,6,{0xa1,0x26,0,0,0x82,0x7c,0,0,0,0}}; /* GRL GRH */
+static struct arcofi_msg ARCOFI_COP_5 =
+ {&ARCOFI_COP_6,0,4,{0xa1,0x25,0xbb,0x4a,0,0,0,0,0,0}}; /* GTX */
+static struct arcofi_msg ARCOFI_VERSION =
+ {NULL,1,2,{0xa0,0,0,0,0,0,0,0,0,0}};
+static struct arcofi_msg ARCOFI_XOP_0 =
+ {NULL,0,2,{0xa1,0x30,0,0,0,0,0,0,0,0}}; /* PWR Down */
static void set_arcofi(struct IsdnCardState *cs, int bc);
-#if ARCOFI_USE
#include "elsa_ser.c"
-#endif
+#endif /* ARCOFI_USE */
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
@@ -343,7 +378,7 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char val;
- int icnt=20;
+ int icnt=5;
if (!cs) {
printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
@@ -400,6 +435,7 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
cs->hw.elsa.counter++;
}
}
+#if ARCOFI_USE
if (cs->hw.elsa.MFlag) {
val = serial_inp(cs, UART_MCR);
val ^= 0x8;
@@ -408,6 +444,7 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
val ^= 0x8;
serial_outp(cs, UART_MCR, val);
}
+#endif
if (cs->hw.elsa.trig)
byteout(cs->hw.elsa.trig, 0x00);
writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0);
@@ -420,15 +457,17 @@ elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char ista,val;
- int icnt=20;
+ int icnt=5;
if (!cs) {
printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
return;
}
- val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */
- if (!(val & ELSA_PCI_IRQ_MASK))
- return;
+ if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) {
+ val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */
+ if (!(val & ELSA_PCI_IRQ_MASK))
+ return;
+ }
#if ARCOFI_USE
if (cs->hw.elsa.MFlag) {
val = serial_inp(cs, UART_IIR);
@@ -480,6 +519,9 @@ release_io_elsa(struct IsdnCardState *cs)
int bytecnt = 8;
del_timer(&cs->hw.elsa.tl);
+#if ARCOFI_USE
+ clear_arcofi(cs);
+#endif
if (cs->hw.elsa.ctrl)
byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */
if (cs->subtyp == ELSA_QS1000PCI) {
@@ -493,12 +535,17 @@ release_io_elsa(struct IsdnCardState *cs)
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
release_region(cs->hw.elsa.cfg, 0x80);
}
+ if (cs->subtyp == ELSA_PCMCIA_IPAC) {
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+ }
if ((cs->subtyp == ELSA_PCFPRO) ||
(cs->subtyp == ELSA_QS3000) ||
(cs->subtyp == ELSA_PCF) ||
(cs->subtyp == ELSA_QS3000PCI)) {
bytecnt = 16;
+#if ARCOFI_USE
release_modem(cs);
+#endif
}
if (cs->hw.elsa.base)
release_region(cs->hw.elsa.base, bytecnt);
@@ -527,19 +574,25 @@ reset_elsa(struct IsdnCardState *cs)
if (cs->hw.elsa.trig)
byteout(cs->hw.elsa.trig, 0xff);
}
- if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
+ if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) {
save_flags(flags);
sti();
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+ schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
+ schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
restore_flags(flags);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0);
- writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c);
+ if (cs->subtyp != ELSA_PCMCIA_IPAC) {
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c);
+ } else {
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_PCFG, 0x10);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x4);
+ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0xf8);
+ }
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
if (cs->subtyp == ELSA_QS1000PCI)
byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */
@@ -548,69 +601,41 @@ reset_elsa(struct IsdnCardState *cs)
}
}
-static void
-init_arcofi(struct IsdnCardState *cs) {
- send_arcofi(cs, ARCOFI_XOP_0, 1, 0);
-/* send_arcofi(cs, ARCOFI_XOP_F, 1);
-*/
-}
-
-#define ARCDEL 500
+#if ARCOFI_USE
static void
set_arcofi(struct IsdnCardState *cs, int bc) {
- long flags;
-
- debugl1(cs,"set_arcofi bc=%d", bc);
- save_flags(flags);
- sti();
- send_arcofi(cs, ARCOFI_XOP_0, bc, 0);
- udelay(ARCDEL);
- send_arcofi(cs, ARCOFI_COP_5, bc, 0);
- udelay(ARCDEL);
- send_arcofi(cs, ARCOFI_COP_6, bc, 0);
- udelay(ARCDEL);
- send_arcofi(cs, ARCOFI_COP_7, bc, 0);
- udelay(ARCDEL);
- send_arcofi(cs, ARCOFI_COP_8, bc, 0);
- udelay(ARCDEL);
- send_arcofi(cs, ARCOFI_COP_9, bc, 0);
- udelay(ARCDEL);
- send_arcofi(cs, ARCOFI_SOP_F, bc, 0);
- udelay(ARCDEL);
- send_arcofi(cs, ARCOFI_XOP_1, bc, 0);
- udelay(ARCDEL);
- send_arcofi(cs, ARCOFI_XOP_F, bc, 0);
- restore_flags(flags);
- debugl1(cs,"end set_arcofi bc=%d", bc);
+ cs->dc.isac.arcofi_bc = bc;
+ arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5);
+ interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
}
static int
check_arcofi(struct IsdnCardState *cs)
{
-#if ARCOFI_USE
int arcofi_present = 0;
char tmp[40];
char *t;
u_char *p;
- if (!cs->mon_tx)
- if (!(cs->mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+ if (!cs->dc.isac.mon_tx)
+ if (!(cs->dc.isac.mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC MON TX out of buffers!");
return(0);
}
- send_arcofi(cs, ARCOFI_VERSION, 0, 1);
- if (test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags)) {
- if (test_and_clear_bit(HW_MON1_RX_END, &cs->HW_Flags)) {
- debugl1(cs, "Arcofi response received %d bytes", cs->mon_rxp);
- p = cs->mon_rx;
+ cs->dc.isac.arcofi_bc = 0;
+ arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION);
+ interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
+ if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) {
+ debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp);
+ p = cs->dc.isac.mon_rx;
t = tmp;
t += sprintf(tmp, "Arcofi data");
- QuickHex(t, p, cs->mon_rxp);
+ QuickHex(t, p, cs->dc.isac.mon_rxp);
debugl1(cs, tmp);
- if ((cs->mon_rxp == 2) && (cs->mon_rx[0] == 0xa0)) {
- switch(cs->mon_rx[1]) {
+ if ((cs->dc.isac.mon_rxp == 2) && (cs->dc.isac.mon_rx[0] == 0xa0)) {
+ switch(cs->dc.isac.mon_rx[1]) {
case 0x80:
debugl1(cs, "Arcofi 2160 detected");
arcofi_present = 1;
@@ -629,9 +654,8 @@ check_arcofi(struct IsdnCardState *cs)
}
} else
debugl1(cs, "undefined Monitor response");
- cs->mon_rxp = 0;
- }
- } else if (cs->mon_tx) {
+ cs->dc.isac.mon_rxp = 0;
+ } else if (cs->dc.isac.mon_tx) {
debugl1(cs, "Arcofi not detected");
}
if (arcofi_present) {
@@ -672,19 +696,20 @@ check_arcofi(struct IsdnCardState *cs)
"Elsa: %s detected modem at 0x%x\n",
Elsa_Types[cs->subtyp],
cs->hw.elsa.base+8);
- init_arcofi(cs);
+ arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0);
+ interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
return(1);
}
-#endif
return(0);
}
+#endif /* ARCOFI_USE */
static void
elsa_led_handler(struct IsdnCardState *cs)
{
int blink = 0;
- if (cs->subtyp == ELSA_PCMCIA)
+ if (cs->subtyp == ELSA_PCMCIA || cs->subtyp == ELSA_PCMCIA_IPAC)
return;
del_timer(&cs->hw.elsa.tl);
if (cs->hw.elsa.status & ELSA_ASSIGN)
@@ -723,8 +748,7 @@ elsa_led_handler(struct IsdnCardState *cs)
static int
Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- int len, ret = 0;
- u_char *msg;
+ int ret = 0;
long flags;
switch (mt) {
@@ -734,15 +758,6 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
case CARD_RELEASE:
release_io_elsa(cs);
return(0);
- case CARD_SETIRQ:
- if ((cs->subtyp == ELSA_QS1000PCI) ||
- (cs->subtyp == ELSA_QS3000PCI))
- ret = request_irq(cs->irq, &elsa_interrupt_ipac,
- I4L_IRQ_FLAG | SA_SHIRQ, "HiSax", cs);
- else
- ret = request_irq(cs->irq, &elsa_interrupt,
- I4L_IRQ_FLAG, "HiSax", cs);
- return(ret);
case CARD_INIT:
cs->debug |= L1_DEB_IPAC;
inithscxisac(cs, 1);
@@ -757,6 +772,7 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
case CARD_TEST:
if ((cs->subtyp == ELSA_PCMCIA) ||
+ (cs->subtyp == ELSA_PCMCIA_IPAC) ||
(cs->subtyp == ELSA_QS1000PCI)) {
return(0);
} else if (cs->subtyp == ELSA_QS3000PCI) {
@@ -770,7 +786,6 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
byteout(cs->hw.elsa.timer, 0);
current->state = TASK_INTERRUPTIBLE;
- /* Timeout 110ms */
schedule_timeout((110*HZ)/1000);
restore_flags(flags);
cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
@@ -822,8 +837,12 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
cs->hw.elsa.status &= ~0x0100;
}
break;
+#if ARCOFI_USE
case CARD_AUX_IND:
if (cs->hw.elsa.MFlag) {
+ int len;
+ u_char *msg;
+
if (!arg)
return(0);
msg = arg;
@@ -832,6 +851,7 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
modem_write_cmd(cs, msg, len);
}
break;
+#endif
}
if (cs->typ == ISDN_CTYPE_ELSA) {
int pwr = bytein(cs->hw.elsa.ale);
@@ -908,8 +928,12 @@ probe_elsa(struct IsdnCardState *cs)
return (CARD_portlist[i]);
}
+#ifdef COMPAT_HAS_NEW_PCI
static struct pci_dev *dev_qs1000 __initdata = NULL;
static struct pci_dev *dev_qs3000 __initdata = NULL;
+#else
+static int pci_index __initdata = 0;
+#endif
int
setup_elsa(struct IsdnCard *card)
@@ -1004,10 +1028,19 @@ setup_elsa(struct IsdnCard *card)
} 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;
+ val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
+ if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
+ cs->subtyp = ELSA_PCMCIA_IPAC;
+ cs->hw.elsa.ale = cs->hw.elsa.base + 0;
+ cs->hw.elsa.isac = cs->hw.elsa.base + 2;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ 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;
@@ -1018,6 +1051,7 @@ setup_elsa(struct IsdnCard *card)
cs->irq);
} else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
#if CONFIG_PCI
+#ifdef COMPAT_HAS_NEW_PCI
if (!pci_present()) {
printk(KERN_ERR "Elsa: no PCI bus present\n");
return(0);
@@ -1027,17 +1061,17 @@ setup_elsa(struct IsdnCard *card)
dev_qs1000))) {
cs->subtyp = ELSA_QS1000PCI;
cs->irq = dev_qs1000->irq;
- cs->hw.elsa.cfg = dev_qs1000->base_address[1] &
+ cs->hw.elsa.cfg = get_pcibase(dev_qs1000, 1) &
PCI_BASE_ADDRESS_IO_MASK;
- cs->hw.elsa.base = dev_qs1000->base_address[3] &
+ cs->hw.elsa.base = get_pcibase(dev_qs1000, 3) &
PCI_BASE_ADDRESS_IO_MASK;
} else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA,
PCI_QS3000_ID, dev_qs3000))) {
cs->subtyp = ELSA_QS3000PCI;
cs->irq = dev_qs3000->irq;
- cs->hw.elsa.cfg = dev_qs3000->base_address[1] &
+ cs->hw.elsa.cfg = get_pcibase(dev_qs3000, 1) &
PCI_BASE_ADDRESS_IO_MASK;
- cs->hw.elsa.base = dev_qs3000->base_address[3] &
+ cs->hw.elsa.base = get_pcibase(dev_qs3000, 3) &
PCI_BASE_ADDRESS_IO_MASK;
} else {
printk(KERN_WARNING "Elsa: No PCI card found\n");
@@ -1052,18 +1086,6 @@ setup_elsa(struct IsdnCard *card)
printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
return(0);
}
- cs->hw.elsa.ale = cs->hw.elsa.base;
- cs->hw.elsa.isac = cs->hw.elsa.base +1;
- cs->hw.elsa.hscx = cs->hw.elsa.base +1;
- 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);
if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
@@ -1075,6 +1097,67 @@ setup_elsa(struct IsdnCard *card)
restore_flags(flags);
}
#else
+ 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 if (pcibios_find_device(PCI_VENDOR_ELSA,
+ PCI_QS3000_ID, pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL)
+ cs->subtyp = ELSA_QS3000PCI;
+ 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);
+ }
+ pci_index++;
+ 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->irq = pci_irq;
+#endif /* COMPAT_HAS_NEW_PCI */
+ cs->hw.elsa.ale = cs->hw.elsa.base;
+ cs->hw.elsa.isac = cs->hw.elsa.base +1;
+ cs->hw.elsa.hscx = cs->hw.elsa.base +1;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->irq_flags |= SA_SHIRQ;
+ 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);
@@ -1088,6 +1171,7 @@ setup_elsa(struct IsdnCard *card)
case ELSA_PCC16:
case ELSA_QS1000:
case ELSA_PCMCIA:
+ case ELSA_PCMCIA_IPAC:
bytecnt = 8;
break;
case ELSA_PCFPRO:
@@ -1129,6 +1213,9 @@ setup_elsa(struct IsdnCard *card)
request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci");
}
}
+#if ARCOFI_USE
+ init_arcofi(cs);
+#endif
cs->hw.elsa.tl.function = (void *) elsa_led_handler;
cs->hw.elsa.tl.data = (long) cs;
init_timer(&cs->hw.elsa.tl);
@@ -1161,11 +1248,12 @@ setup_elsa(struct IsdnCard *card)
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Elsa_card_msg;
reset_elsa(cs);
- if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
+ if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) {
cs->readisac = &ReadISAC_IPAC;
cs->writeisac = &WriteISAC_IPAC;
cs->readisacfifo = &ReadISACfifo_IPAC;
cs->writeisacfifo = &WriteISACfifo_IPAC;
+ cs->irq_func = &elsa_interrupt_ipac;
val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID);
printk(KERN_INFO "Elsa: IPAC version %x\n", val);
} else {
@@ -1173,6 +1261,7 @@ setup_elsa(struct IsdnCard *card)
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
+ cs->irq_func = &elsa_interrupt;
ISACVersion(cs, "Elsa:");
if (HscxVersion(cs, "Elsa:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index f5ec29839..e4b35e502 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -298,7 +298,7 @@ modem_fill(struct BCState *bcs) {
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st,
bcs->hw.hscx.count);
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
}
}
@@ -510,13 +510,13 @@ close_elsastate(struct BCState *bcs)
bcs->hw.hscx.rcvbuf = NULL;
}
while ((skb = skb_dequeue(&bcs->rqueue))) {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
}
while ((skb = skb_dequeue(&bcs->squeue))) {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_WRITE);
}
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
@@ -664,7 +664,9 @@ modem_l2l1(struct PStack *st, int pr, void *arg)
st->l1.bcs->cs->hw.elsa.MFlag=2;
} else if (pr == (PH_DEACTIVATE | REQUEST)) {
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
- send_arcofi(st->l1.bcs->cs, ARCOFI_XOP_0, st->l1.bc, 0);
+ st->l1.bcs->cs->dc.isac.arcofi_bc = st->l1.bc;
+ arcofi_fsm(st->l1.bcs->cs, ARCOFI_START, &ARCOFI_XOP_0);
+ interruptible_sleep_on(&st->l1.bcs->cs->dc.isac.arcofi_wait);
st->l1.bcs->cs->hw.elsa.MFlag=1;
} else {
printk(KERN_WARNING"ElsaSer: unknown pr %x\n", pr);
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
new file mode 100644
index 000000000..ef64a4702
--- /dev/null
+++ b/drivers/isdn/hisax/gazel.c
@@ -0,0 +1,758 @@
+/* $Id: gazel.c,v 2.6 1999/08/22 20:27:03 calle Exp $
+
+ * gazel.c low level stuff for Gazel isdn cards
+ *
+ * Author BeWan Systems
+ * based on source code from Karsten Keil
+ *
+ * $Log: gazel.c,v $
+ * Revision 2.6 1999/08/22 20:27:03 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 2.5 1999/08/11 21:01:26 keil
+ * new PCI codefix
+ *
+ * Revision 2.4 1999/08/10 16:01:54 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 2.3 1999/07/12 21:05:09 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 2.1 1999/07/08 21:26:17 keil
+ * new card
+ *
+ * Revision 1.0 1999/28/06
+ * Initial revision
+ *
+ */
+#include <linux/config.h>
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include "ipac.h"
+#include <linux/pci.h>
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
+
+extern const char *CardType[];
+const char *gazel_revision = "$Revision: 2.6 $";
+
+#define R647 1
+#define R685 2
+#define R753 3
+#define R742 4
+
+/* Gazel R685 stuff */
+#define GAZEL_MANUFACTURER 0x10b5
+#define GAZEL_R685 0x1030
+#define GAZEL_R753 0x1152
+#define GAZEL_DJINN_ITOO 0x1151
+
+#define PLX_CNTRL 0x50 /* registre de controle PLX */
+#define RESET_GAZEL 0x4
+#define RESET_9050 0x40000000
+#define PLX_INCSR 0x4C /* registre d'IT du 9050 */
+#define INT_ISAC_EN 0x8 /* 1 = enable IT isac */
+#define INT_ISAC 0x20 /* 1 = IT isac en cours */
+#define INT_HSCX_EN 0x1 /* 1 = enable IT hscx */
+#define INT_HSCX 0x4 /* 1 = IT hscx en cours */
+#define INT_PCI_EN 0x40 /* 1 = enable IT PCI */
+#define INT_IPAC_EN 0x3 /* enable IT ipac */
+
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+static inline u_char
+readreg(unsigned int adr, u_short off)
+{
+ return bytein(adr + off);
+}
+
+static inline void
+writereg(unsigned int adr, u_short off, u_char data)
+{
+ byteout(adr + off, data);
+}
+
+
+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);
+}
+
+static inline u_char
+readreg_ipac(unsigned int adr, u_short off)
+{
+ register u_char ret;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(adr, off);
+ ret = bytein(adr + 4);
+ restore_flags(flags);
+ return ret;
+}
+
+static inline void
+writereg_ipac(unsigned int adr, u_short off, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(adr, off);
+ byteout(adr + 4, data);
+ restore_flags(flags);
+}
+
+
+static inline void
+read_fifo_ipac(unsigned int adr, u_short off, u_char * data, int size)
+{
+ byteout(adr, off);
+ insb(adr + 4, data, size);
+}
+
+static void
+write_fifo_ipac(unsigned int adr, u_short off, u_char * data, int size)
+{
+ byteout(adr, off);
+ outsb(adr + 4, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ u_short off2 = offset;
+
+ switch (cs->subtyp) {
+ case R647:
+ off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
+ case R685:
+ return (readreg(cs->hw.gazel.isac, off2));
+ case R753:
+ case R742:
+ return (readreg_ipac(cs->hw.gazel.ipac, 0x80 + off2));
+ }
+ return 0;
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ u_short off2 = offset;
+
+ switch (cs->subtyp) {
+ case R647:
+ off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
+ case R685:
+ writereg(cs->hw.gazel.isac, off2, value);
+ break;
+ case R753:
+ case R742:
+ writereg_ipac(cs->hw.gazel.ipac, 0x80 + off2, value);
+ break;
+ }
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ switch (cs->subtyp) {
+ case R647:
+ case R685:
+ read_fifo(cs->hw.gazel.isacfifo, data, size);
+ break;
+ case R753:
+ case R742:
+ read_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
+ break;
+ }
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ switch (cs->subtyp) {
+ case R647:
+ case R685:
+ write_fifo(cs->hw.gazel.isacfifo, data, size);
+ break;
+ case R753:
+ case R742:
+ write_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
+ break;
+ }
+}
+
+static void
+ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
+{
+ switch (cs->subtyp) {
+ case R647:
+ case R685:
+ read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
+ break;
+ case R753:
+ case R742:
+ read_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
+ break;
+ }
+}
+
+static void
+WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
+{
+ switch (cs->subtyp) {
+ case R647:
+ case R685:
+ write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
+ break;
+ case R753:
+ case R742:
+ write_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
+ break;
+ }
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+ u_short off2 = offset;
+
+ switch (cs->subtyp) {
+ case R647:
+ off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
+ case R685:
+ return (readreg(cs->hw.gazel.hscx[hscx], off2));
+ case R753:
+ case R742:
+ return (readreg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2));
+ }
+ return 0;
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+ u_short off2 = offset;
+
+ switch (cs->subtyp) {
+ case R647:
+ off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
+ case R685:
+ writereg(cs->hw.gazel.hscx[hscx], off2, value);
+ break;
+ case R753:
+ case R742:
+ writereg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2, value);
+ break;
+ }
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
+#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+gazel_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+#define MAXCOUNT 5
+ struct IsdnCardState *cs = dev_id;
+ u_char valisac, valhscx;
+ int count = 0;
+
+ if (!cs) {
+ printk(KERN_WARNING "Gazel: Spurious interrupt!\n");
+ return;
+ }
+ do {
+ valhscx = ReadHSCX(cs, 1, HSCX_ISTA);
+ if (valhscx)
+ hscx_int_main(cs, valhscx);
+ valisac = ReadISAC(cs, ISAC_ISTA);
+ if (valisac)
+ isac_interrupt(cs, valisac);
+ count++;
+ } while ((valhscx || valisac) && (count < MAXCOUNT));
+
+ WriteHSCX(cs, 0, HSCX_MASK, 0xFF);
+ WriteHSCX(cs, 1, HSCX_MASK, 0xFF);
+ WriteISAC(cs, ISAC_MASK, 0xFF);
+ WriteISAC(cs, ISAC_MASK, 0x0);
+ WriteHSCX(cs, 0, HSCX_MASK, 0x0);
+ WriteHSCX(cs, 1, HSCX_MASK, 0x0);
+}
+
+
+static void
+gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char ista, val;
+ int count = 0;
+
+ if (!cs) {
+ printk(KERN_WARNING "Gazel: Spurious interrupt!\n");
+ return;
+ }
+ ista = ReadISAC(cs, IPAC_ISTA - 0x80);
+ do {
+ if (ista & 0x0f) {
+ val = ReadHSCX(cs, 1, HSCX_ISTA);
+ 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 & ReadISAC(cs, ISAC_ISTA);
+ if (val) {
+ isac_interrupt(cs, val);
+ }
+ }
+ if (ista & 0x10) {
+ val = 0x01;
+ isac_interrupt(cs, val);
+ }
+ ista = ReadISAC(cs, IPAC_ISTA - 0x80);
+ count++;
+ }
+ while ((ista & 0x3f) && (count < MAXCOUNT));
+
+ WriteISAC(cs, IPAC_MASK - 0x80, 0xFF);
+ WriteISAC(cs, IPAC_MASK - 0x80, 0xC0);
+}
+void
+release_io_gazel(struct IsdnCardState *cs)
+{
+ unsigned int i;
+
+ switch (cs->subtyp) {
+ case R647:
+ for (i = 0x0000; i < 0xC000; i += 0x1000)
+ release_region(i + cs->hw.gazel.hscx[0], 16);
+ release_region(0xC000 + cs->hw.gazel.hscx[0], 1);
+ break;
+
+ case R685:
+ release_region(cs->hw.gazel.hscx[0], 0x100);
+ release_region(cs->hw.gazel.cfg_reg, 0x80);
+ break;
+
+ case R753:
+ release_region(cs->hw.gazel.ipac, 0x8);
+ release_region(cs->hw.gazel.cfg_reg, 0x80);
+ break;
+
+ case R742:
+ release_region(cs->hw.gazel.ipac, 8);
+ break;
+ }
+}
+
+static int
+reset_gazel(struct IsdnCardState *cs)
+{
+ long flags;
+ unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg;
+
+ switch (cs->subtyp) {
+ case R647:
+ save_flags(flags);
+ cli();
+ writereg(addr, 0, 0);
+ HZDELAY(10);
+ writereg(addr, 0, 1);
+ HZDELAY(2);
+ restore_flags(flags);
+ break;
+ case R685:
+ plxcntrl = inl(addr + PLX_CNTRL);
+ plxcntrl |= (RESET_9050 + RESET_GAZEL);
+ outl(plxcntrl, addr + PLX_CNTRL);
+ plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
+ HZDELAY(4);
+ outl(plxcntrl, addr + PLX_CNTRL);
+ HZDELAY(10);
+ outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR);
+ break;
+ case R753:
+ plxcntrl = inl(addr + PLX_CNTRL);
+ plxcntrl |= (RESET_9050 + RESET_GAZEL);
+ outl(plxcntrl, addr + PLX_CNTRL);
+ plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
+ WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
+ HZDELAY(4);
+ outl(plxcntrl, addr + PLX_CNTRL);
+ HZDELAY(10);
+ WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
+ WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
+ WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
+ WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
+ WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
+ outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR);
+ WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
+ break;
+ case R742:
+ WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
+ HZDELAY(4);
+ WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
+ WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
+ WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
+ WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
+ WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
+ WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
+ break;
+ }
+ return (0);
+}
+
+static int
+Gazel_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ reset_gazel(cs);
+ return (0);
+ case CARD_RELEASE:
+ release_io_gazel(cs);
+ return (0);
+ case CARD_INIT:
+ inithscxisac(cs, 1);
+ if ((cs->subtyp==R647)||(cs->subtyp==R685)) {
+ int i;
+ for (i=0;i<(2+MAX_WAITING_CALLS);i++) {
+ cs->bcs[i].hw.hscx.tsaxr0 = 0x1f;
+ cs->bcs[i].hw.hscx.tsaxr1 = 0x23;
+ }
+ }
+ return (0);
+ case CARD_TEST:
+ return (0);
+ }
+ return (0);
+}
+
+static int
+reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs)
+{
+ unsigned int i, base = 0, adr = 0, len = 0;
+ long flags;
+
+ save_flags(flags);
+ cli();
+
+ switch (cs->subtyp) {
+ case R647:
+ base = cs->hw.gazel.hscx[0];
+ for (i = 0x0000; i < 0xC000; i += 0x1000) {
+ if (check_region(adr = (i + base), len = 16))
+ goto error;
+ }
+ if (check_region(adr = (0xC000 + base), len = 1))
+ goto error;
+
+ for (i = 0x0000; i < 0xC000; i += 0x1000)
+ request_region(i + base, 16, "gazel");
+ request_region(0xC000 + base, 1, "gazel");
+
+ break;
+
+ case R685:
+ if (check_region(adr = cs->hw.gazel.hscx[0], len = 0x100))
+ goto error;
+ if (check_region(adr = cs->hw.gazel.cfg_reg, len = 0x80))
+ goto error;
+
+ request_region(cs->hw.gazel.hscx[0], 0x100, "gazel");
+ request_region(cs->hw.gazel.cfg_reg, 0x80, "gazel");
+ break;
+
+ case R753:
+ if (check_region(adr = cs->hw.gazel.ipac, len = 0x8))
+ goto error;
+ if (check_region(adr = cs->hw.gazel.cfg_reg, len = 0x80))
+ goto error;
+
+ request_region(cs->hw.gazel.ipac, 0x8, "gazel");
+ request_region(cs->hw.gazel.cfg_reg, 0x80, "gazel");
+ break;
+
+ case R742:
+ if (check_region(adr = cs->hw.gazel.ipac, len = 0x8))
+ goto error;
+ request_region(cs->hw.gazel.ipac, 0x8, "gazel");
+ break;
+ }
+
+ restore_flags(flags);
+ return 0;
+
+ error:
+ restore_flags(flags);
+ printk(KERN_WARNING "Gazel: %s io ports 0x%x-0x%x already in use\n",
+ CardType[cs->typ], adr, adr + len);
+ return 1;
+}
+
+static int
+setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
+{
+ printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n");
+ // we got an irq parameter, assume it is an ISA card
+ // R742 decodes address even in not started...
+ // R647 returns FF if not present or not started
+ // eventually needs improvment
+ if (readreg_ipac(card->para[1], IPAC_ID) == 1)
+ cs->subtyp = R742;
+ else
+ cs->subtyp = R647;
+
+ cs->hw.gazel.cfg_reg = card->para[1] + 0xC000;
+ cs->hw.gazel.ipac = card->para[1];
+ cs->hw.gazel.isac = card->para[1] + 0x8000;
+ cs->hw.gazel.hscx[0] = card->para[1];
+ cs->hw.gazel.hscx[1] = card->para[1] + 0x4000;
+ cs->irq = card->para[0];
+ cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
+ cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
+ cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
+
+ switch (cs->subtyp) {
+ case R647:
+ printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n");
+ cs->dc.isac.adf2 = 0x87;
+ printk(KERN_INFO
+ "Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
+ cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
+ printk(KERN_INFO
+ "Gazel: hscx A:0x%X hscx B:0x%X\n",
+ cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
+
+ break;
+ case R742:
+ printk(KERN_INFO "Gazel: Card ISA R742 found\n");
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ printk(KERN_INFO
+ "Gazel: config irq:%d ipac:0x%X\n",
+ cs->irq, cs->hw.gazel.ipac);
+ break;
+ }
+
+ return (0);
+}
+
+#ifdef COMPAT_HAS_NEW_PCI
+static struct pci_dev *dev_tel __initdata = NULL;
+#else
+static int pci_index __initdata = 0;
+#endif
+
+static int
+setup_gazelpci(struct IsdnCardState *cs)
+{
+ u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
+ u_char pci_irq = 0, found;
+ u_int nbseek, seekcard;
+
+ printk(KERN_WARNING "Gazel: PCI card automatic recognition\n");
+
+ found = 0;
+#ifdef COMPAT_HAS_NEW_PCI
+ if (!pci_present()) {
+ printk(KERN_WARNING "Gazel: No PCI bus present\n");
+ return 1;
+ }
+#endif
+ seekcard = GAZEL_R685;
+ for (nbseek = 0; nbseek < 3; nbseek++) {
+#ifdef COMPAT_HAS_NEW_PCI
+ if ((dev_tel = pci_find_device(GAZEL_MANUFACTURER, seekcard, dev_tel))) {
+
+ pci_irq = dev_tel->irq;
+ pci_ioaddr0 = get_pcibase(dev_tel, 1);
+ pci_ioaddr1 = get_pcibase(dev_tel, 2);
+ found = 1;
+ }
+#else
+ for (; pci_index < 0xff; pci_index++) {
+ u_char pci_bus, pci_device_fn;
+
+ if (pcibios_find_device(GAZEL_MANUFACTURER, seekcard,
+ pci_index, &pci_bus, &pci_device_fn)
+ != PCIBIOS_SUCCESSFUL)
+ 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_ioaddr0);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_2, &pci_ioaddr1);
+ found = 1;
+ break;
+ }
+#endif /* COMPAT_HAS_NEW_PCI */
+ if (found)
+ break;
+ else {
+ switch (seekcard) {
+ case GAZEL_R685:
+ seekcard = GAZEL_R753;
+ break;
+ case GAZEL_R753:
+ seekcard = GAZEL_DJINN_ITOO;
+ break;
+ }
+#ifndef COMPAT_HAS_NEW_PCI
+ pci_index = 0;
+#endif
+ }
+ }
+ if (!found) {
+ printk(KERN_WARNING "Gazel: No PCI card found\n");
+ return (1);
+ }
+ if (!pci_irq) {
+ printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n");
+ return 1;
+ }
+ cs->hw.gazel.pciaddr[0] = pci_ioaddr0;
+ cs->hw.gazel.pciaddr[1] = pci_ioaddr1;
+
+ pci_ioaddr1 &= 0xfffe;
+ cs->hw.gazel.cfg_reg = pci_ioaddr0 & 0xfffe;
+ cs->hw.gazel.ipac = pci_ioaddr1;
+ cs->hw.gazel.isac = pci_ioaddr1 + 0x80;
+ cs->hw.gazel.hscx[0] = pci_ioaddr1;
+ cs->hw.gazel.hscx[1] = pci_ioaddr1 + 0x40;
+ cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
+ cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
+ cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
+ cs->irq = pci_irq;
+ cs->irq_flags |= SA_SHIRQ;
+
+ switch (seekcard) {
+ case GAZEL_R685:
+ printk(KERN_INFO "Gazel: Card PCI R685 found\n");
+ cs->subtyp = R685;
+ cs->dc.isac.adf2 = 0x87;
+ printk(KERN_INFO
+ "Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
+ cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
+ printk(KERN_INFO
+ "Gazel: hscx A:0x%X hscx B:0x%X\n",
+ cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
+ break;
+ case GAZEL_R753:
+ case GAZEL_DJINN_ITOO:
+ printk(KERN_INFO "Gazel: Card PCI R753 found\n");
+ cs->subtyp = R753;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ printk(KERN_INFO
+ "Gazel: config irq:%d ipac:0x%X cfg:0x%X\n",
+ cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg);
+ break;
+ }
+
+ return (0);
+}
+
+int __init
+ setup_gazel(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ u_char val;
+
+ strcpy(tmp, gazel_revision);
+ printk(KERN_INFO "Gazel: Driver Revision %s\n", HiSax_getrev(tmp));
+
+ if (cs->typ != ISDN_CTYPE_GAZEL)
+ return (0);
+
+ if (card->para[0]) {
+ if (setup_gazelisa(card, cs))
+ return (0);
+ } else {
+
+#if CONFIG_PCI
+ if (setup_gazelpci(cs))
+ return (0);
+#else
+ printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n");
+ return (0);
+#endif /* CONFIG_PCI */
+ }
+
+ if (reserve_regions(card, cs)) {
+ return (0);
+ }
+ if (reset_gazel(cs)) {
+ printk(KERN_WARNING "Gazel: wrong IRQ\n");
+ release_io_gazel(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 = &Gazel_card_msg;
+
+ switch (cs->subtyp) {
+ case R647:
+ case R685:
+ cs->irq_func = &gazel_interrupt;
+ ISACVersion(cs, "Gazel:");
+ if (HscxVersion(cs, "Gazel:")) {
+ printk(KERN_WARNING
+ "Gazel: wrong HSCX versions check IO address\n");
+ release_io_gazel(cs);
+ return (0);
+ }
+ break;
+ case R742:
+ case R753:
+ cs->irq_func = &gazel_interrupt_ipac;
+ val = ReadISAC(cs, IPAC_ID - 0x80);
+ printk(KERN_INFO "Gazel: IPAC version %x\n", val);
+ break;
+ }
+
+ return (1);
+}
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index 4e734b2c6..266916c39 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bds0.c,v 1.8 1998/11/15 23:54:40 keil Exp $
+/* $Id: hfc_2bds0.c,v 1.9 1999/07/01 08:11:35 keil Exp $
*
* specific routines for CCD's HFC 2BDS0
*
@@ -6,6 +6,9 @@
*
*
* $Log: hfc_2bds0.c,v $
+ * Revision 1.9 1999/07/01 08:11:35 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.8 1998/11/15 23:54:40 keil
* changes from 2.0
*
@@ -264,6 +267,7 @@ static struct sk_buff
} else if (!(skb = dev_alloc_skb(count - 3)))
printk(KERN_WARNING "HFC: receive out of memory\n");
else {
+ SET_SKB_FREE(skb);
ptr = skb_put(skb, count - 3);
idx = 0;
cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
@@ -281,7 +285,7 @@ static struct sk_buff
sti();
debugl1(cs, "RFIFO BUSY error");
printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
skb = NULL;
} else {
cli();
@@ -297,7 +301,7 @@ static struct sk_buff
bcs->channel, chksum, stat);
if (stat) {
debugl1(cs, "FIFO CRC error");
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
skb = NULL;
}
}
@@ -386,7 +390,7 @@ hfc_fill_fifo(struct BCState *bcs)
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
}
WaitForBusy(cs);
@@ -588,7 +592,7 @@ close_2bs0(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
@@ -642,7 +646,7 @@ hfcd_bh(struct IsdnCardState *cs)
}
#endif
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
- switch (cs->ph_state) {
+ switch (cs->dc.hfcd.ph_state) {
case (0):
l1_msg(cs, HW_RESET | INDICATION, NULL);
break;
@@ -733,6 +737,7 @@ int receive_dmsg(struct IsdnCardState *cs)
while ((idx++ < rcnt) && WaitNoBusy(cs))
ReadReg(cs, HFCD_DATA_NODEB, cip);
} else if ((skb = dev_alloc_skb(rcnt - 3))) {
+ SET_SKB_FREE(skb);
ptr = skb_put(skb, rcnt - 3);
while (idx < (rcnt - 3)) {
cli();
@@ -747,7 +752,7 @@ int receive_dmsg(struct IsdnCardState *cs)
sti();
debugl1(cs, "RFIFO D BUSY error");
printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n");
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
skb = NULL;
} else {
cli();
@@ -763,7 +768,7 @@ int receive_dmsg(struct IsdnCardState *cs)
chksum, stat);
if (stat) {
debugl1(cs, "FIFO CRC error");
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
skb = NULL;
} else {
skb_queue_tail(&cs->rq, skb);
@@ -860,7 +865,7 @@ hfc_fill_dfifo(struct IsdnCardState *cs)
cli();
WaitNoBusy(cs);
ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND);
- dev_kfree_skb(cs->tx_skb);
+ idev_kfree_skb(cs->tx_skb, FREE_WRITE);
cs->tx_skb = NULL;
sti();
WaitForBusy(cs);
@@ -895,9 +900,9 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
if (val & 0x40) { /* TE state machine irq */
exval = cs->readisac(cs, HFCD_STATES) & 0xf;
if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_state chg %d->%d", cs->ph_state,
+ debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcd.ph_state,
exval);
- cs->ph_state = exval;
+ cs->dc.hfcd.ph_state = exval;
sched_event_D(cs, D_L1STATECHANGE);
val &= ~0x40;
}
@@ -984,7 +989,7 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
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) {
if (cs->tx_skb->len) {
if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
hfc_fill_dfifo(cs);
@@ -994,10 +999,11 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
}
goto afterXPR;
} else {
- dev_kfree_skb(cs->tx_skb);
+ idev_kfree_skb(cs->tx_skb, FREE_WRITE);
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)) {
@@ -1166,8 +1172,8 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
#endif
}
-unsigned int __init
-*init_send_hfcd(int cnt)
+unsigned int * __init
+init_send_hfcd(int cnt)
{
int i, *send;
@@ -1181,7 +1187,7 @@ unsigned int __init
return(send);
}
-void __init
+void __init
init2bds0(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_hfcd;
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index 13225cb7a..71767c888 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bs0.c,v 1.8 1998/11/15 23:54:43 keil Exp $
+/* $Id: hfc_2bs0.c,v 1.9 1999/07/01 08:11:36 keil Exp $
* specific routines for CCD's HFC 2BS0
*
@@ -6,6 +6,9 @@
*
*
* $Log: hfc_2bs0.c,v $
+ * Revision 1.9 1999/07/01 08:11:36 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.8 1998/11/15 23:54:43 keil
* changes from 2.0
*
@@ -219,6 +222,7 @@ hfc_empty_fifo(struct BCState *bcs, int count)
if (!(skb = dev_alloc_skb(count - 3)))
printk(KERN_WARNING "HFC: receive out of memory\n");
else {
+ SET_SKB_FREE(skb);
ptr = skb_put(skb, count - 3);
idx = 0;
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
@@ -229,7 +233,7 @@ hfc_empty_fifo(struct BCState *bcs, int count)
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);
+ idev_kfree_skb(skb, FREE_READ);
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
@@ -247,7 +251,7 @@ hfc_empty_fifo(struct BCState *bcs, int count)
bcs->channel, chksum, stat);
if (stat) {
debugl1(cs, "FIFO CRC error");
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
skb = NULL;
}
WaitNoBusy(cs);
@@ -321,7 +325,7 @@ hfc_fill_fifo(struct BCState *bcs)
bcs->tx_cnt -= count;
if (PACKET_NOACK == bcs->tx_skb->pkt_type)
count = -1;
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
WaitForBusy(cs);
WaitNoBusy(cs);
@@ -519,7 +523,7 @@ close_hfcstate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
@@ -555,7 +559,7 @@ setstack_hfc(struct PStack *st, struct BCState *bcs)
return (0);
}
-void __init
+void __init
init_send(struct BCState *bcs)
{
int i;
@@ -569,7 +573,7 @@ init_send(struct BCState *bcs)
bcs->hw.hfc.send[i] = 0x1fff;
}
-void __init
+void __init
inithfc(struct IsdnCardState *cs)
{
init_send(&cs->bcs[0]);
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
new file mode 100644
index 000000000..9d8968e98
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -0,0 +1,1744 @@
+/* $Id: hfc_pci.c,v 1.18 1999/08/29 17:05:44 werner Exp $
+
+ * hfc_pci.c low level driver for CCD´s hfc-pci based cards
+ *
+ * Author Werner Cornelius (werner@isdn4linux.de)
+ * based on existing driver for CCD hfc ISA cards
+ *
+ * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
+ * Copyright 1999 by Karsten Keil (keil@isdn4linux.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: hfc_pci.c,v $
+ * Revision 1.18 1999/08/29 17:05:44 werner
+ * corrected tx_lo line setup. Datasheet is not correct.
+ *
+ * Revision 1.17 1999/08/28 21:04:27 werner
+ * Implemented full audio support (transparent mode)
+ *
+ * Revision 1.16 1999/08/25 17:01:27 keil
+ * Use new LL->HL auxcmd call
+ *
+ * Revision 1.15 1999/08/22 20:27:05 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.14 1999/08/12 18:59:45 werner
+ * Added further manufacturer and device ids to PCI list
+ *
+ * Revision 1.13 1999/08/11 21:01:28 keil
+ * new PCI codefix
+ *
+ * Revision 1.12 1999/08/10 16:01:58 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 1.11 1999/08/09 19:13:32 werner
+ * moved constant pci ids to pci id table
+ *
+ * Revision 1.10 1999/08/08 10:17:34 werner
+ * added new PCI vendor and card ids for Manufacturer 0x1043
+ *
+ * Revision 1.9 1999/08/07 21:09:10 werner
+ * Fixed another memcpy problem in fifo handling.
+ * Thanks for debugging aid by Olaf Kordwittenborg.
+ *
+ * Revision 1.8 1999/07/23 14:25:15 werner
+ * Some smaller bug fixes and prepared support for GCI/IOM bus
+ *
+ * Revision 1.7 1999/07/14 21:24:20 werner
+ * fixed memcpy problem when using E-channel feature
+ *
+ * Revision 1.6 1999/07/13 21:08:08 werner
+ * added echo channel logging feature.
+ *
+ * Revision 1.5 1999/07/12 21:05:10 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.4 1999/07/04 21:51:39 werner
+ * Changes to solve problems with irq sharing and smp machines
+ * Thanks to Karsten Keil and Alex Holden for giving aid with
+ * testing and debugging
+ *
+ * Revision 1.3 1999/07/01 09:43:19 keil
+ * removed additional schedules in timeouts
+ *
+ * Revision 1.2 1999/07/01 08:07:51 keil
+ * Initial version
+ *
+ *
+ *
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_pci.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
+#include <linux/interrupt.h>
+
+extern const char *CardType[];
+
+static const char *hfcpci_revision = "$Revision: 1.18 $";
+
+/* table entry in the PCI devices list */
+typedef struct {
+ int vendor_id;
+ int device_id;
+ char *vendor_name;
+ char *card_name;
+ } PCI_ENTRY;
+
+static const PCI_ENTRY id_list[] = {
+ {0x1397,0x2BD0,"CCD/Billion/Asuscom","2BD0"},
+ {0x1397,0xB000,"Billion","B000"},
+ {0x1397,0xB006,"Billion","B006"},
+ {0x1397,0xB007,"Billion","B007"},
+ {0x1397,0xB008,"Billion","B008"},
+ {0x1397,0xB009,"Billion","B009"},
+ {0x1397,0xB00A,"Billion","B00A"},
+ {0x1397,0xB00B,"Billion","B00B"},
+ {0x1397,0xB00C,"Billion","B00C"},
+ {0x1043,0x0675,"Asuscom/Askey","675"},
+ {0x0871,0xFFA2,"German telekom","T-Concept"},
+ {0x0871,0xFFA1,"German telekom","A1T"},
+ {0x1051,0x0100,"Motorola MC145575","MC145575"},
+ {0x1397,0xB100,"Seyeon","B100"},
+ {0x15B0,0x2BD0,"Zoltrix","2BD0"},
+ {0,0,NULL,NULL},
+};
+
+
+#if CONFIG_PCI
+/*****************************/
+/* release D- and B-channels */
+/*****************************/
+void
+releasehfcpci(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;
+ }
+}
+
+/******************************************/
+/* free hardware resources used by driver */
+/******************************************/
+void
+release_io_hfcpci(struct IsdnCardState *cs)
+{
+#if CONFIG_PCI
+ pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0); /* disabe memory mapped ports + busmaster */
+#endif /* CONFIG_PCI */
+ releasehfcpci(cs);
+ del_timer(&cs->hw.hfcpci.timer);
+ kfree(cs->hw.hfcpci.share_start);
+ cs->hw.hfcpci.share_start = NULL;
+ vfree(cs->hw.hfcpci.pci_io);
+}
+
+/********************************************************************************/
+/* function called to reset the HFC PCI chip. A complete software reset of chip */
+/* and fifos is done. */
+/********************************************************************************/
+static void
+reset_hfcpci(struct IsdnCardState *cs)
+{
+ long flags;
+
+ pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */
+ printk(KERN_INFO "HFC_PCI: resetting card\n");
+ pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */
+ Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
+ Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+ if (Read_hfc(cs, HFCPCI_STATUS) & 2)
+ printk(KERN_WARNING "HFC-PCI init bit busy\n");
+
+ cs->hw.hfcpci.fifo_en = 0x30; /* only D fifos enabled */
+ Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
+
+ cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
+ Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
+
+ Write_hfc(cs, HFCPCI_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */
+ cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE;
+ Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */
+ cs->hw.hfcpci.bswapped = 0; /* no exchange */
+ cs->hw.hfcpci.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
+ Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
+
+ cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
+ cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
+ HFCPCI_INTS_L1STATE | HFCPCI_CLTIMER;
+ Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+ Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+
+ /* Clear already pending ints */
+ if (Read_hfc(cs, HFCPCI_INT_S1));
+ if (Read_hfc(cs, HFCPCI_INT_S2));
+
+ Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2); /* HFC ST 2 */
+ udelay(10);
+ Write_hfc(cs, HFCPCI_STATES, 2); /* HFC ST 2 */
+ cs->hw.hfcpci.mst_m = HFCPCI_MASTER; /* HFC Master Mode */
+
+ Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
+ cs->hw.hfcpci.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
+ Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
+ cs->hw.hfcpci.sctrl_r = 0;
+ Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
+
+ /* Init GCI/IOM2 in master mode */
+ /* Slots 0 and 1 are set for B-chan 1 and 2 */
+ /* D- and monitor/CI channel are not enabled */
+ /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
+ /* STIO2 is used as data input, B1+B2 from IOM->ST */
+ /* ST B-channel send disabled -> continous 1s */
+ /* The IOM slots are always enabled */
+ cs->hw.hfcpci.conn = 0x36; /* set data flow directions */
+ Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+ Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */
+ Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */
+ Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */
+ Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */
+ restore_flags(flags);
+}
+
+/***************************************************/
+/* Timer function called when kernel timer expires */
+/***************************************************/
+static void
+hfcpci_Timer(struct IsdnCardState *cs)
+{
+ cs->hw.hfcpci.timer.expires = jiffies + 75;
+ /* WD RESET */
+/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcpci.ctmt | 0x80);
+ add_timer(&cs->hw.hfcpci.timer);
+ */
+}
+
+
+/*********************************/
+/* schedule a new D-channel task */
+/*********************************/
+static void
+sched_event_D_pci(struct IsdnCardState *cs, int event)
+{
+ test_and_set_bit(event, &cs->event);
+ queue_task(&cs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+/*********************************/
+/* schedule a new b_channel task */
+/*********************************/
+static void
+hfcpci_sched_event(struct BCState *bcs, int event)
+{
+ bcs->event |= 1 << event;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+/************************************************/
+/* select a b-channel entry matching and active */
+/************************************************/
+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);
+}
+
+/*********************************************/
+/* read a complete B-frame out of the buffer */
+/*********************************************/
+static struct sk_buff
+*
+hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u_char * bdata, int count)
+{
+ u_char *ptr, *ptr1, new_f2;
+ struct sk_buff *skb;
+ struct IsdnCardState *cs = bcs->cs;
+ int flags, total, maxlen, new_z2;
+ z_type *zp;
+
+ save_flags(flags);
+ sti();
+ if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+ debugl1(cs, "hfcpci_empty_fifo");
+ zp = &bz->za[bz->f2]; /* point to Z-Regs */
+ new_z2 = zp->z2 + count; /* new position in fifo */
+ if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
+ new_z2 -= B_FIFO_SIZE; /* buffer wrap */
+ new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
+ if ((count > HSCX_BUFMAX + 3) || (count < 4) ||
+ (*(bdata + (zp->z1 - B_SUB_VAL)))) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count);
+ bz->za[new_f2].z2 = new_z2;
+ bz->f2 = new_f2; /* next buffer */
+ skb = NULL;
+ } else if (!(skb = dev_alloc_skb(count - 3)))
+ printk(KERN_WARNING "HFCPCI: receive out of memory\n");
+ else {
+ SET_SKB_FREE(skb);
+ total = count;
+ count -= 3;
+ ptr = skb_put(skb, count);
+
+ if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
+ maxlen = count; /* complete transfer */
+ else
+ maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */
+
+ ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */
+ memcpy(ptr, ptr1, maxlen); /* copy data */
+ count -= maxlen;
+
+ if (count) { /* rest remaining */
+ ptr += maxlen;
+ ptr1 = bdata; /* start of buffer */
+ memcpy(ptr, ptr1, count); /* rest */
+ }
+ bz->za[new_f2].z2 = new_z2;
+ bz->f2 = new_f2; /* next buffer */
+
+ }
+ restore_flags(flags);
+ return (skb);
+}
+
+/*******************************/
+/* D-channel receive procedure */
+/*******************************/
+static
+int
+receive_dmsg(struct IsdnCardState *cs)
+{
+ struct sk_buff *skb;
+ int maxlen;
+ int rcnt, total;
+ int count = 5;
+ u_char *ptr, *ptr1;
+ dfifo_type *df;
+ z_type *zp;
+
+ df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_rx;
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ debugl1(cs, "rec_dmsg blocked");
+ return (1);
+ }
+ while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {
+ zp = &df->za[df->f2 & D_FREG_MASK];
+ rcnt = zp->z1 - zp->z2;
+ if (rcnt < 0)
+ rcnt += D_FIFO_SIZE;
+ rcnt++;
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",
+ df->f1, df->f2, zp->z1, zp->z2, rcnt);
+
+ if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) ||
+ (df->data[zp->z1])) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]);
+ df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */
+ df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1);
+ } else if ((skb = dev_alloc_skb(rcnt - 3))) {
+ SET_SKB_FREE(skb);
+ total = rcnt;
+ rcnt -= 3;
+ ptr = skb_put(skb, rcnt);
+
+ if (zp->z2 + rcnt <= D_FIFO_SIZE)
+ maxlen = rcnt; /* complete transfer */
+ else
+ maxlen = D_FIFO_SIZE - zp->z2; /* maximum */
+
+ ptr1 = df->data + zp->z2; /* start of data */
+ memcpy(ptr, ptr1, maxlen); /* copy data */
+ rcnt -= maxlen;
+
+ if (rcnt) { /* rest remaining */
+ ptr += maxlen;
+ ptr1 = df->data; /* start of buffer */
+ memcpy(ptr, ptr1, rcnt); /* rest */
+ }
+ df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */
+ df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + total) & (D_FIFO_SIZE - 1);
+
+ skb_queue_tail(&cs->rq, skb);
+ sched_event_D_pci(cs, D_RCVBUFREADY);
+ } else
+ printk(KERN_WARNING "HFC-PCI: D receive out of memory\n");
+ }
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ return (1);
+}
+
+/*******************************************************************************/
+/* check for transparent receive data and read max one threshold size if avail */
+/*******************************************************************************/
+int hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type *bz, u_char *bdata)
+{ unsigned short *z1r, *z2r;
+ int new_z2, fcnt, maxlen;
+ struct sk_buff *skb;
+ u_char *ptr, *ptr1;
+
+ z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
+ z2r = z1r + 1;
+
+ if (!(fcnt = *z1r - *z2r))
+ return(0); /* no data avail */
+
+ if (fcnt <= 0)
+ fcnt += B_FIFO_SIZE; /* bytes actually buffered */
+ if (fcnt > HFCPCI_BTRANS_THRESHOLD)
+ fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */
+
+ new_z2 = *z2r + fcnt; /* new position in fifo */
+ if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
+ new_z2 -= B_FIFO_SIZE; /* buffer wrap */
+
+ if (!(skb = dev_alloc_skb(fcnt)))
+ printk(KERN_WARNING "HFCPCI: receive out of memory\n");
+ else {
+ SET_SKB_FREE(skb);
+ ptr = skb_put(skb, fcnt);
+ if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
+ maxlen = fcnt; /* complete transfer */
+ else
+ maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r; /* maximum */
+
+ ptr1 = bdata + (*z2r - B_SUB_VAL); /* start of data */
+ memcpy(ptr, ptr1, maxlen); /* copy data */
+ fcnt -= maxlen;
+
+ if (fcnt) { /* rest remaining */
+ ptr += maxlen;
+ ptr1 = bdata; /* start of buffer */
+ memcpy(ptr, ptr1, fcnt); /* rest */
+ }
+ cli();
+ skb_queue_tail(&bcs->rqueue, skb);
+ sti();
+ hfcpci_sched_event(bcs, B_RCVBUFREADY);
+ }
+
+ *z2r = new_z2; /* new position */
+ return(1);
+} /* hfcpci_empty_fifo_trans */
+
+/**********************************/
+/* B-channel main receive routine */
+/**********************************/
+void
+main_rec_hfcpci(struct BCState *bcs)
+{
+ long flags;
+ struct IsdnCardState *cs = bcs->cs;
+ int rcnt;
+ int receive, count = 5;
+ struct sk_buff *skb;
+ bzfifo_type *bz;
+ u_char *bdata;
+ z_type *zp;
+
+
+ save_flags(flags);
+ if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) {
+ bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
+ bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2;
+ } else {
+ bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
+ bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b1;
+ }
+ Begin:
+ count--;
+ cli();
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ debugl1(cs, "rec_data %d blocked", bcs->channel);
+ restore_flags(flags);
+ return;
+ }
+ sti();
+ if (bz->f1 != bz->f2) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfcpci rec %d f1(%d) f2(%d)",
+ bcs->channel, bz->f1, bz->f2);
+ zp = &bz->za[bz->f2];
+
+ rcnt = zp->z1 - zp->z2;
+ if (rcnt < 0)
+ rcnt += B_FIFO_SIZE;
+ rcnt++;
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfcpci rec %d z1(%x) z2(%x) cnt(%d)",
+ bcs->channel, zp->z1, zp->z2, rcnt);
+ if ((skb = hfcpci_empty_fifo(bcs, bz, bdata, rcnt))) {
+ cli();
+ skb_queue_tail(&bcs->rqueue, skb);
+ sti();
+ hfcpci_sched_event(bcs, B_RCVBUFREADY);
+ }
+ rcnt = bz->f1 - bz->f2;
+ if (rcnt < 0)
+ rcnt += MAX_B_FRAMES + 1;
+ if (rcnt > 1)
+ receive = 1;
+ else
+ receive = 0;
+ } else
+ if (bcs->mode == L1_MODE_TRANS)
+ receive = hfcpci_empty_fifo_trans(bcs, bz, bdata);
+ else
+ receive = 0;
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ if (count && receive)
+ goto Begin;
+ restore_flags(flags);
+ return;
+}
+
+/**************************/
+/* D-channel send routine */
+/**************************/
+static void
+hfcpci_fill_dfifo(struct IsdnCardState *cs)
+{
+ long flags;
+ int fcnt;
+ int count, new_z1, maxlen;
+ dfifo_type *df;
+ u_char *src, *dst, new_f1;
+
+ if (!cs->tx_skb)
+ return;
+ if (cs->tx_skb->len <= 0)
+ return;
+
+ df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_tx;
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "hfcpci_fill_Dfifo f1(%d) f2(%d) z1(f1)(%x)",
+ df->f1, df->f2,
+ df->za[df->f1 & D_FREG_MASK].z1);
+ fcnt = df->f1 - df->f2; /* frame count actually buffered */
+ if (fcnt < 0)
+ fcnt += (MAX_D_FRAMES + 1); /* if wrap around */
+ if (fcnt > (MAX_D_FRAMES - 1)) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames");
+ return;
+ }
+ /* now determine free bytes in FIFO buffer */
+ count = df->za[df->f1 & D_FREG_MASK].z2 - df->za[df->f1 & D_FREG_MASK].z1;
+ if (count <= 0)
+ count += D_FIFO_SIZE; /* count now contains available bytes */
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "hfcpci_fill_Dfifo count(%ld/%d)",
+ cs->tx_skb->len, count);
+ if (count < cs->tx_skb->len) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "hfcpci_fill_Dfifo no fifo mem");
+ return;
+ }
+ count = cs->tx_skb->len; /* get frame len */
+ new_z1 = (df->za[df->f1 & D_FREG_MASK].z1 + count) & (D_FIFO_SIZE - 1);
+ new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1);
+ src = cs->tx_skb->data; /* source pointer */
+ dst = df->data + df->za[df->f1 & D_FREG_MASK].z1;
+ maxlen = D_FIFO_SIZE - df->za[df->f1 & D_FREG_MASK].z1; /* end fifo */
+ if (maxlen > count)
+ maxlen = count; /* limit size */
+ memcpy(dst, src, maxlen); /* first copy */
+
+ count -= maxlen; /* remaining bytes */
+ if (count) {
+ dst = df->data; /* start of buffer */
+ src += maxlen; /* new position */
+ memcpy(dst, src, count);
+ }
+ save_flags(flags);
+ cli();
+ df->za[new_f1 & D_FREG_MASK].z1 = new_z1; /* for next buffer */
+ df->za[df->f1 & D_FREG_MASK].z1 = new_z1; /* new pos actual buffer */
+ df->f1 = new_f1; /* next frame */
+ restore_flags(flags);
+
+ idev_kfree_skb(cs->tx_skb, FREE_WRITE);
+ cs->tx_skb = NULL;
+ return;
+}
+
+/**************************/
+/* B-channel send routine */
+/**************************/
+static void
+hfcpci_fill_fifo(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int flags, maxlen, fcnt;
+ int count, new_z1;
+ bzfifo_type *bz;
+ u_char *bdata;
+ u_char new_f1, *src, *dst;
+ unsigned short *z1t, *z2t;
+
+ if (!bcs->tx_skb)
+ return;
+ if (bcs->tx_skb->len <= 0)
+ return;
+
+ save_flags(flags);
+ sti();
+
+ if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) {
+ bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
+ bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b2;
+ } else {
+ bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
+ bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b1;
+ }
+
+ if (bcs->mode == L1_MODE_TRANS) {
+ z1t = &bz->za[MAX_B_FRAMES].z1;
+ z2t = z1t + 1;
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
+ bcs->channel, *z1t, *z2t);
+ fcnt = *z2t - *z1t;
+ if (fcnt <= 0)
+ fcnt += B_FIFO_SIZE; /* fcnt contains available bytes in fifo */
+ fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */
+
+ while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) {
+ if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) {
+ /* data is suitable for fifo */
+ count = bcs->tx_skb->len;
+
+ new_z1 = *z1t + count; /* new buffer Position */
+ if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
+ new_z1 -= B_FIFO_SIZE; /* buffer wrap */
+ src = bcs->tx_skb->data; /* source pointer */
+ dst = bdata + (*z1t - B_SUB_VAL);
+ maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */
+ if (maxlen > count)
+ maxlen = count; /* limit size */
+ memcpy(dst, src, maxlen); /* first copy */
+
+ count -= maxlen; /* remaining bytes */
+ if (count) {
+ dst = bdata; /* start of buffer */
+ src += maxlen; /* new position */
+ memcpy(dst, src, count);
+ }
+ bcs->tx_cnt -= bcs->tx_skb->len;
+ fcnt += bcs->tx_skb->len;
+ *z1t = new_z1; /* now send data */
+ }
+ else
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
+ bcs->channel, bcs->tx_skb->len);
+
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
+ cli();
+ bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */
+ sti();
+ }
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ restore_flags(flags);
+ return;
+ }
+
+
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)",
+ bcs->channel, bz->f1, bz->f2,
+ bz->za[bz->f1].z1);
+
+ fcnt = bz->f1 - bz->f2; /* frame count actually buffered */
+ if (fcnt < 0)
+ fcnt += (MAX_B_FRAMES + 1); /* if wrap around */
+ if (fcnt > (MAX_B_FRAMES - 1)) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfcpci_fill_Bfifo more as 14 frames");
+ restore_flags(flags);
+ return;
+ }
+ /* now determine free bytes in FIFO buffer */
+ count = bz->za[bz->f1].z2 - bz->za[bz->f1].z1;
+ if (count <= 0)
+ count += B_FIFO_SIZE; /* count now contains available bytes */
+
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfcpci_fill_fifo %d count(%ld/%d),%lx",
+ bcs->channel, bcs->tx_skb->len,
+ count, current->state);
+
+ if (count < bcs->tx_skb->len) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfcpci_fill_fifo no fifo mem");
+ restore_flags(flags);
+ return;
+ }
+ count = bcs->tx_skb->len; /* get frame len */
+ new_z1 = bz->za[bz->f1].z1 + count; /* new buffer Position */
+ if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
+ new_z1 -= B_FIFO_SIZE; /* buffer wrap */
+
+ new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES);
+ src = bcs->tx_skb->data; /* source pointer */
+ dst = bdata + (bz->za[bz->f1].z1 - B_SUB_VAL);
+ maxlen = (B_FIFO_SIZE + B_SUB_VAL) - bz->za[bz->f1].z1; /* end fifo */
+ if (maxlen > count)
+ maxlen = count; /* limit size */
+ memcpy(dst, src, maxlen); /* first copy */
+
+ count -= maxlen; /* remaining bytes */
+ if (count) {
+ dst = bdata; /* start of buffer */
+ src += maxlen; /* new position */
+ memcpy(dst, src, count);
+ }
+ bcs->tx_cnt -= bcs->tx_skb->len;
+ if (bcs->st->lli.l1writewakeup &&
+ (PACKET_NOACK != bcs->tx_skb->pkt_type))
+ bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
+
+ cli();
+ bz->za[new_f1].z1 = new_z1; /* for next buffer */
+ bz->f1 = new_f1; /* next frame */
+ restore_flags(flags);
+
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
+ bcs->tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ return;
+}
+
+/***********************/
+/* set/reset echo mode */
+/***********************/
+static int
+hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic)
+{
+ int flags;
+ int i = *(unsigned int *) ic->parm.num;
+
+ if (cs->chanlimit > 1)
+ return(-EINVAL);
+
+ save_flags(flags);
+ cli();
+ if (i) {
+ cs->logecho = 1;
+ cs->hw.hfcpci.trm |= 0x20; /* enable echo chan */
+ cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC;
+ cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX;
+ }
+ else {
+ cs->logecho = 0;
+ cs->hw.hfcpci.trm &= ~0x20; /* enable echo chan */
+ cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC;
+ cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX;
+ }
+ cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
+ cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
+ cs->hw.hfcpci.conn |= 0x10; /* B2-IOM -> B2-ST */
+ cs->hw.hfcpci.ctmt &= ~2;
+ Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
+ Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
+ Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
+ Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+ Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
+ Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
+ Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+ restore_flags(flags);
+ return(0);
+} /* hfcpci_auxcmd */
+
+/*****************************/
+/* E-channel receive routine */
+/*****************************/
+static void receive_emsg(struct IsdnCardState *cs)
+{
+ long flags;
+ int rcnt;
+ int receive, count = 5;
+ bzfifo_type *bz;
+ u_char *bdata;
+ z_type *zp;
+ u_char *ptr, *ptr1, new_f2;
+ int total, maxlen, new_z2;
+ u_char e_buffer[256];
+
+ save_flags(flags);
+ bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
+ bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2;
+ Begin:
+ count--;
+ cli();
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ debugl1(cs, "echo_rec_data blocked");
+ restore_flags(flags);
+ return;
+ }
+ sti();
+ if (bz->f1 != bz->f2) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "hfcpci e_rec f1(%d) f2(%d)",
+ bz->f1, bz->f2);
+ zp = &bz->za[bz->f2];
+
+ rcnt = zp->z1 - zp->z2;
+ if (rcnt < 0)
+ rcnt += B_FIFO_SIZE;
+ rcnt++;
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)",
+ zp->z1, zp->z2, rcnt);
+ new_z2 = zp->z2 + rcnt; /* new position in fifo */
+ if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
+ new_z2 -= B_FIFO_SIZE; /* buffer wrap */
+ new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
+ if ((rcnt > 256 + 3) || (count < 4) ||
+ (*(bdata + (zp->z1 - B_SUB_VAL)))) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
+ bz->za[new_f2].z2 = new_z2;
+ bz->f2 = new_f2; /* next buffer */
+ } else {
+ total = rcnt;
+ rcnt -= 3;
+ ptr = e_buffer;
+
+ if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
+ maxlen = rcnt; /* complete transfer */
+ else
+ maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */
+
+ ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */
+ memcpy(ptr, ptr1, maxlen); /* copy data */
+ rcnt -= maxlen;
+
+ if (rcnt) { /* rest remaining */
+ ptr += maxlen;
+ ptr1 = bdata; /* start of buffer */
+ memcpy(ptr, ptr1, rcnt); /* rest */
+ }
+ bz->za[new_f2].z2 = new_z2;
+ bz->f2 = new_f2; /* next buffer */
+ if (cs->debug & DEB_DLOG_HEX) {
+ ptr = cs->dlog;
+ if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) {
+ *ptr++ = 'E';
+ *ptr++ = 'C';
+ *ptr++ = 'H';
+ *ptr++ = 'O';
+ *ptr++ = ':';
+ ptr += QuickHex(ptr, e_buffer, total - 3);
+ ptr--;
+ *ptr++ = '\n';
+ *ptr = 0;
+ HiSax_putstatus(cs, NULL, cs->dlog);
+ } else
+ HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
+ }
+
+ }
+
+ rcnt = bz->f1 - bz->f2;
+ if (rcnt < 0)
+ rcnt += MAX_B_FRAMES + 1;
+ 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;
+} /* receive_emsg */
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static void
+hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char exval;
+ struct BCState *bcs;
+ int count = 15;
+ long flags;
+ u_char val, stat;
+
+ if (!cs) {
+ printk(KERN_WARNING "HFC-PCI: Spurious interrupt!\n");
+ return;
+ }
+ if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) {
+ val = Read_hfc(cs, HFCPCI_INT_S1);
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFC-PCI: stat(%02x) s1(%02x)", stat, val);
+ } else
+ return;
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFC-PCI irq %x %s", val,
+ test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
+ "locked" : "unlocked");
+ val &= cs->hw.hfcpci.int_m1;
+ if (val & 0x40) { /* TE state machine irq */
+ exval = Read_hfc(cs, HFCPCI_STATES) & 0xf;
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state,
+ exval);
+ cs->dc.hfcpci.ph_state = exval;
+ sched_event_D_pci(cs, D_L1STATECHANGE);
+ val &= ~0x40;
+ }
+ while (val) {
+ save_flags(flags);
+ cli();
+ if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ cs->hw.hfcpci.int_s1 |= val;
+ restore_flags(flags);
+ return;
+ }
+ if (cs->hw.hfcpci.int_s1 & 0x18) {
+ exval = val;
+ val = cs->hw.hfcpci.int_s1;
+ cs->hw.hfcpci.int_s1 = exval;
+ }
+ if (val & 0x08) {
+ if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1:0))) {
+ if (cs->debug)
+ debugl1(cs, "hfcpci spurious 0x08 IRQ");
+ } else
+ main_rec_hfcpci(bcs);
+ }
+ if (val & 0x10) {
+ if (cs->logecho)
+ receive_emsg(cs);
+ else
+ if (!(bcs = Sel_BCS(cs, 1))) {
+ if (cs->debug)
+ debugl1(cs, "hfcpci spurious 0x10 IRQ");
+ } else
+ main_rec_hfcpci(bcs);
+ }
+ if (val & 0x01) {
+ if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1:0))) {
+ if (cs->debug)
+ debugl1(cs, "hfcpci spurious 0x01 IRQ");
+ } else {
+ if (bcs->tx_skb) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcpci_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "fill_data %d blocked", bcs->channel);
+ } else {
+ if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcpci_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "fill_data %d blocked", bcs->channel);
+ } else {
+ hfcpci_sched_event(bcs, B_XMTBUFREADY);
+ }
+ }
+ }
+ }
+ if (val & 0x02) {
+ if (!(bcs = Sel_BCS(cs, 1))) {
+ if (cs->debug)
+ debugl1(cs, "hfcpci spurious 0x02 IRQ");
+ } else {
+ if (bcs->tx_skb) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcpci_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "fill_data %d blocked", bcs->channel);
+ } else {
+ if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcpci_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "fill_data %d blocked", bcs->channel);
+ } else {
+ hfcpci_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_pci(cs, D_CLEARBUSY);
+ if (cs->tx_skb) {
+ if (cs->tx_skb->len) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcpci_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ debugl1(cs, "hfcpci_fill_dfifo irq blocked");
+ }
+ goto afterXPR;
+ } else {
+ idev_kfree_skb(cs->tx_skb, FREE_WRITE);
+ 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)) {
+ hfcpci_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ debugl1(cs, "hfcpci_fill_dfifo irq blocked");
+ }
+ } else
+ sched_event_D_pci(cs, D_XMTBUFREADY);
+ }
+ afterXPR:
+ if (cs->hw.hfcpci.int_s1 && count--) {
+ val = cs->hw.hfcpci.int_s1;
+ cs->hw.hfcpci.int_s1 = 0;
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFC-PCI irq %x loop %d", val, 15 - count);
+ } else
+ val = 0;
+ restore_flags(flags);
+ }
+}
+
+/********************************************************************/
+/* timer callback for D-chan busy resolution. Currently no function */
+/********************************************************************/
+static void
+hfcpci_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 | INDICATION, NULL);
+ stptr = stptr->next;
+ }
+ }
+#endif
+}
+
+/*************************************/
+/* Layer 1 D-channel hardware access */
+/*************************************/
+static void
+HFCPCI_l1hw(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+ struct sk_buff *skb = arg;
+
+ switch (pr) {
+ case (PH_DATA | REQUEST):
+ if (cs->debug & DEB_DLOG_HEX)
+ LogFrame(cs, skb->data, skb->len);
+ if (cs->debug & DEB_DLOG_VERBOSE)
+ dlogframe(cs, skb, 0);
+ if (cs->tx_skb) {
+ skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+ } else {
+ cs->tx_skb = skb;
+ cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcpci_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "hfcpci_fill_dfifo blocked");
+
+ }
+ break;
+ case (PH_PULL | INDICATION):
+ if (cs->tx_skb) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+ skb_queue_tail(&cs->sq, skb);
+ break;
+ }
+ if (cs->debug & DEB_DLOG_HEX)
+ LogFrame(cs, skb->data, skb->len);
+ if (cs->debug & DEB_DLOG_VERBOSE)
+ dlogframe(cs, skb, 0);
+ cs->tx_skb = skb;
+ cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcpci_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "hfcpci_fill_dfifo blocked");
+ break;
+ case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG /* psa */
+ if (cs->debug & L1_DEB_LAPD)
+ debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+ if (!cs->tx_skb) {
+ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ case (HW_RESET | REQUEST):
+ Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */
+ udelay(6);
+ Write_hfc(cs, HFCPCI_STATES, 3); /* HFC ST 2 */
+ cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
+ Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
+ Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
+ l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+ break;
+ case (HW_ENABLE | REQUEST):
+ Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
+ break;
+ case (HW_DEACTIVATE | REQUEST):
+ cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
+ Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
+ break;
+ case (HW_INFO3 | REQUEST):
+ cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
+ Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
+ break;
+#if 0
+ case (HW_TESTLOOP | REQUEST):
+ 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)
+ debugl1(cs, "hfcpci_l1hw unknown pr %4x", pr);
+ break;
+ }
+}
+
+/***********************************************/
+/* called during init setting l1 stack pointer */
+/***********************************************/
+void
+setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs)
+{
+ st->l1.l1hw = HFCPCI_l1hw;
+}
+
+/**************************************/
+/* send B-channel data if not blocked */
+/**************************************/
+static void
+hfcpci_send_data(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcpci_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "send_data %d blocked", bcs->channel);
+}
+
+/***************************************************************/
+/* activate/deactivate hardware for selected channels and mode */
+/***************************************************************/
+void
+mode_hfcpci(struct BCState *bcs, int mode, int bc)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ bzfifo_type *bzr, *bzt;
+ int flags;
+
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HFCPCI bchannel mode %d bchan %d/%d",
+ mode, bc, bcs->channel);
+ bcs->mode = mode;
+ bcs->channel = bc;
+ if (cs->chanlimit > 1) {
+ cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
+ cs->hw.hfcpci.sctrl_e &= ~0x80;
+ }
+ else {
+ if (bc) {
+ cs->hw.hfcpci.bswapped = 1; /* B1 and B2 exchanged */
+ cs->hw.hfcpci.sctrl_e |= 0x80;
+ bc = 0; /* B1 controller used */
+ }
+ else {
+ cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
+ cs->hw.hfcpci.sctrl_e &= ~0x80;
+ }
+ }
+ save_flags(flags);
+ cli();
+ switch (mode) {
+ case (L1_MODE_NULL):
+ if (bc) {
+ cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
+ cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
+ cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
+ cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
+ } else {
+ cs->hw.hfcpci.sctrl &= ~SCTRL_B1_ENA;
+ cs->hw.hfcpci.sctrl_r &= ~SCTRL_B1_ENA;
+ cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
+ cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+ }
+ break;
+ case (L1_MODE_TRANS):
+ if (bc) {
+ cs->hw.hfcpci.ctmt |= 2;
+ cs->hw.hfcpci.conn &= ~0x18;
+ cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
+ cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
+ cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
+ cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
+ bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
+ bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
+ } else {
+ cs->hw.hfcpci.ctmt |= 1;
+ cs->hw.hfcpci.conn &= ~0x03;
+ cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
+ cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
+ cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
+ cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+ bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
+ bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
+ }
+ bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
+ bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;
+ bzr->f1 = MAX_B_FRAMES;
+ bzr->f2 = bzr->f1; /* init F pointers to remain constant */
+ bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
+ bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;
+ bzt->f1 = MAX_B_FRAMES;
+ bzt->f2 = bzt->f1; /* init F pointers to remain constant */
+ break;
+ case (L1_MODE_HDLC):
+ if (bc) {
+ cs->hw.hfcpci.ctmt &= ~2;
+ cs->hw.hfcpci.conn &= ~0x18;
+ cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
+ cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
+ cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
+ cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
+ } else {
+ cs->hw.hfcpci.ctmt &= ~1;
+ cs->hw.hfcpci.conn &= ~0x3;
+ cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
+ cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
+ cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
+ cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+ }
+ break;
+ case (L1_MODE_EXTRN):
+ if (bc) {
+ cs->hw.hfcpci.conn |= 0x10;
+ cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
+ cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
+ cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
+ cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
+ } else {
+ cs->hw.hfcpci.conn |= 0x02;
+ cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
+ cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
+ cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
+ cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+ }
+ break;
+ }
+ Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+ restore_flags(flags);
+ Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
+ Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
+ Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
+ Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
+ Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+}
+
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+static void
+hfcpci_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ long flags;
+
+ switch (pr) {
+ case (PH_DATA | REQUEST):
+ save_flags(flags);
+ cli();
+ if (st->l1.bcs->tx_skb) {
+ skb_queue_tail(&st->l1.bcs->squeue, skb);
+ restore_flags(flags);
+ } else {
+ st->l1.bcs->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 | INDICATION):
+ if (st->l1.bcs->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->tx_skb = skb;
+ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ restore_flags(flags);
+ break;
+ case (PH_PULL | REQUEST):
+ if (!st->l1.bcs->tx_skb) {
+ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ case (PH_ACTIVATE | REQUEST):
+ test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ mode_hfcpci(st->l1.bcs, st->l1.mode, st->l1.bc);
+ l1_msg_b(st, pr, arg);
+ break;
+ case (PH_DEACTIVATE | REQUEST):
+ l1_msg_b(st, pr, arg);
+ break;
+ case (PH_DEACTIVATE | CONFIRM):
+ test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ mode_hfcpci(st->l1.bcs, 0, st->l1.bc);
+ st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ break;
+ }
+}
+
+/******************************************/
+/* deactivate B-channel access and queues */
+/******************************************/
+static void
+close_hfcpci(struct BCState *bcs)
+{
+ mode_hfcpci(bcs, 0, bcs->channel);
+ if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+ discard_queue(&bcs->rqueue);
+ discard_queue(&bcs->squeue);
+ if (bcs->tx_skb) {
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
+ bcs->tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+ }
+}
+
+/*************************************/
+/* init B-channel queues and control */
+/*************************************/
+static int
+open_hfcpcistate(struct IsdnCardState *cs, struct BCState *bcs)
+{
+ if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+ skb_queue_head_init(&bcs->rqueue);
+ skb_queue_head_init(&bcs->squeue);
+ }
+ bcs->tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ bcs->event = 0;
+ bcs->tx_cnt = 0;
+ return (0);
+}
+
+/*********************************/
+/* inits the stack for B-channel */
+/*********************************/
+static int
+setstack_2b(struct PStack *st, struct BCState *bcs)
+{
+ bcs->channel = st->l1.bc;
+ if (open_hfcpcistate(st->l1.hardware, bcs))
+ return (-1);
+ st->l1.bcs = bcs;
+ st->l2.l2l1 = hfcpci_l2l1;
+ setstack_manager(st);
+ bcs->st = st;
+ setstack_l1_B(st);
+ return (0);
+}
+
+/***************************/
+/* handle L1 state changes */
+/***************************/
+static void
+hfcpci_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 | CONFIRM, NULL);
+ stptr = stptr->next;
+ }
+ }
+#endif
+ if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+ switch (cs->dc.hfcpci.ph_state) {
+ case (0):
+ l1_msg(cs, HW_RESET | INDICATION, NULL);
+ break;
+ case (3):
+ l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+ break;
+ case (8):
+ l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+ break;
+ case (6):
+ l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+ break;
+ case (7):
+ l1_msg(cs, HW_INFO4_P8 | INDICATION, 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);
+}
+
+
+/*************************************/
+/* Alloc memory send data for queues */
+/*************************************/
+unsigned int * __init
+ init_send_hfcpci(int cnt)
+{
+ int i, *send;
+
+ if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for hfcpci.send\n");
+ return (NULL);
+ }
+ for (i = 0; i < cnt; i++)
+ send[i] = 0x1fff;
+ return (send);
+}
+
+/********************************/
+/* called for card init message */
+/********************************/
+void __init
+ inithfcpci(struct IsdnCardState *cs)
+{
+ cs->setstack_d = setstack_hfcpci;
+ cs->dbusytimer.function = (void *) hfcpci_dbusy_timer;
+ cs->dbusytimer.data = (long) cs;
+ init_timer(&cs->dbusytimer);
+ cs->tqueue.routine = (void *) (void *) hfcpci_bh;
+#if 0
+ if (!cs->hw.hfcpci.send)
+ cs->hw.hfcpci.send = init_send_hfcpci(16);
+#endif
+ if (!cs->bcs[0].hw.hfc.send)
+ cs->bcs[0].hw.hfc.send = init_send_hfcpci(32);
+ if (!cs->bcs[1].hw.hfc.send)
+ cs->bcs[1].hw.hfc.send = init_send_hfcpci(32);
+ cs->BC_Send_Data = &hfcpci_send_data;
+ cs->bcs[0].BC_SetStack = setstack_2b;
+ cs->bcs[1].BC_SetStack = setstack_2b;
+ cs->bcs[0].BC_Close = close_hfcpci;
+ cs->bcs[1].BC_Close = close_hfcpci;
+ mode_hfcpci(cs->bcs, 0, 0);
+ mode_hfcpci(cs->bcs + 1, 0, 1);
+}
+
+
+
+/*******************************************/
+/* handle card messages from control layer */
+/*******************************************/
+static int
+hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ long flags;
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFCPCI: card_msg %x", mt);
+ switch (mt) {
+ case CARD_RESET:
+ reset_hfcpci(cs);
+ return (0);
+ case CARD_RELEASE:
+ release_io_hfcpci(cs);
+ return (0);
+ case CARD_INIT:
+ inithfcpci(cs);
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */
+ /* now switch timer interrupt off */
+ cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
+ Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+ /* reinit mode reg */
+ Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
+ restore_flags(flags);
+ return (0);
+ case CARD_TEST:
+ return (0);
+ }
+ return (0);
+}
+
+
+/* this variable is used as card index when more than one cards are present */
+#ifdef COMPAT_HAS_NEW_PCI
+static struct pci_dev *dev_hfcpci __initdata = NULL;
+#else
+static int pci_index __initdata = 0;
+#endif
+
+#endif /* CONFIG_PCI */
+
+int __init
+ setup_hfcpci(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ int i;
+#ifdef COMPAT_HAS_NEW_PCI
+ struct pci_dev *tmp_hfcpci = NULL;
+#endif
+
+ strcpy(tmp, hfcpci_revision);
+ printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
+#if CONFIG_PCI
+ cs->hw.hfcpci.int_s1 = 0;
+#if 0
+ cs->hw.hfcpci.send = NULL;
+#endif
+ cs->bcs[0].hw.hfc.send = NULL;
+ cs->bcs[1].hw.hfc.send = NULL;
+ cs->dc.hfcpci.ph_state = 0;
+ cs->hw.hfcpci.fifo = 255;
+ if (cs->typ == ISDN_CTYPE_HFC_PCI) {
+#ifdef COMPAT_HAS_NEW_PCI
+ if (!pci_present()) {
+ printk(KERN_ERR "HFC-PCI: no PCI bus present\n");
+ return (0);
+ }
+ i = 0;
+ while (id_list[i].vendor_id) {
+ tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
+ id_list[i].device_id,
+ dev_hfcpci);
+ if (tmp_hfcpci) break;
+ i++;
+ }
+
+ if (tmp_hfcpci) {
+ dev_hfcpci = tmp_hfcpci; /* old device */
+ cs->hw.hfcpci.pci_bus = dev_hfcpci->bus->number;
+ cs->hw.hfcpci.pci_device_fn = dev_hfcpci->devfn;
+ cs->irq = dev_hfcpci->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
+ return (0);
+ }
+ cs->hw.hfcpci.pci_io = (char *) get_pcibase(dev_hfcpci, 1);
+ printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n",id_list[i].vendor_name,id_list[i].card_name);
+ } else {
+ printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
+ return (0);
+ }
+#else
+ for (; pci_index < 255; pci_index++) {
+ unsigned char irq;
+
+ i = 0;
+ while (id_list[i].vendor_id) {
+ if (pcibios_find_device(id_list[i].vendor_id,
+ id_list[i].device_id, pci_index,
+ &cs->hw.hfcpci.pci_bus, &cs->hw.hfcpci.pci_device_fn) == 0)
+ break;
+ i++;
+ }
+ if (!id_list[i].vendor_id)
+ continue;
+
+ pcibios_read_config_byte(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn,
+ PCI_INTERRUPT_LINE, &irq);
+ cs->irq = irq;
+
+ pcibios_read_config_dword(cs->hw.hfcpci.pci_bus,
+ cs->hw.hfcpci.pci_device_fn, PCI_BASE_ADDRESS_1,
+ (void *) &cs->hw.hfcpci.pci_io);
+ printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n",id_list[i].vendor_name,id_list[i].card_name);
+ break;
+ }
+ if (pci_index == 255) {
+ printk(KERN_WARNING "HFC-PCI: No card found\n");
+ return (0);
+ }
+ pci_index++;
+#endif /* COMPAT_HAS_NEW_PCI */
+ if (!cs->hw.hfcpci.pci_io) {
+ printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
+ return (0);
+ }
+ /* Allocate memory for FIFOS */
+ /* Because the HFC-PCI needs a 32K physical alignment, we */
+ /* need to allocate the double mem and align the address */
+ if (!((void *) cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) {
+ printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
+ return 0;
+ }
+ (ulong) cs->hw.hfcpci.fifos =
+ (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
+ pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
+ cs->hw.hfcpci.pci_device_fn, 0x80,
+ (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
+ cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
+ printk(KERN_INFO
+ "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
+ (u_int) cs->hw.hfcpci.pci_io,
+ (u_int) cs->hw.hfcpci.fifos,
+ (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
+ cs->irq, HZ);
+ pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */
+ cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */
+ cs->hw.hfcpci.int_m1 = 0;
+ Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+ Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+ /* At this point the needed PCI config is done */
+ /* fifos are still not enabled */
+ } else
+ return (0); /* no valid card type */
+
+
+ cs->readisac = NULL;
+ cs->writeisac = NULL;
+ cs->readisacfifo = NULL;
+ cs->writeisacfifo = NULL;
+ cs->BC_Read_Reg = NULL;
+ cs->BC_Write_Reg = NULL;
+ cs->irq_func = &hfcpci_interrupt;
+ cs->irq_flags |= SA_SHIRQ;
+
+ cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer;
+ cs->hw.hfcpci.timer.data = (long) cs;
+ init_timer(&cs->hw.hfcpci.timer);
+
+ reset_hfcpci(cs);
+ cs->cardmsg = &hfcpci_card_msg;
+ cs->auxcmd = &hfcpci_auxcmd;
+ return (1);
+#else
+ printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n");
+ return (0);
+#endif /* CONFIG_PCI */
+}
diff --git a/drivers/isdn/hisax/hfc_pci.h b/drivers/isdn/hisax/hfc_pci.h
new file mode 100644
index 000000000..ae04d3d16
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_pci.h
@@ -0,0 +1,263 @@
+/* $Id: hfc_pci.h,v 1.6 1999/08/28 21:04:29 werner Exp $
+
+ * specific defines for CCD's HFC 2BDS0 PCI chips
+ *
+ * Author Werner Cornelius (werner@isdn4linux.de)
+ *
+ * Copyright 1999 by Werner Cornelius (werner@isdn4linux.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: hfc_pci.h,v $
+ * Revision 1.6 1999/08/28 21:04:29 werner
+ * Implemented full audio support (transparent mode)
+ *
+ * Revision 1.5 1999/08/09 19:13:34 werner
+ * moved constant pci ids to pci id table
+ *
+ * Revision 1.4 1999/08/08 10:17:33 werner
+ * added new PCI vendor and card ids for Manufacturer 0x1043
+ *
+ * Revision 1.3 1999/07/14 12:39:34 werner
+ * Added changes for echo handling.
+ *
+ * Revision 1.2 1999/07/01 08:07:52 keil
+ * Initial version
+ *
+ *
+ *
+ */
+
+/*********************************************/
+/* thresholds for transparent B-channel mode */
+/* change mask and threshold simultaneously */
+/*********************************************/
+#define HFCPCI_BTRANS_THRESHOLD 128
+#define HFCPCI_BTRANS_THRESMASK 0x00
+
+
+
+/* defines for PCI config */
+
+#define PCI_ENA_MEMIO 0x02
+#define PCI_ENA_MASTER 0x04
+
+
+/* GCI/IOM bus monitor registers */
+
+#define HCFPCI_C_I 0x08
+#define HFCPCI_TRxR 0x0C
+#define HFCPCI_MON1_D 0x28
+#define HFCPCI_MON2_D 0x2C
+
+
+/* GCI/IOM bus timeslot registers */
+
+#define HFCPCI_B1_SSL 0x80
+#define HFCPCI_B2_SSL 0x84
+#define HFCPCI_AUX1_SSL 0x88
+#define HFCPCI_AUX2_SSL 0x8C
+#define HFCPCI_B1_RSL 0x90
+#define HFCPCI_B2_RSL 0x94
+#define HFCPCI_AUX1_RSL 0x98
+#define HFCPCI_AUX2_RSL 0x9C
+
+/* GCI/IOM bus data registers */
+
+#define HFCPCI_B1_D 0xA0
+#define HFCPCI_B2_D 0xA4
+#define HFCPCI_AUX1_D 0xA8
+#define HFCPCI_AUX2_D 0xAC
+
+/* GCI/IOM bus configuration registers */
+
+#define HFCPCI_MST_EMOD 0xB4
+#define HFCPCI_MST_MODE 0xB8
+#define HFCPCI_CONNECT 0xBC
+
+
+/* Interrupt and status registers */
+
+#define HFCPCI_FIFO_EN 0x44
+#define HFCPCI_TRM 0x48
+#define HFCPCI_B_MODE 0x4C
+#define HFCPCI_CHIP_ID 0x58
+#define HFCPCI_CIRM 0x60
+#define HFCPCI_CTMT 0x64
+#define HFCPCI_INT_M1 0x68
+#define HFCPCI_INT_M2 0x6C
+#define HFCPCI_INT_S1 0x78
+#define HFCPCI_INT_S2 0x7C
+#define HFCPCI_STATUS 0x70
+
+/* S/T section registers */
+
+#define HFCPCI_STATES 0xC0
+#define HFCPCI_SCTRL 0xC4
+#define HFCPCI_SCTRL_E 0xC8
+#define HFCPCI_SCTRL_R 0xCC
+#define HFCPCI_SQ 0xD0
+#define HFCPCI_CLKDEL 0xDC
+#define HFCPCI_B1_REC 0xF0
+#define HFCPCI_B1_SEND 0xF0
+#define HFCPCI_B2_REC 0xF4
+#define HFCPCI_B2_SEND 0xF4
+#define HFCPCI_D_REC 0xF8
+#define HFCPCI_D_SEND 0xF8
+#define HFCPCI_E_REC 0xFC
+
+
+/* bits in status register (READ) */
+#define HFCPCI_PCI_PROC 0x02
+#define HFCPCI_NBUSY 0x04
+#define HFCPCI_TIMER_ELAP 0x10
+#define HFCPCI_STATINT 0x20
+#define HFCPCI_FRAMEINT 0x40
+#define HFCPCI_ANYINT 0x80
+
+/* bits in CTMT (Write) */
+#define HFCPCI_CLTIMER 0x80
+#define HFCPCI_TIM3_125 0x00
+#define HFCPCI_TIM25 0x10
+#define HFCPCI_TIM50 0x14
+#define HFCPCI_TIM400 0x18
+#define HFCPCI_TIM800 0x1C
+#define HFCPCI_AUTO_TIMER 0x20
+#define HFCPCI_TRANSB2 0x02
+#define HFCPCI_TRANSB1 0x01
+
+/* bits in CIRM (Write) */
+#define HFCPCI_AUX_MSK 0x07
+#define HFCPCI_RESET 0x08
+#define HFCPCI_B1_REV 0x40
+#define HFCPCI_B2_REV 0x80
+
+/* bits in INT_M1 and INT_S1 */
+#define HFCPCI_INTS_B1TRANS 0x01
+#define HFCPCI_INTS_B2TRANS 0x02
+#define HFCPCI_INTS_DTRANS 0x04
+#define HFCPCI_INTS_B1REC 0x08
+#define HFCPCI_INTS_B2REC 0x10
+#define HFCPCI_INTS_DREC 0x20
+#define HFCPCI_INTS_L1STATE 0x40
+#define HFCPCI_INTS_TIMER 0x80
+
+/* bits in INT_M2 */
+#define HFCPCI_PROC_TRANS 0x01
+#define HFCPCI_GCI_I_CHG 0x02
+#define HFCPCI_GCI_MON_REC 0x04
+#define HFCPCI_IRQ_ENABLE 0x08
+#define HFCPCI_PMESEL 0x80
+
+/* bits in STATES */
+#define HFCPCI_STATE_MSK 0x0F
+#define HFCPCI_LOAD_STATE 0x10
+#define HFCPCI_ACTIVATE 0x20
+#define HFCPCI_DO_ACTION 0x40
+#define HFCPCI_NT_G2_G3 0x80
+
+/* bits in HFCD_MST_MODE */
+#define HFCPCI_MASTER 0x01
+#define HFCPCI_SLAVE 0x00
+/* remaining bits are for codecs control */
+
+/* bits in HFCD_SCTRL */
+#define SCTRL_B1_ENA 0x01
+#define SCTRL_B2_ENA 0x02
+#define SCTRL_MODE_TE 0x00
+#define SCTRL_MODE_NT 0x04
+#define SCTRL_LOW_PRIO 0x08
+#define SCTRL_SQ_ENA 0x10
+#define SCTRL_TEST 0x20
+#define SCTRL_NONE_CAP 0x40
+#define SCTRL_PWR_DOWN 0x80
+
+/* bits in SCTRL_E */
+#define HFCPCI_AUTO_AWAKE 0x01
+#define HFCPCI_DBIT_1 0x04
+#define HFCPCI_IGNORE_COL 0x08
+#define HFCPCI_CHG_B1_B2 0x80
+
+/****************************/
+/* bits in FIFO_EN register */
+/****************************/
+#define HFCPCI_FIFOEN_B1 0x03
+#define HFCPCI_FIFOEN_B2 0x0C
+#define HFCPCI_FIFOEN_DTX 0x10
+#define HFCPCI_FIFOEN_B2RX 0x08
+
+
+/***********************************/
+/* definitions of fifo memory area */
+/***********************************/
+#define MAX_D_FRAMES 15
+#define MAX_B_FRAMES 31
+#define B_SUB_VAL 0x200
+#define B_FIFO_SIZE (0x2000 - B_SUB_VAL)
+#define D_FIFO_SIZE 512
+#define D_FREG_MASK 0xF
+
+typedef struct {
+ unsigned short z1; /* Z1 pointer 16 Bit */
+ unsigned short z2; /* Z2 pointer 16 Bit */
+ } z_type;
+
+typedef struct {
+ u_char data[D_FIFO_SIZE]; /* FIFO data space */
+ u_char fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */
+ u_char f1,f2; /* f pointers */
+ u_char fill2[0x20C0-0x20A2]; /* reserved, do not use */
+ z_type za[MAX_D_FRAMES+1]; /* mask index with D_FREG_MASK for access */
+ u_char fill3[0x4000-0x2100]; /* align 16K */
+ } dfifo_type;
+
+typedef struct {
+ z_type za[MAX_B_FRAMES+1]; /* only range 0x0..0x1F allowed */
+ u_char f1,f2; /* f pointers */
+ u_char fill[0x2100-0x2082]; /* alignment */
+ } bzfifo_type;
+
+
+typedef union {
+ struct {
+ dfifo_type d_tx; /* D-send channel */
+ dfifo_type d_rx; /* D-receive channel */
+ } d_chan;
+ struct {
+ u_char fill1[0x200];
+ u_char txdat_b1[B_FIFO_SIZE];
+ bzfifo_type txbz_b1;
+
+ bzfifo_type txbz_b2;
+ u_char txdat_b2[B_FIFO_SIZE];
+
+ u_char fill2[D_FIFO_SIZE];
+
+ u_char rxdat_b1[B_FIFO_SIZE];
+ bzfifo_type rxbz_b1;
+
+ bzfifo_type rxbz_b2;
+ u_char rxdat_b2[B_FIFO_SIZE];
+ } b_chans;
+ u_char fill[32768];
+ } fifo_area;
+
+
+#define Write_hfc(a,b,c) (*(((u_char *)a->hw.hfcpci.pci_io)+b) = c)
+#define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b))
+
+extern void main_irq_hcpci(struct BCState *bcs);
+extern void inithfcpci(struct IsdnCardState *cs);
+extern void releasehfcpci(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
new file mode 100644
index 000000000..05735e150
--- /dev/null
+++ b/drivers/isdn/hisax/hfcscard.c
@@ -0,0 +1,206 @@
+/* $Id: hfcscard.c,v 1.4 1999/08/09 18:59:59 keil Exp $
+
+ * hfcscard.c low level stuff for hfcs based cards (Teles3c, ACER P10)
+ *
+ * Author Karsten Keil (keil@isdn4linux.de)
+ *
+ *
+ * $Log: hfcscard.c,v $
+ * Revision 1.4 1999/08/09 18:59:59 keil
+ * Fix S0 init - Thanks to Stefan Gybas
+ *
+ * Revision 1.3 1999/07/12 21:05:12 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.2 1999/07/01 08:16:03 keil
+ * teles3c ---> hfcscard
+ *
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_2bds0.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+static const char *hfcs_revision = "$Revision: 1.4 $";
+
+static void
+hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val, stat;
+
+ if (!cs) {
+ printk(KERN_WARNING "HFCS: 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)
+ debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val);
+ hfc2bds0_interrupt(cs, val);
+ } else {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat);
+ }
+}
+
+static void
+hfcs_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_hfcs(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_hfcs(struct IsdnCardState *cs)
+{
+ long flags;
+
+ printk(KERN_INFO "HFCS: resetting card\n");
+ cs->hw.hfcD.cirm = HFCD_RESET;
+ if (cs->typ == ISDN_CTYPE_TELES3C)
+ cs->hw.hfcD.cirm |= 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;
+ schedule_timeout((30*HZ)/1000);
+ cs->hw.hfcD.cirm = 0;
+ if (cs->typ == ISDN_CTYPE_TELES3C)
+ 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;
+ schedule_timeout((10*HZ)/1000);
+ if (cs->typ == ISDN_CTYPE_TELES3C)
+ cs->hw.hfcD.cirm |= HFCD_INTB;
+ else if (cs->typ == ISDN_CTYPE_ACERP10)
+ cs->hw.hfcD.cirm |= HFCD_INTA;
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);
+ 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 = HFCD_MASTER;
+ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* 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
+hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ long flags;
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFCS: card_msg %x", mt);
+ switch (mt) {
+ case CARD_RESET:
+ reset_hfcs(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_hfcs(cs);
+ return(0);
+ case CARD_INIT:
+ cs->hw.hfcD.timer.expires = jiffies + 75;
+ add_timer(&cs->hw.hfcD.timer);
+ init2bds0(cs);
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((80*HZ)/1000);
+ 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);
+}
+
+int __init
+setup_hfcs(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, hfcs_revision);
+ printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp));
+ 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.dfifosize = 512;
+ cs->dc.hfcd.ph_state = 0;
+ cs->hw.hfcD.fifo = 255;
+ if (cs->typ == ISDN_CTYPE_TELES3C) {
+ cs->hw.hfcD.bfifosize = 1024 + 512;
+ } else if (cs->typ == ISDN_CTYPE_ACERP10) {
+ cs->hw.hfcD.bfifosize = 7*1024 + 512;
+ } else
+ return (0);
+ 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, "HFCS isdn");
+ }
+ printk(KERN_INFO
+ "HFCS: defined at 0x%x IRQ %d HZ %d\n",
+ cs->hw.hfcD.addr,
+ cs->irq, HZ);
+ if (cs->typ == ISDN_CTYPE_TELES3C) {
+ /* 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);
+ } else if (cs->typ == ISDN_CTYPE_ACERP10) {
+ /* Acer P10 IO ADR is 0x300 */
+ outb(0x00, cs->hw.hfcD.addr);
+ outb(0x57, cs->hw.hfcD.addr | 1);
+ }
+ set_cs_func(cs);
+ cs->hw.hfcD.timer.function = (void *) hfcs_Timer;
+ cs->hw.hfcD.timer.data = (long) cs;
+ init_timer(&cs->hw.hfcD.timer);
+ reset_hfcs(cs);
+ cs->cardmsg = &hfcs_card_msg;
+ cs->irq_func = &hfcs_interrupt;
+ return (1);
+}
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 36cd82ee1..0fdf65a40 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1,8 +1,32 @@
-/* $Id: hisax.h,v 2.26 1998/11/15 23:54:45 keil Exp $
+/* $Id: hisax.h,v 2.34 1999/08/25 17:00:04 keil Exp $
* Basic declarations, defines and prototypes
*
* $Log: hisax.h,v $
+ * Revision 2.34 1999/08/25 17:00:04 keil
+ * Make ISAR V32bis modem running
+ * Make LL->HL interface open for additional commands
+ *
+ * Revision 2.33 1999/08/05 20:43:16 keil
+ * ISAR analog modem support
+ *
+ * Revision 2.31 1999/07/21 14:46:11 keil
+ * changes from EICON certification
+ *
+ * Revision 2.30 1999/07/14 12:38:38 werner
+ * Added changes for echo channel handling
+ *
+ * Revision 2.29 1999/07/12 21:05:14 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 2.28 1999/07/05 23:51:46 werner
+ * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl
+ * hisaxctrl id 10 <nr. of chans 0-2>
+ *
+ * Revision 2.27 1999/07/01 08:11:38 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.26 1998/11/15 23:54:45 keil
* changes from 2.0
*
@@ -111,8 +135,7 @@
#include <linux/wait.h>
#include <linux/isdnif.h>
#include <linux/tty.h>
-#include <linux/init.h>
-#include <linux/serialP.h>
+#include <linux/serial_reg.h>
#define REQUEST 0
#define CONFIRM 1
@@ -131,12 +154,10 @@
#define HW_RSYNC 0x0060
#define HW_TESTLOOP 0x0070
#define CARD_RESET 0x00F0
-#define CARD_SETIRQ 0x00F1
#define CARD_INIT 0x00F2
#define CARD_RELEASE 0x00F3
#define CARD_TEST 0x00F4
#define CARD_AUX_IND 0x00F5
-#define CARD_LOAD_FIRM 0x00F6
#define PH_ACTIVATE 0x0100
#define PH_DEACTIVATE 0x0110
@@ -168,16 +189,21 @@
#define CC_SETUP_COMPL 0x0330
#define CC_PROCEEDING 0x0340
#define CC_ALERTING 0x0344
+#define CC_PROGRESS 0x0348
#define CC_CONNECT 0x0350
#define CC_CHARGE 0x0354
+#define CC_NOTIFY 0x0358
#define CC_DISCONNECT 0x0360
#define CC_RELEASE 0x0368
#define CC_SUSPEND 0x0370
+#define CC_PROCEED_SEND 0x0374
+#define CC_REDIR 0x0378
#define CC_T303 0x0383
#define CC_T304 0x0384
#define CC_T305 0x0385
#define CC_T308_1 0x0388
-#define CC_T308_2 0x0389
+#define CC_T308_2 0x038A
+#define CC_T309 0x0309
#define CC_T310 0x0390
#define CC_T313 0x0393
#define CC_T318 0x0398
@@ -188,12 +214,22 @@
#define CC_RESUME_ERR 0x03E3
#define CC_CONNECT_ERR 0x03E4
#define CC_RELEASE_ERR 0x03E5
-#define CC_DLRL 0x03F0
#define CC_RESTART 0x03F4
+#define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */
+
+/* define maximum number of possible waiting incoming calls */
+#define MAX_WAITING_CALLS 2
#ifdef __KERNEL__
+/* include only l3dss1 specific process structures, but no other defines */
+#ifdef CONFIG_HISAX_EURO
+ #define l3dss1_process
+ #include "l3dss1.h"
+ #undef l3dss1_process
+#endif CONFIG_HISAX_EURO
+
#define MAX_DFRAME_LEN 260
#define MAX_DFRAME_LEN_L1 300
#define HSCX_BUFMAX 4096
@@ -294,16 +330,17 @@ struct Layer1 {
#define FLG_ESTAB_PEND 13
#define FLG_PTP 14
#define FLG_FIXED_TEI 15
+#define FLG_L2BLOCK 16
struct Layer2 {
int tei;
int sap;
int maxlen;
unsigned int flag;
- int vs, va, vr;
+ unsigned int vs, va, vr;
int rc;
- int window;
- int sow;
+ unsigned int window;
+ unsigned int sow;
struct sk_buff *windowar[MAX_WINDOW];
struct sk_buff_head i_queue;
struct sk_buff_head ui_queue;
@@ -319,8 +356,10 @@ struct Layer2 {
struct Layer3 {
void (*l3l4) (struct PStack *, int, void *);
+ void (*l3ml3) (struct PStack *, int, void *);
void (*l3l2) (struct PStack *, int, void *);
struct FsmInst l3m;
+ struct FsmTimer l3m_timer;
struct sk_buff_head squeue;
struct l3_process *proc;
struct l3_process *global;
@@ -331,6 +370,7 @@ struct Layer3 {
struct LLInterface {
void (*l4l3) (struct PStack *, int, void *);
+ int (*l4l3_proto) (struct PStack *, isdn_ctrl *);
void *userdata;
void (*l1writewakeup) (struct PStack *, int);
void (*l2writewakeup) (struct PStack *, int);
@@ -345,16 +385,17 @@ struct Management {
void (*layer) (struct PStack *, int, void *);
};
+#define NO_CAUSE 254
struct Param {
- int cause;
- int loc;
+ u_char cause;
+ u_char loc;
+ u_char diag[6];
int bchannel;
- setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
- int chargeinfo; /* Charge Info - only for 1tr6 in
- * the moment
- */
+ int chargeinfo;
int spv; /* SPV Flag */
+ setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
+ u_char moderate; /* transfer mode and rate (bearer octet 4) */
};
@@ -366,6 +407,14 @@ struct PStack {
struct LLInterface lli;
struct Management ma;
int protocol; /* EDSS1 or 1TR6 */
+
+ /* protocol specific data fields */
+ union
+ { u_char uuuu; /* only as dummy */
+#ifdef CONFIG_HISAX_EURO
+ dss1_stk_priv dss1; /* private dss1 data */
+#endif CONFIG_HISAX_EURO
+ } prot;
};
struct l3_process {
@@ -378,6 +427,15 @@ struct l3_process {
struct Channel *chan;
struct PStack *st;
struct l3_process *next;
+ ulong redir_result;
+
+ /* protocol specific data fields */
+ union
+ { u_char uuuu; /* only when euro not defined, avoiding empty union */
+#ifdef CONFIG_HISAX_EURO
+ dss1_proc_priv dss1; /* private dss1 data */
+#endif CONFIG_HISAX_EURO
+ } prot;
};
struct hscx_hw {
@@ -385,6 +443,8 @@ struct hscx_hw {
int rcvidx;
int count; /* Current skb sent count */
u_char *rcvbuf; /* B-Channel receive Buffer */
+ u_char tsaxr0;
+ u_char tsaxr1;
};
struct isar_reg {
@@ -401,7 +461,14 @@ struct isar_hw {
int rcvidx;
int txcnt;
int mml;
+ u_char state;
+ u_char cmd;
+ u_char mod;
+ u_char newcmd;
+ u_char newmod;
+ struct timer_list ftimer;
u_char *rcvbuf; /* B-Channel receive Buffer */
+ u_char conmsg[16];
struct isar_reg *reg;
};
@@ -469,11 +536,23 @@ struct amd7930_hw {
#define BC_FLG_NOFRAME 4
#define BC_FLG_HALF 5
#define BC_FLG_EMPTY 6
+#define BC_FLG_ORIG 7
+#define BC_FLG_DLEETX 8
+#define BC_FLG_LASTDLE 9
+#define BC_FLG_FIRST 10
+#define BC_FLG_LASTDATA 11
+#define BC_FLG_NMD_DATA 12
+#define BC_FLG_FTI_RUN 13
+#define BC_FLG_LL_OK 14
+#define BC_FLG_LL_CONN 15
#define L1_MODE_NULL 0
#define L1_MODE_TRANS 1
#define L1_MODE_HDLC 2
+#define L1_MODE_EXTRN 3
#define L1_MODE_MODEM 7
+#define L1_MODE_V32 8
+#define L1_MODE_FAX 9
struct BCState {
int channel;
@@ -486,6 +565,7 @@ struct BCState {
struct sk_buff_head squeue; /* B-Channel send Queue */
struct PStack *st;
u_char *blog;
+ u_char *conmsg;
struct timer_list transbusy;
struct tq_struct tqueue;
int event;
@@ -578,7 +658,8 @@ struct ix1_hw {
};
struct diva_hw {
- unsigned int cfg_reg;
+ unsigned long cfg_reg;
+ unsigned long pci_cfg;
unsigned int ctrl;
unsigned int isac_adr;
unsigned int isac;
@@ -647,6 +728,31 @@ struct njet_hw {
unsigned char last_is0;
};
+struct hfcPCI_hw {
+ unsigned char cirm;
+ unsigned char ctmt;
+ unsigned char conn;
+ unsigned char mst_m;
+ unsigned char int_m1;
+ unsigned char int_m2;
+ unsigned char int_s1;
+ unsigned char sctrl;
+ unsigned char sctrl_r;
+ unsigned char sctrl_e;
+ unsigned char trm;
+ unsigned char stat;
+ unsigned char fifo;
+ unsigned char fifo_en;
+ unsigned char bswapped;
+ /* unsigned int *send; */
+ unsigned char pci_bus;
+ unsigned char pci_device_fn;
+ unsigned char *pci_io; /* start of PCI IO memory */
+ void *share_start; /* shared memory for Fifos start */
+ void *fifos; /* FIFO memory */
+ struct timer_list timer;
+};
+
struct hfcD_hw {
unsigned int addr;
unsigned int bfifosize;
@@ -668,25 +774,119 @@ struct hfcD_hw {
struct timer_list timer;
};
-#define HW_IOM1 0
-#define HW_IPAC 1
-#define HW_ISAR 2
-#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 isurf_hw {
+ unsigned int reset;
+ unsigned int isac;
+ unsigned int isar;
+ struct isar_reg isar_r;
+};
+
+struct saphir_hw {
+ unsigned int cfg_reg;
+ unsigned int ale;
+ unsigned int isac;
+ unsigned int hscx;
+ struct timer_list timer;
+};
+
+struct bkm_hw {
+ unsigned int base;
+ /* A4T stuff */
+ unsigned int isac_adr;
+ unsigned int isac_ale;
+ unsigned int jade_adr;
+ unsigned int jade_ale;
+ /* Scitel Quadro stuff */
+ unsigned int plx_adr;
+ unsigned int data_adr;
+};
+
+struct gazel_hw {
+ unsigned int cfg_reg;
+ unsigned int pciaddr[2];
+ signed int ipac;
+ signed int isac;
+ signed int hscx[2];
+ signed int isacfifo;
+ signed int hscxfifo[2];
+ unsigned char timeslot;
+ unsigned char iom2;
+};
+
+#ifdef CONFIG_HISAX_TESTEMU
+struct te_hw {
+ unsigned char *sfifo;
+ unsigned char *sfifo_w;
+ unsigned char *sfifo_r;
+ unsigned char *sfifo_e;
+ int sfifo_cnt;
+ unsigned int stat;
+#ifdef COMPAT_HAS_NEW_WAITQ
+ wait_queue_head_t rwaitq;
+ wait_queue_head_t swaitq;
+#else
+ struct wait_queue *rwaitq;
+ struct wait_queue *swaitq;
+#endif
+};
+#endif
+
+struct arcofi_msg {
+ struct arcofi_msg *next;
+ u_char receive;
+ u_char len;
+ u_char msg[10];
+};
+
+struct isac_chip {
+ int ph_state;
+ u_char *mon_tx;
+ u_char *mon_rx;
+ int mon_txp;
+ int mon_txc;
+ int mon_rxp;
+ struct arcofi_msg *arcofi_list;
+ struct timer_list arcofitimer;
+#ifdef COMPAT_HAS_NEW_WAITQ
+ wait_queue_head_t arcofi_wait;
+#else
+ struct wait_queue *arcofi_wait;
+#endif
+ u_char arcofi_bc;
+ u_char arcofi_state;
+ u_char mocr;
+ u_char adf2;
+};
+
+struct hfcd_chip {
+ int ph_state;
+};
+
+struct hfcpci_chip {
+ int ph_state;
+};
+
+#define HW_IOM1 0
+#define HW_IPAC 1
+#define HW_ISAR 2
+#define HW_ARCOFI 3
+#define FLG_TWO_DCHAN 4
+#define FLG_L1_DBUSY 5
+#define FLG_DBUSY_TIMER 6
+#define FLG_LOCK_ATOMIC 7
+#define FLG_ARCOFI_TIMER 8
+#define FLG_ARCOFI_ERROR 9
struct IsdnCardState {
unsigned char typ;
unsigned char subtyp;
int protocol;
unsigned int irq;
+ unsigned long irq_flags;
int HW_Flags;
int *busy_flag;
+ int chanlimit; /* limited number of B-chans to use */
+ int logecho; /* log echo if supported by card */
union {
struct elsa_hw elsa;
struct teles0_hw teles0;
@@ -701,7 +901,15 @@ struct IsdnCardState {
struct mic_hw mic;
struct njet_hw njet;
struct hfcD_hw hfcD;
+ struct hfcPCI_hw hfcpci;
struct ix1_hw niccy;
+ struct isurf_hw isurf;
+ struct saphir_hw saphir;
+#ifdef CONFIG_HISAX_TESTEMU
+ struct te_hw te;
+#endif
+ struct bkm_hw ax;
+ struct gazel_hw gazel;
} hw;
int myid;
isdn_if iif;
@@ -717,9 +925,22 @@ struct IsdnCardState {
void (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char);
void (*BC_Send_Data) (struct BCState *);
int (*cardmsg) (struct IsdnCardState *, int, void *);
- struct Channel channel[2];
- struct BCState bcs[2];
+ void (*setstack_d) (struct PStack *, struct IsdnCardState *);
+ void (*DC_Close) (struct IsdnCardState *);
+ void (*irq_func) (int, void *, struct pt_regs *);
+ int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *);
+ struct Channel channel[2+MAX_WAITING_CALLS];
+ struct BCState bcs[2+MAX_WAITING_CALLS];
struct PStack *stlist;
+ struct sk_buff_head rq, sq; /* D-channel queues */
+ int cardnr;
+ char *dlog;
+ int debug;
+ union {
+ struct isac_chip isac;
+ struct hfcd_chip hfcd;
+ struct hfcpci_chip hfcpci;
+ } dc;
u_char *rcvbuf;
int rcvidx;
struct sk_buff *tx_skb;
@@ -727,18 +948,6 @@ struct IsdnCardState {
int event;
struct tq_struct tqueue;
struct timer_list dbusytimer;
- struct sk_buff_head rq, sq; /* D-channel queues */
- int ph_state;
- int cardnr;
- char *dlog;
- int debug;
- 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
@@ -776,18 +985,37 @@ struct IsdnCardState {
#define ISDN_CTYPE_A1_PCMCIA 26
#define ISDN_CTYPE_FRITZPCI 27
#define ISDN_CTYPE_SEDLBAUER_FAX 28
+#define ISDN_CTYPE_ISURF 29
+#define ISDN_CTYPE_ACERP10 30
+#define ISDN_CTYPE_HSTSAPHIR 31
+#define ISDN_CTYPE_BKM_A4T 32
+#define ISDN_CTYPE_SCT_QUADRO 33
+#define ISDN_CTYPE_GAZEL 34
+#define ISDN_CTYPE_HFC_PCI 35
+#define ISDN_CTYPE_COUNT 35
-#define ISDN_CTYPE_COUNT 28
#ifdef ISDN_CHIP_ISAC
#undef ISDN_CHIP_ISAC
#endif
+#ifndef __initfunc
+#define __initfunc(__arginit) __arginit
+#endif
+
+#ifndef __initdata
+#define __initdata
+#endif
+
+#ifndef __init
+#define __init
+#endif
+
#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)
+#define CARD_TELES0 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -796,8 +1024,7 @@ struct IsdnCardState {
#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_COMPAQ_ISA)
+#define CARD_TELES3 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -806,7 +1033,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_TELESPCI
-#define CARD_TELESPCI (1<< ISDN_CTYPE_TELESPCI)
+#define CARD_TELESPCI 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -815,7 +1042,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_AVM_A1
-#define CARD_AVM_A1 (1<< ISDN_CTYPE_A1)
+#define CARD_AVM_A1 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -824,7 +1051,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
-#define CARD_AVM_A1_PCMCIA (1<< ISDN_CTYPE_A1_PCMCIA)
+#define CARD_AVM_A1_PCMCIA 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -833,7 +1060,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_FRITZPCI
-#define CARD_FRITZPCI (1<< ISDN_CTYPE_FRITZPCI)
+#define CARD_FRITZPCI 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -842,8 +1069,7 @@ struct IsdnCardState {
#endif
#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)
+#define CARD_ELSA 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -855,9 +1081,8 @@ struct IsdnCardState {
#define CARD_ELSA 0
#endif
-
#ifdef CONFIG_HISAX_IX1MICROR2
-#define CARD_IX1MICROR2 (1 << ISDN_CTYPE_IX1MICROR2)
+#define CARD_IX1MICROR2 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -866,7 +1091,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_DIEHLDIVA
-#define CARD_DIEHLDIVA (1 << ISDN_CTYPE_DIEHLDIVA)
+#define CARD_DIEHLDIVA 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -875,7 +1100,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_ASUSCOM
-#define CARD_ASUSCOM (1 << ISDN_CTYPE_ASUSCOM)
+#define CARD_ASUSCOM 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -884,7 +1109,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_TELEINT
-#define CARD_TELEINT (1 << ISDN_CTYPE_TELEINT)
+#define CARD_TELEINT 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -893,7 +1118,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_SEDLBAUER
-#define CARD_SEDLBAUER (1 << ISDN_CTYPE_SEDLBAUER) | (1 << ISDN_CTYPE_SEDLBAUER_PCMCIA) | ( 1 << ISDN_CTYPE_SEDLBAUER_FAX)
+#define CARD_SEDLBAUER 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -902,7 +1127,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_SPORTSTER
-#define CARD_SPORTSTER (1 << ISDN_CTYPE_SPORTSTER)
+#define CARD_SPORTSTER 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -911,7 +1136,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_MIC
-#define CARD_MIC (1 << ISDN_CTYPE_MIC)
+#define CARD_MIC 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -920,7 +1145,7 @@ struct IsdnCardState {
#endif
#ifdef CONFIG_HISAX_NETJET
-#define CARD_NETJET (1 << ISDN_CTYPE_NETJET)
+#define CARD_NETJET 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -928,20 +1153,26 @@ struct IsdnCardState {
#define CARD_NETJET 0
#endif
-#ifdef CONFIG_HISAX_TELES3C
-#define CARD_TELES3C (1<< ISDN_CTYPE_TELES3C)
+#ifdef CONFIG_HISAX_HFCS
+#define CARD_HFCS 1
+#else
+#define CARD_HFCS 0
+#endif
+
+#ifdef CONFIG_HISAX_HFC_PCI
+#define CARD_HFC_PCI 1
#else
-#define CARD_TELES3C 0
+#define CARD_HFC_PCI 0
#endif
#ifdef CONFIG_HISAX_AMD7930
-#define CARD_AMD7930 (1 << ISDN_CTYPE_AMD7930)
+#define CARD_AMD7930 1
#else
#define CARD_AMD7930 0
#endif
#ifdef CONFIG_HISAX_NICCY
-#define CARD_NICCY (1 << ISDN_CTYPE_NICCY)
+#define CARD_NICCY 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -949,8 +1180,17 @@ struct IsdnCardState {
#define CARD_NICCY 0
#endif
+#ifdef CONFIG_HISAX_ISURF
+#define CARD_ISURF 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_ISURF 0
+#endif
+
#ifdef CONFIG_HISAX_S0BOX
-#define CARD_S0BOX (1 << ISDN_CTYPE_S0BOX)
+#define CARD_S0BOX 1
#ifndef ISDN_CHIP_ISAC
#define ISDN_CHIP_ISAC 1
#endif
@@ -958,12 +1198,50 @@ struct IsdnCardState {
#define CARD_S0BOX 0
#endif
-#define SUPORTED_CARDS (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA \
- | CARD_IX1MICROR2 | CARD_DIEHLDIVA | CARD_ASUSCOM \
- | CARD_TELEINT | CARD_SEDLBAUER | CARD_SPORTSTER \
- | CARD_MIC | CARD_NETJET | CARD_TELES3C | CARD_AMD7930 \
- | CARD_AVM_A1_PCMCIA | CARD_FRITZPCI\
- | CARD_NICCY | CARD_S0BOX | CARD_TELESPCI)
+#ifdef CONFIG_HISAX_HSTSAPHIR
+#define CARD_HSTSAPHIR 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_HSTSAPHIR 0
+#endif
+
+#ifdef CONFIG_HISAX_TESTEMU
+#define CARD_TESTEMU 1
+#define ISDN_CTYPE_TESTEMU 99
+#undef ISDN_CTYPE_COUNT
+#define ISDN_CTYPE_COUNT ISDN_CTYPE_TESTEMU
+#else
+#define CARD_TESTEMU 0
+#endif
+
+#ifdef CONFIG_HISAX_BKM_A4T
+#define CARD_BKM_A4T 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_BKM_A4T 0
+#endif
+
+#ifdef CONFIG_HISAX_SCT_QUADRO
+#define CARD_SCT_QUADRO 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_SCT_QUADRO 0
+#endif
+
+#ifdef CONFIG_HISAX_GAZEL
+#define CARD_GAZEL 1
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_GAZEL 0
+#endif
#define TEI_PER_CARD 0
@@ -1071,7 +1349,7 @@ void setstack_isac(struct PStack *st, struct IsdnCardState *cs);
#define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
-int ll_run(struct IsdnCardState *cs);
+int ll_run(struct IsdnCardState *cs, int addfeatures);
void ll_stop(struct IsdnCardState *cs);
void CallcNew(void);
void CallcFree(void);
diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c
index 980dc76e8..290c89f50 100644
--- a/drivers/isdn/hisax/hscx.c
+++ b/drivers/isdn/hisax/hscx.c
@@ -1,4 +1,4 @@
-/* $Id: hscx.c,v 1.16 1998/11/15 23:54:48 keil Exp $
+/* $Id: hscx.c,v 1.17 1999/07/01 08:11:41 keil Exp $
* hscx.c HSCX specific routines
*
@@ -6,6 +6,9 @@
*
*
* $Log: hscx.c,v $
+ * Revision 1.17 1999/07/01 08:11:41 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.16 1998/11/15 23:54:48 keil
* changes from 2.0
*
@@ -110,12 +113,12 @@ modehscx(struct BCState *bcs, int mode, int bc)
if (bc == 0) {
cs->BC_Write_Reg(cs, hscx, HSCX_TSAX,
- test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : 0x2f);
+ test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
cs->BC_Write_Reg(cs, hscx, HSCX_TSAR,
- test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : 0x2f);
+ test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
} else {
- cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x3);
- cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x3);
+ cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, bcs->hw.hscx.tsaxr1);
+ cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, bcs->hw.hscx.tsaxr1);
}
switch (mode) {
case (L1_MODE_NULL):
@@ -216,7 +219,7 @@ close_hscxstate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
@@ -301,6 +304,10 @@ inithscx(struct IsdnCardState *cs))
cs->bcs[1].BC_Close = close_hscxstate;
cs->bcs[0].hw.hscx.hscx = 0;
cs->bcs[1].hw.hscx.hscx = 1;
+ cs->bcs[0].hw.hscx.tsaxr0 = 0x2f;
+ cs->bcs[0].hw.hscx.tsaxr1 = 3;
+ cs->bcs[1].hw.hscx.tsaxr0 = 0x2f;
+ cs->bcs[1].hw.hscx.tsaxr1 = 3;
modehscx(cs->bcs, 0, 0);
modehscx(cs->bcs + 1, 0, 0);
}
diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c
index 217d241c3..ecc1e825e 100644
--- a/drivers/isdn/hisax/hscx_irq.c
+++ b/drivers/isdn/hisax/hscx_irq.c
@@ -1,4 +1,4 @@
-/* $Id: hscx_irq.c,v 1.11 1998/11/15 23:54:49 keil Exp $
+/* $Id: hscx_irq.c,v 1.12 1999/07/01 08:11:42 keil Exp $
* hscx_irq.c low level b-channel stuff for Siemens HSCX
*
@@ -7,6 +7,9 @@
* This is an include file for fast inline IRQ stuff
*
* $Log: hscx_irq.c,v $
+ * Revision 1.12 1999/07/01 08:11:42 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.11 1998/11/15 23:54:49 keil
* changes from 2.0
*
@@ -42,8 +45,6 @@
*
*/
-#include <linux/string.h>
-
static inline void
waitforCEC(struct IsdnCardState *cs, int hscx)
@@ -203,6 +204,7 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HSCX: receive out of memory\n");
else {
+ SET_SKB_FREE(skb);
memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
skb_queue_tail(&bcs->rqueue, skb);
}
@@ -218,6 +220,7 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
if (!(skb = dev_alloc_skb(fifo_size)))
printk(KERN_WARNING "HiSax: receive out of memory\n");
else {
+ SET_SKB_FREE(skb);
memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
skb_queue_tail(&bcs->rqueue, skb);
}
@@ -234,7 +237,7 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL;
}
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
index a239fdfad..46d5daef0 100644
--- a/drivers/isdn/hisax/isac.c
+++ b/drivers/isdn/hisax/isac.c
@@ -1,4 +1,4 @@
-/* $Id: isac.c,v 1.18 1998/11/15 23:54:51 keil Exp $
+/* $Id: isac.c,v 1.23 1999/08/25 16:50:52 keil Exp $
* isac.c ISAC specific routines
*
@@ -9,6 +9,22 @@
* ../../../Documentation/isdn/HiSax.cert
*
* $Log: isac.c,v $
+ * Revision 1.23 1999/08/25 16:50:52 keil
+ * Fix bugs which cause 2.3.14 hangs (waitqueue init)
+ *
+ * Revision 1.22 1999/08/09 19:04:40 keil
+ * Fix race condition - Thanks to Christer Weinigel
+ *
+ * Revision 1.21 1999/07/12 21:05:17 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.20 1999/07/09 08:23:06 keil
+ * Fix ISAC lost TX IRQ handling
+ *
+ * Revision 1.19 1999/07/01 08:11:43 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.18 1998/11/15 23:54:51 keil
* changes from 2.0
*
@@ -69,6 +85,7 @@
#define __NO_VERSION__
#include "hisax.h"
#include "isac.h"
+#include "arcofi.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
@@ -100,7 +117,7 @@ ph_command(struct IsdnCardState *cs, unsigned int command)
static void
isac_new_ph(struct IsdnCardState *cs)
{
- switch (cs->ph_state) {
+ switch (cs->dc.isac.ph_state) {
case (ISAC_IND_RS):
case (ISAC_IND_EI):
ph_command(cs, ISAC_CMD_DUI);
@@ -154,14 +171,14 @@ isac_bh(struct IsdnCardState *cs)
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_RX_END, &cs->HW_Flags);
+#if ARCOFI_USE
+ if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
+ return;
if (test_and_clear_bit(D_RX_MON1, &cs->event))
- test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags);
- if (test_and_clear_bit(D_TX_MON0, &cs->event))
- test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags);
+ arcofi_fsm(cs, ARCOFI_RX_END, NULL);
if (test_and_clear_bit(D_TX_MON1, &cs->event))
- test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags);
+ arcofi_fsm(cs, ARCOFI_TX_END, NULL);
+#endif
}
void
@@ -226,7 +243,6 @@ isac_fill_fifo(struct IsdnCardState *cs)
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);
@@ -234,6 +250,7 @@ isac_fill_fifo(struct IsdnCardState *cs)
init_timer(&cs->dbusytimer);
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
add_timer(&cs->dbusytimer);
+ restore_flags(flags);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
@@ -283,6 +300,7 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
if (!(skb = alloc_skb(count, GFP_ATOMIC)))
printk(KERN_WARNING "HiSax: D receive out of memory\n");
else {
+ SET_SKB_FREE(skb);
memcpy(skb_put(skb, count), cs->rcvbuf, count);
skb_queue_tail(&cs->rq, skb);
}
@@ -310,7 +328,7 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
isac_fill_fifo(cs);
goto afterXPR;
} else {
- dev_kfree_skb(cs->tx_skb);
+ idev_kfree_skb(cs->tx_skb, FREE_WRITE);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
}
@@ -327,9 +345,9 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC CIR0 %02X", exval );
if (exval & 2) {
- cs->ph_state = (exval >> 2) & 0xf;
+ cs->dc.isac.ph_state = (exval >> 2) & 0xf;
if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "ph_state change %x", cs->ph_state);
+ debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state);
isac_sched_event(cs, D_L1STATECHANGE);
}
if (exval & 1) {
@@ -347,127 +365,147 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
exval = cs->readisac(cs, ISAC_EXIR);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC EXIR %02x", exval);
- if (exval & 0x04) {
+ if (exval & 0x80) { /* XMR */
+ debugl1(cs, "ISAC XMR");
+ printk(KERN_WARNING "HiSax: ISAC XMR\n");
+ }
+ if (exval & 0x40) { /* XDU */
+ debugl1(cs, "ISAC XDU");
+ printk(KERN_WARNING "HiSax: ISAC XDU\n");
+ 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) { /* Restart frame */
+ skb_push(cs->tx_skb, cs->tx_cnt);
+ cs->tx_cnt = 0;
+ isac_fill_fifo(cs);
+ } else {
+ printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
+ debugl1(cs, "ISAC XDU no skb");
+ }
+ }
+ if (exval & 0x04) { /* MOS */
v1 = cs->readisac(cs, ISAC_MOSR);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC MOSR %02x", v1);
#if ARCOFI_USE
if (v1 & 0x08) {
- if (!cs->mon_rx) {
- if (!(cs->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+ if (!cs->dc.isac.mon_rx) {
+ if (!(cs->dc.isac.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);
+ cs->dc.isac.mocr &= 0xf0;
+ cs->dc.isac.mocr |= 0x0a;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
goto afterMONR0;
} else
- cs->mon_rxp = 0;
+ cs->dc.isac.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->dc.isac.mon_rxp >= MAX_MON_FRAME) {
+ cs->dc.isac.mocr &= 0xf0;
+ cs->dc.isac.mocr |= 0x0a;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+ cs->dc.isac.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);
+ cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ISAC MOR0 %02x", cs->mon_rx[cs->mon_rxp -1]);
- if (cs->mon_rxp == 1) {
- cs->mocr |= 0x04;
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]);
+ if (cs->dc.isac.mon_rxp == 1) {
+ cs->dc.isac.mocr |= 0x04;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
}
}
afterMONR0:
if (v1 & 0x80) {
- if (!cs->mon_rx) {
- if (!(cs->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+ if (!cs->dc.isac.mon_rx) {
+ if (!(cs->dc.isac.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);
+ cs->dc.isac.mocr &= 0x0f;
+ cs->dc.isac.mocr |= 0xa0;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
goto afterMONR1;
} else
- cs->mon_rxp = 0;
+ cs->dc.isac.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->dc.isac.mon_rxp >= MAX_MON_FRAME) {
+ cs->dc.isac.mocr &= 0x0f;
+ cs->dc.isac.mocr |= 0xa0;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+ cs->dc.isac.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);
+ cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ISAC MOR1 %02x", cs->mon_rx[cs->mon_rxp -1]);
- cs->mocr |= 0x40;
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+ debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]);
+ cs->dc.isac.mocr |= 0x40;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
}
afterMONR1:
if (v1 & 0x04) {
- cs->mocr &= 0xf0;
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
- cs->mocr |= 0x0a;
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
- test_and_set_bit(HW_MON0_RX_END, &cs->HW_Flags);
+ cs->dc.isac.mocr &= 0xf0;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+ cs->dc.isac.mocr |= 0x0a;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+ isac_sched_event(cs, D_RX_MON0);
}
if (v1 & 0x40) {
- cs->mocr &= 0x0f;
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
- cs->mocr |= 0xa0;
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
- test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags);
+ cs->dc.isac.mocr &= 0x0f;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+ cs->dc.isac.mocr |= 0xa0;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+ isac_sched_event(cs, D_RX_MON1);
}
if (v1 & 0x02) {
- if ((!cs->mon_tx) || (cs->mon_txc &&
- (cs->mon_txp >= cs->mon_txc) &&
+ if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
+ (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
!(v1 & 0x08))) {
- cs->mocr &= 0xf0;
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
- cs->mocr |= 0x0a;
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
- if (cs->mon_txc &&
- (cs->mon_txp >= cs->mon_txc))
- test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags);
+ cs->dc.isac.mocr &= 0xf0;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+ cs->dc.isac.mocr |= 0x0a;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+ if (cs->dc.isac.mon_txc &&
+ (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
+ isac_sched_event(cs, D_TX_MON0);
goto AfterMOX0;
}
- if (cs->mon_txc && (cs->mon_txp >= cs->mon_txc)) {
- test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags);
+ if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
+ isac_sched_event(cs, D_TX_MON0);
goto AfterMOX0;
}
cs->writeisac(cs, ISAC_MOX0,
- cs->mon_tx[cs->mon_txp++]);
+ cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ISAC %02x -> MOX0", cs->mon_tx[cs->mon_txp -1]);
+ debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
}
AfterMOX0:
if (v1 & 0x20) {
- if ((!cs->mon_tx) || (cs->mon_txc &&
- (cs->mon_txp >= cs->mon_txc) &&
+ if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
+ (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
!(v1 & 0x80))) {
- cs->mocr &= 0x0f;
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
- cs->mocr |= 0xa0;
- cs->writeisac(cs, ISAC_MOCR, cs->mocr);
- if (cs->mon_txc &&
- (cs->mon_txp >= cs->mon_txc))
- test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags);
+ cs->dc.isac.mocr &= 0x0f;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+ cs->dc.isac.mocr |= 0xa0;
+ cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
+ if (cs->dc.isac.mon_txc &&
+ (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
+ isac_sched_event(cs, D_TX_MON1);
goto AfterMOX1;
}
- if (cs->mon_txc && (cs->mon_txp >= cs->mon_txc)) {
- test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags);
+ if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
+ isac_sched_event(cs, D_TX_MON1);
goto AfterMOX1;
}
cs->writeisac(cs, ISAC_MOX1,
- cs->mon_tx[cs->mon_txp++]);
+ cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
if (cs->debug & L1_DEB_MONITOR)
- debugl1(cs, "ISAC %02x -> MOX1", cs->mon_tx[cs->mon_txp -1]);
+ debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
}
AfterMOX1:
#endif
@@ -535,9 +573,9 @@ ISAC_l1hw(struct PStack *st, int pr, void *arg)
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (HW_RESET | REQUEST):
- if ((cs->ph_state == ISAC_IND_EI) ||
- (cs->ph_state == ISAC_IND_DR) ||
- (cs->ph_state == ISAC_IND_RS))
+ if ((cs->dc.isac.ph_state == ISAC_IND_EI) ||
+ (cs->dc.isac.ph_state == ISAC_IND_DR) ||
+ (cs->dc.isac.ph_state == ISAC_IND_RS))
ph_command(cs, ISAC_CMD_TIM);
else
ph_command(cs, ISAC_CMD_RS);
@@ -576,7 +614,7 @@ ISAC_l1hw(struct PStack *st, int pr, void *arg)
discard_queue(&cs->rq);
discard_queue(&cs->sq);
if (cs->tx_skb) {
- dev_kfree_skb(cs->tx_skb);
+ idev_kfree_skb(cs->tx_skb, FREE_WRITE);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
@@ -597,27 +635,50 @@ setstack_isac(struct PStack *st, struct IsdnCardState *cs)
st->l1.l1hw = ISAC_l1hw;
}
+void
+DC_Close_isac(struct IsdnCardState *cs) {
+ if (cs->dc.isac.mon_rx) {
+ kfree(cs->dc.isac.mon_rx);
+ cs->dc.isac.mon_rx = NULL;
+ }
+ if (cs->dc.isac.mon_tx) {
+ kfree(cs->dc.isac.mon_tx);
+ cs->dc.isac.mon_tx = NULL;
+ }
+}
+
static void
dbusy_timer_handler(struct IsdnCardState *cs)
{
struct PStack *stptr;
- int val;
+ int rbch, star;
if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
- if (cs->debug) {
- debugl1(cs, "D-Channel Busy");
- val = cs->readisac(cs, ISAC_RBCH);
- if (val & ISAC_RBCH_XAC)
- debugl1(cs, "ISAC XAC");
- else
- debugl1(cs, "ISAC No XAC");
- }
- test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
- stptr = cs->stlist;
-
- while (stptr != NULL) {
- stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
- stptr = stptr->next;
+ rbch = cs->readisac(cs, ISAC_RBCH);
+ star = cs->readisac(cs, ISAC_STAR);
+ if (cs->debug)
+ debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
+ rbch, star);
+ if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */
+ test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+ stptr = cs->stlist;
+ while (stptr != NULL) {
+ stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+ stptr = stptr->next;
+ }
+ } else {
+ /* discard frame; reset transceiver */
+ test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
+ if (cs->tx_skb) {
+ idev_kfree_skb(cs->tx_skb, FREE_WRITE);
+ cs->tx_cnt = 0;
+ cs->tx_skb = NULL;
+ } else {
+ printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
+ debugl1(cs, "D-Channel Busy no skb");
+ }
+ cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
+ cs->irq_func(cs->irq, cs, NULL);
}
}
}
@@ -627,11 +688,14 @@ initisac(struct IsdnCardState *cs))
{
cs->tqueue.routine = (void *) (void *) isac_bh;
cs->setstack_d = setstack_isac;
+ cs->DC_Close = DC_Close_isac;
+ cs->dc.isac.mon_tx = NULL;
+ cs->dc.isac.mon_rx = NULL;
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;
+ cs->dc.isac.mocr = 0xaa;
if (test_bit(HW_IOM1, &cs->HW_Flags)) {
/* IOM 1 Mode */
cs->writeisac(cs, ISAC_ADF2, 0x0);
@@ -641,7 +705,9 @@ initisac(struct IsdnCardState *cs))
cs->writeisac(cs, ISAC_MODE, 0xc9);
} else {
/* IOM 2 Mode */
- cs->writeisac(cs, ISAC_ADF2, 0x80);
+ if (!cs->dc.isac.adf2)
+ cs->dc.isac.adf2 = 0x80;
+ cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2);
cs->writeisac(cs, ISAC_SQXR, 0x2f);
cs->writeisac(cs, ISAC_SPCR, 0x00);
cs->writeisac(cs, ISAC_STCR, 0x70);
@@ -672,7 +738,7 @@ clear_pending_isac_ints(struct IsdnCardState *cs))
}
val = cs->readisac(cs, ISAC_CIR0);
debugl1(cs, "ISAC CIR0 %x", val);
- cs->ph_state = (val >> 2) & 0xf;
+ cs->dc.isac.ph_state = (val >> 2) & 0xf;
isac_sched_event(cs, D_L1STATECHANGE);
/* Disable all IRQ */
cs->writeisac(cs, ISAC_MASK, 0xFF);
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index ba9247a9f..96442ff7d 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.2 1998/11/15 23:54:53 keil Exp $
+/* $Id: isar.c,v 1.5 1999/08/25 16:59:55 keil Exp $
* isar.c ISAR (Siemens PSB 7110) specific routines
*
@@ -6,6 +6,16 @@
*
*
* $Log: isar.c,v $
+ * Revision 1.5 1999/08/25 16:59:55 keil
+ * Make ISAR V32bis modem running
+ * Make LL->HL interface open for additional commands
+ *
+ * Revision 1.4 1999/08/05 20:43:18 keil
+ * ISAR analog modem support
+ *
+ * Revision 1.3 1999/07/01 08:11:45 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.2 1998/11/15 23:54:53 keil
* changes from 2.0
*
@@ -303,6 +313,10 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf)
printk(KERN_DEBUG"isar firmware block %5d words loaded\n",
blk_head.len);
}
+ /* 10ms delay */
+ cnt = 10;
+ while (cnt--)
+ udelay(1000);
msg[0] = 0xff;
msg[1] = 0xfe;
ireg->bstat = 0;
@@ -337,20 +351,26 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf)
printk(KERN_DEBUG"isar general status event %x\n",
ireg->bstat);
}
+ /* 10ms delay */
+ cnt = 10;
+ while (cnt--)
+ udelay(1000);
ireg->iis = 0;
if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) {
printk(KERN_ERR"isar sendmsg self tst failed\n");
ret = 1;goto reterrflg;
}
- cnt = 1000; /* max 10 ms */
+ cnt = 10000; /* max 100 ms */
while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
udelay(10);
cnt--;
}
+ udelay(1000);
if (!cnt) {
printk(KERN_ERR"isar no self tst response\n");
ret = 1;goto reterrflg;
- } else if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1)
+ }
+ if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1)
&& (ireg->par[0] == 0)) {
printk(KERN_DEBUG"isar selftest OK\n");
} else {
@@ -363,11 +383,12 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf)
printk(KERN_ERR"isar RQST SVN failed\n");
ret = 1;goto reterror;
}
- cnt = 10000; /* max 100 ms */
+ cnt = 30000; /* max 300 ms */
while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
udelay(10);
cnt--;
}
+ udelay(1000);
if (!cnt) {
printk(KERN_ERR"isar no SVN response\n");
ret = 1;goto reterrflg;
@@ -396,7 +417,18 @@ reterror:
return(ret);
}
-void
+extern void BChannel_bh(struct BCState *);
+#define B_LL_NOCARRIER 8
+#define B_LL_CONNECT 9
+#define B_LL_OK 10
+
+static void
+isar_bh(struct BCState *bcs)
+{
+ BChannel_bh(bcs);
+}
+
+static void
isar_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
@@ -425,7 +457,9 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
break;
case L1_MODE_TRANS:
+ case L1_MODE_V32:
if ((skb = dev_alloc_skb(ireg->clsb))) {
+ SET_SKB_FREE(skb);
rcv_mbox(cs, ireg, (u_char *)skb_put(skb, ireg->clsb));
skb_queue_tail(&bcs->rqueue, skb);
isar_sched_event(bcs, B_RCVBUFREADY);
@@ -456,9 +490,10 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n",
bcs->hw.isar.rcvidx);
- } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2)))
+ } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) {
printk(KERN_WARNING "ISAR: receive out of memory\n");
- else {
+ } else {
+ SET_SKB_FREE(skb);
memcpy(skb_put(skb, bcs->hw.isar.rcvidx-2),
bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx-2);
skb_queue_tail(&bcs->rqueue, skb);
@@ -512,6 +547,7 @@ isar_fill_fifo(struct BCState *bcs)
printk(KERN_ERR"isar_fill_fifo wrong mode 0\n");
break;
case L1_MODE_TRANS:
+ case L1_MODE_V32:
if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
0, count, ptr)) {
if (cs->debug)
@@ -557,7 +593,7 @@ send_frames(struct BCState *bcs)
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.isar.txcnt);
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->hw.isar.txcnt = 0;
bcs->tx_skb = NULL;
}
@@ -593,8 +629,137 @@ check_send(struct IsdnCardState *cs, u_char rdm)
}
}
+const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4",
+ "300", "600", "1200", "2400", "4800", "7200",
+ "9600nt", "9600t", "12000", "14400", "WRONG"};
+const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
+ "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"};
-static char debbuf[64];
+static void
+isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) {
+ struct IsdnCardState *cs = bcs->cs;
+ u_char ril = ireg->par[0];
+ u_char rim;
+
+ if (!test_and_clear_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags))
+ return;
+ if (ril > 14) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "wrong pstrsp ril=%d",ril);
+ ril = 15;
+ }
+ switch(ireg->par[1]) {
+ case 0:
+ rim = 0;
+ break;
+ case 0x20:
+ rim = 2;
+ break;
+ case 0x40:
+ rim = 3;
+ break;
+ case 0x41:
+ rim = 4;
+ break;
+ case 0x51:
+ rim = 5;
+ break;
+ case 0x61:
+ rim = 6;
+ break;
+ case 0x71:
+ rim = 7;
+ break;
+ case 0x82:
+ rim = 8;
+ break;
+ case 0x92:
+ rim = 9;
+ break;
+ case 0xa2:
+ rim = 10;
+ break;
+ default:
+ rim = 1;
+ break;
+ }
+ sprintf(bcs->hw.isar.conmsg,"%s %s", dmril[ril], dmrim[rim]);
+ bcs->conmsg = bcs->hw.isar.conmsg;
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump strsp %s", bcs->conmsg);
+}
+
+static void
+isar_pump_status_ev(struct BCState *bcs, u_char devt) {
+ struct IsdnCardState *cs = bcs->cs;
+ u_char dps = SET_DPS(bcs->hw.isar.dpath);
+
+ switch(devt) {
+ case PSEV_10MS_TIMER:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev TIMER");
+ break;
+ case PSEV_CON_ON:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev CONNECT");
+ l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL);
+ break;
+ case PSEV_CON_OFF:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev NO CONNECT");
+ sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ l1_msg_b(bcs->st, PH_DEACTIVATE | REQUEST, NULL);
+ break;
+ case PSEV_V24_OFF:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev V24 OFF");
+ break;
+ case PSEV_CTS_ON:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev CTS ON");
+ break;
+ case PSEV_CTS_OFF:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev CTS OFF");
+ break;
+ case PSEV_DCD_ON:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev CARRIER ON");
+ test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags);
+ sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ break;
+ case PSEV_DCD_OFF:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev CARRIER OFF");
+ break;
+ case PSEV_DSR_ON:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev DSR ON");
+ break;
+ case PSEV_DSR_OFF:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev DSR_OFF");
+ break;
+ case PSEV_REM_RET:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev REMOTE RETRAIN");
+ break;
+ case PSEV_REM_REN:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev REMOTE RENEGOTIATE");
+ break;
+ case PSEV_GSTN_CLR:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev GSTN CLEAR", devt);
+ break;
+ default:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "unknown pump stev %x", devt);
+ break;
+ }
+}
+
+static char debbuf[128];
void
isar_int_main(struct IsdnCardState *cs)
@@ -628,10 +793,31 @@ isar_int_main(struct IsdnCardState *cs)
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "Buffer STEV dpath%d msb(%x)",
ireg->iis>>6, ireg->cmsb);
+ case ISAR_IIS_PSTEV:
+ if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
+ rcv_mbox(cs, ireg, (u_char *)ireg->par);
+ isar_pump_status_ev(bcs, ireg->cmsb);
+ } else {
+ debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x",
+ ireg->iis, ireg->cmsb, ireg->clsb);
+ printk(KERN_WARNING"isar spurious IIS_PSTEV %x/%x/%x\n",
+ ireg->iis, ireg->cmsb, ireg->clsb);
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ }
break;
- case ISAR_IIS_DIAG:
case ISAR_IIS_PSTRSP:
- case ISAR_IIS_PSTEV:
+ if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
+ rcv_mbox(cs, ireg, (u_char *)ireg->par);
+ isar_pump_status_rsp(bcs, ireg);
+ } else {
+ debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x",
+ ireg->iis, ireg->cmsb, ireg->clsb);
+ printk(KERN_WARNING"isar spurious IIS_PSTRSP %x/%x/%x\n",
+ ireg->iis, ireg->cmsb, ireg->clsb);
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ }
+ break;
+ case ISAR_IIS_DIAG:
case ISAR_IIS_BSTRSP:
case ISAR_IIS_IOM2RSP:
rcv_mbox(cs, ireg, (u_char *)ireg->par);
@@ -645,6 +831,12 @@ isar_int_main(struct IsdnCardState *cs)
debugl1(cs, debbuf);
}
break;
+ case ISAR_IIS_INVMSG:
+ rcv_mbox(cs, ireg, debbuf);
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "invalid msg his:%x",
+ ireg->cmsb);
+ break;
default:
rcv_mbox(cs, ireg, debbuf);
if (cs->debug & L1_DEB_WARN)
@@ -655,11 +847,12 @@ isar_int_main(struct IsdnCardState *cs)
restore_flags(flags);
}
-void
+static void
setup_pump(struct BCState *bcs) {
struct IsdnCardState *cs = bcs->cs;
u_char dps = SET_DPS(bcs->hw.isar.dpath);
-
+ u_char ctrl, param[6];
+
switch (bcs->mode) {
case L1_MODE_NULL:
case L1_MODE_TRANS:
@@ -670,6 +863,41 @@ setup_pump(struct BCState *bcs) {
bcs->hw.isar.dpath);
}
break;
+ case L1_MODE_V32:
+ ctrl = PMOD_DATAMODEM;
+ if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
+ ctrl |= PCTRL_ORIG;
+ param[5] = PV32P6_CTN;
+ } else {
+ param[5] = PV32P6_ATN;
+ }
+ param[0] = 6; /* 6 db */
+ param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
+ PV32P2_V22C | PV32P2_V21 | PV32P2_BEL;
+ param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
+ param[3] = PV32P4_UT144;
+ param[4] = PV32P5_UT144;
+ if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param)) {
+ if (cs->debug)
+ debugl1(cs, "isar pump datamodem cfg dp%d failed",
+ bcs->hw.isar.dpath);
+ }
+ break;
+ case L1_MODE_FAX:
+ ctrl = PMOD_FAX;
+ if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
+ ctrl |= PCTRL_ORIG;
+ param[1] = PFAXP2_CTN;
+ } else {
+ param[1] = PFAXP2_ATN;
+ }
+ param[0] = 6; /* 6 db */
+ if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param)) {
+ if (cs->debug)
+ debugl1(cs, "isar pump faxmodem cfg dp%d failed",
+ bcs->hw.isar.dpath);
+ }
+ break;
}
if (!sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL)) {
if (cs->debug)
@@ -678,10 +906,11 @@ setup_pump(struct BCState *bcs) {
}
}
-void
+static void
setup_sart(struct BCState *bcs) {
struct IsdnCardState *cs = bcs->cs;
u_char dps = SET_DPS(bcs->hw.isar.dpath);
+ u_char ctrl, param[2];
switch (bcs->mode) {
case L1_MODE_NULL:
@@ -699,9 +928,21 @@ setup_sart(struct BCState *bcs) {
}
break;
case L1_MODE_HDLC:
- if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, "\0")) {
+ case L1_MODE_FAX:
+ param[0] = 0;
+ if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, param)) {
if (cs->debug)
- debugl1(cs, "isar sart binary dp%d failed",
+ debugl1(cs, "isar sart hdlc dp%d failed",
+ bcs->hw.isar.dpath);
+ }
+ break;
+ case L1_MODE_V32:
+ ctrl = SMODE_V14 | SCTRL_HDMC_BOTH;
+ param[0] = S_P1_CHS_8;
+ param[1] = S_P2_BFT_DEF;
+ if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2, param)) {
+ if (cs->debug)
+ debugl1(cs, "isar sart v14 dp%d failed",
bcs->hw.isar.dpath);
}
break;
@@ -713,22 +954,26 @@ setup_sart(struct BCState *bcs) {
}
}
-void
+static void
setup_iom2(struct BCState *bcs) {
struct IsdnCardState *cs = bcs->cs;
u_char dps = SET_DPS(bcs->hw.isar.dpath);
- u_char cmsb = 0, msg[5] = {0x10,0,0,0,0};
+ u_char cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD,0,0,0,0};
+ if (bcs->channel)
+ msg[1] = msg[3] = 1;
switch (bcs->mode) {
case L1_MODE_NULL:
+ cmsb = 0;
/* dummy slot */
msg[1] = msg[3] = bcs->hw.isar.dpath + 2;
break;
case L1_MODE_TRANS:
case L1_MODE_HDLC:
- cmsb = 0x80;
- if (bcs->channel)
- msg[1] = msg[3] = 1;
+ break;
+ case L1_MODE_V32:
+ case L1_MODE_FAX:
+ cmsb |= IOM_CTRL_ALAW | IOM_CTRL_RCV;
break;
}
if (!sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg)) {
@@ -752,6 +997,9 @@ modeisar(struct BCState *bcs, int mode, int bc)
bcs->channel = bc;
switch (mode) {
case L1_MODE_NULL: /* init */
+ if (!bcs->hw.isar.dpath)
+ /* no init for dpath 0 */
+ return(0);
break;
case L1_MODE_TRANS:
case L1_MODE_HDLC:
@@ -763,7 +1011,19 @@ modeisar(struct BCState *bcs, int mode, int bc)
&bcs->hw.isar.reg->Flags))
bcs->hw.isar.dpath = 1;
else {
- printk(KERN_ERR"isar modeisar both pathes in use\n");
+ printk(KERN_WARNING"isar modeisar both pathes in use\n");
+ return(1);
+ }
+ break;
+ case L1_MODE_V32:
+ case L1_MODE_FAX:
+ /* only datapath 1 */
+ if (!test_and_set_bit(ISAR_DP1_USE,
+ &bcs->hw.isar.reg->Flags))
+ bcs->hw.isar.dpath = 1;
+ else {
+ printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
+ debugl1(cs, "isar modeisar analog funktions only with DP1");
return(1);
}
break;
@@ -774,8 +1034,8 @@ modeisar(struct BCState *bcs, int mode, int bc)
bcs->hw.isar.dpath, bcs->mode, mode, bc);
bcs->mode = mode;
setup_pump(bcs);
- setup_sart(bcs);
setup_iom2(bcs);
+ setup_sart(bcs);
if (bcs->mode == L1_MODE_NULL) {
/* Clear resources */
if (bcs->hw.isar.dpath == 1)
@@ -806,6 +1066,7 @@ isar_setup(struct IsdnCardState *cs)
cs->bcs[i].mode = 0;
cs->bcs[i].hw.isar.dpath = i + 1;
modeisar(&cs->bcs[i], 0, 0);
+ cs->bcs[i].tqueue.routine = (void *) (void *) isar_bh;
}
}
@@ -853,8 +1114,24 @@ isar_l2l1(struct PStack *st, int pr, void *arg)
break;
case (PH_ACTIVATE | REQUEST):
test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
- modeisar(st->l1.bcs, st->l1.mode, st->l1.bc);
- l1_msg_b(st, pr, arg);
+ st->l1.bcs->hw.isar.conmsg[0] = 0;
+ if (test_bit(FLG_ORIG, &st->l2.flag))
+ test_and_set_bit(BC_FLG_ORIG, &st->l1.bcs->Flag);
+ else
+ test_and_clear_bit(BC_FLG_ORIG, &st->l1.bcs->Flag);
+ switch(st->l1.mode) {
+ case L1_MODE_TRANS:
+ case L1_MODE_HDLC:
+ if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc))
+ l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
+ else
+ l1_msg_b(st, PH_ACTIVATE | REQUEST, arg);
+ break;
+ case L1_MODE_V32:
+ if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc))
+ l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
+ break;
+ }
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
@@ -882,7 +1159,7 @@ close_isarstate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
if (bcs->cs->debug & L1_DEB_HSCX)
@@ -927,6 +1204,36 @@ setstack_isar(struct PStack *st, struct BCState *bcs)
return (0);
}
+int
+isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
+ u_long adr;
+ int features;
+
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg);
+ switch (ic->command) {
+ case (ISDN_CMD_IOCTL):
+ switch (ic->arg) {
+ case (9): /* load firmware */
+ features = ISDN_FEATURE_L2_MODEM;
+ memcpy(&adr, ic->parm.num, sizeof(ulong));
+ if (isar_load_firmware(cs, (u_char *)adr))
+ return(1);
+ else
+ ll_run(cs, features);
+ break;
+ default:
+ printk(KERN_DEBUG "HiSax: invalid ioclt %d\n",
+ (int) ic->arg);
+ return(-EINVAL);
+ }
+ break;
+ default:
+ return(-EINVAL);
+ }
+ return(0);
+}
+
HISAX_INITFUNC(void
initisar(struct IsdnCardState *cs))
{
diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h
index de892f813..c6ac6532b 100644
--- a/drivers/isdn/hisax/isar.h
+++ b/drivers/isdn/hisax/isar.h
@@ -1,10 +1,20 @@
-/* $Id: isar.h,v 1.2 1998/11/15 23:54:54 keil Exp $
+/* $Id: isar.h,v 1.5 1999/08/25 16:59:59 keil Exp $
* isar.h ISAR (Siemens PSB 7110) specific defines
*
* Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: isar.h,v $
+ * Revision 1.5 1999/08/25 16:59:59 keil
+ * Make ISAR V32bis modem running
+ * Make LL->HL interface open for additional commands
+ *
+ * Revision 1.4 1999/08/05 20:43:20 keil
+ * ISAR analog modem support
+ *
+ * Revision 1.3 1999/07/01 08:11:46 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.2 1998/11/15 23:54:54 keil
* changes from 2.0
*
@@ -27,38 +37,41 @@
#define ISAR_WADR 0x4a
#define ISAR_RADR 0x48
-#define ISAR_HIS_VNR 0x14
-#define ISAR_HIS_DKEY 0x02
-#define ISAR_HIS_FIRM 0x1e
-#define ISAR_HIS_STDSP 0x08
-#define ISAR_HIS_DIAG 0x05
-#define ISAR_HIS_P0CFG 0x3c
-#define ISAR_HIS_P12CFG 0x24
+#define ISAR_HIS_VNR 0x14
+#define ISAR_HIS_DKEY 0x02
+#define ISAR_HIS_FIRM 0x1e
+#define ISAR_HIS_STDSP 0x08
+#define ISAR_HIS_DIAG 0x05
+#define ISAR_HIS_P0CFG 0x3c
+#define ISAR_HIS_P12CFG 0x24
#define ISAR_HIS_SARTCFG 0x25
#define ISAR_HIS_PUMPCFG 0x26
+#define ISAR_HIS_PUMPCTRL 0x2a
#define ISAR_HIS_IOM2CFG 0x27
#define ISAR_HIS_IOM2REQ 0x07
-#define ISAR_HIS_BSTREQ 0x0c
-#define ISAR_HIS_PSTREQ 0x0e
-#define ISAR_HIS_SDATA 0x20
-#define ISAR_HIS_DPS1 0x40
-#define ISAR_HIS_DPS2 0x80
-#define SET_DPS(x) ((x<<6) & 0xc0)
-
-#define ISAR_IIS_MSCMSD 0x3f
-#define ISAR_IIS_VNR 0x15
-#define ISAR_IIS_DKEY 0x03
-#define ISAR_IIS_FIRM 0x1f
-#define ISAR_IIS_STDSP 0x09
-#define ISAR_IIS_DIAG 0x25
-#define ISAR_IIS_GSTEV 0x0
-#define ISAR_IIS_BSTEV 0x28
-#define ISAR_IIS_BSTRSP 0x2c
-#define ISAR_IIS_PSTRSP 0x2e
-#define ISAR_IIS_PSTEV 0x2a
+#define ISAR_HIS_IOM2CTRL 0x2b
+#define ISAR_HIS_BSTREQ 0x0c
+#define ISAR_HIS_PSTREQ 0x0e
+#define ISAR_HIS_SDATA 0x20
+#define ISAR_HIS_DPS1 0x40
+#define ISAR_HIS_DPS2 0x80
+#define SET_DPS(x) ((x<<6) & 0xc0)
+
+#define ISAR_IIS_MSCMSD 0x3f
+#define ISAR_IIS_VNR 0x15
+#define ISAR_IIS_DKEY 0x03
+#define ISAR_IIS_FIRM 0x1f
+#define ISAR_IIS_STDSP 0x09
+#define ISAR_IIS_DIAG 0x25
+#define ISAR_IIS_GSTEV 0x00
+#define ISAR_IIS_BSTEV 0x28
+#define ISAR_IIS_BSTRSP 0x2c
+#define ISAR_IIS_PSTRSP 0x2e
+#define ISAR_IIS_PSTEV 0x2a
#define ISAR_IIS_IOM2RSP 0x27
+#define ISAR_IIS_RDATA 0x20
+#define ISAR_IIS_INVMSG 0x3f
-#define ISAR_IIS_RDATA 0x20
#define ISAR_CTRL_SWVER 0x10
#define ISAR_CTRL_STST 0x40
@@ -66,26 +79,114 @@
#define ISAR_DP1_USE 1
#define ISAR_DP2_USE 2
+#define ISAR_RATE_REQ 3
+#define PMOD_DISABLE 0
+#define PMOD_FAX 1
+#define PMOD_DATAMODEM 2
+#define PMOD_HALFDUPLEX 3
+#define PMOD_V110 4
+#define PMOD_DTMF 5
+#define PMOD_DTMF_TRANS 6
#define PMOD_BYPASS 7
+#define PCTRL_ORIG 0x80
+#define PV32P2_V23R 0x40
+#define PV32P2_V22A 0x20
+#define PV32P2_V22B 0x10
+#define PV32P2_V22C 0x08
+#define PV32P2_V21 0x02
+#define PV32P2_BEL 0x01
+
+// LSB MSB in ISAR doc wrong !!! Arghhh
+#define PV32P3_AMOD 0x80
+#define PV32P3_V32B 0x02
+#define PV32P3_V23B 0x01
+#define PV32P4_48 0x11
+#define PV32P5_48 0x05
+#define PV32P4_UT48 0x11
+#define PV32P5_UT48 0x0d
+#define PV32P4_96 0x11
+#define PV32P5_96 0x03
+#define PV32P4_UT96 0x11
+#define PV32P5_UT96 0x0f
+#define PV32P4_B96 0x91
+#define PV32P5_B96 0x0b
+#define PV32P4_UTB96 0xd1
+#define PV32P5_UTB96 0x0f
+#define PV32P4_120 0xb1
+#define PV32P5_120 0x09
+#define PV32P4_UT120 0xf1
+#define PV32P5_UT120 0x0f
+#define PV32P4_144 0x99
+#define PV32P5_144 0x09
+#define PV32P4_UT144 0xf9
+#define PV32P5_UT144 0x0f
+#define PV32P6_CTN 0x01
+#define PV32P6_ATN 0x02
+
+#define PFAXP2_CTN 0x01
+#define PFAXP2_ATN 0x04
+
+#define PSEV_10MS_TIMER 0x02
+#define PSEV_CON_ON 0x18
+#define PSEV_CON_OFF 0x19
+#define PSEV_V24_OFF 0x20
+#define PSEV_CTS_ON 0x21
+#define PSEV_CTS_OFF 0x22
+#define PSEV_DCD_ON 0x23
+#define PSEV_DCD_OFF 0x24
+#define PSEV_DSR_ON 0x25
+#define PSEV_DSR_OFF 0x26
+#define PSEV_REM_RET 0xcc
+#define PSEV_REM_REN 0xcd
+#define PSEV_GSTN_CLR 0xd4
+
+#define PCTRL_LOC_RET 0xcf
+#define PCTRL_LOC_REN 0xce
+
#define SMODE_DISABLE 0
+#define SMODE_V14 2
#define SMODE_HDLC 3
#define SMODE_BINARY 4
+#define SMODE_FSK_V14 5
+
+#define SCTRL_HDMC_BOTH 0x00
+#define SCTRL_HDMC_DTX 0x80
+#define SCTRL_HDMC_DRX 0x40
+#define S_P1_OVSP 0x40
+#define S_P1_SNP 0x20
+#define S_P1_EOP 0x10
+#define S_P1_EDP 0x08
+#define S_P1_NSB 0x04
+#define S_P1_CHS_8 0x03
+#define S_P1_CHS_7 0x02
+#define S_P1_CHS_6 0x01
+#define S_P1_CHS_5 0x00
+
+#define S_P2_BFT_DEF 0x10
+
+#define IOM_CTRL_ENA 0x80
+#define IOM_CTRL_NOPCM 0x00
+#define IOM_CTRL_ALAW 0x02
+#define IOM_CTRL_ULAW 0x04
+#define IOM_CTRL_RCV 0x01
+
+#define IOM_P1_TXD 0x10
#define HDLC_FED 0x40
#define HDLC_FSD 0x20
#define HDLC_FST 0x20
#define HDLC_ERROR 0x1c
+#define SART_NMD 0x01
#define BSTAT_RDM0 0x1
#define BSTAT_RDM1 0x2
#define BSTAT_RDM2 0x4
#define BSTAT_RDM3 0x8
-
extern int ISARVersion(struct IsdnCardState *cs, char *s);
-extern int isar_load_firmware(struct IsdnCardState *cs, u_char *buf);
extern void isar_int_main(struct IsdnCardState *cs);
extern void initisar(struct IsdnCardState *cs);
extern void isar_fill_fifo(struct BCState *bcs);
+extern int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic);
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index c8f88a162..c819c4811 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 2.31 1998/11/15 23:54:56 keil Exp $
+/* $Id: isdnl1.c,v 2.36 1999/08/25 16:50:57 keil Exp $
* isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards
* based on the teles driver from Jan den Ouden
@@ -15,6 +15,24 @@
*
*
* $Log: isdnl1.c,v $
+ * Revision 2.36 1999/08/25 16:50:57 keil
+ * Fix bugs which cause 2.3.14 hangs (waitqueue init)
+ *
+ * Revision 2.35 1999/08/22 20:27:07 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 2.34 1999/07/09 13:50:15 keil
+ * remove unused variable
+ *
+ * Revision 2.33 1999/07/09 13:34:33 keil
+ * remove debug code
+ *
+ * Revision 2.32 1999/07/01 08:11:47 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.31 1998/11/15 23:54:56 keil
* changes from 2.0
*
@@ -120,7 +138,7 @@
*
*/
-const char *l1_revision = "$Revision: 2.31 $";
+const char *l1_revision = "$Revision: 2.36 $";
#define __NO_VERSION__
#include "hisax.h"
@@ -298,9 +316,18 @@ DChannel_proc_rcv(struct IsdnCardState *cs)
Logl2Frame(cs, skb, "PH_DATA", 1);
#endif
stptr = cs->stlist;
+ if (skb->len<3) {
+ debugl1(cs, "D-channel frame too short(%d)",skb->len);
+ idev_kfree_skb(skb, FREE_READ);
+ return;
+ }
+ if ((skb->data[0] & 1) || !(skb->data[1] &1)) {
+ debugl1(cs, "D-channel frame wrong EA0/EA1");
+ idev_kfree_skb(skb, FREE_READ);
+ return;
+ }
sapi = skb->data[0] >> 2;
tei = skb->data[1] >> 1;
-
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
@@ -323,7 +350,7 @@ DChannel_proc_rcv(struct IsdnCardState *cs)
stptr = stptr->next;
}
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
} else if (sapi == CTRL_SAPI) { /* sapi 0 */
found = 0;
while (stptr != NULL)
@@ -334,7 +361,7 @@ DChannel_proc_rcv(struct IsdnCardState *cs)
} else
stptr = stptr->next;
if (!found)
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
}
}
}
@@ -372,7 +399,7 @@ BChannel_proc_rcv(struct BCState *bcs)
}
}
-static void
+void
BChannel_bh(struct BCState *bcs)
{
if (!bcs)
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
index ccef2682e..ca721ea86 100644
--- a/drivers/isdn/hisax/isdnl2.c
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -1,4 +1,4 @@
-/* $Id: isdnl2.c,v 2.16 1998/11/15 23:55:01 keil Exp $
+/* $Id: isdnl2.c,v 2.20 1999/08/25 16:52:04 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -11,6 +11,18 @@
* Fritz Elfert
*
* $Log: isdnl2.c,v $
+ * Revision 2.20 1999/08/25 16:52:04 keil
+ * Make gcc on AXP happy
+ *
+ * Revision 2.19 1999/08/05 20:40:26 keil
+ * Fix interlayer communication
+ *
+ * Revision 2.18 1999/07/21 14:46:16 keil
+ * changes from EICON certification
+ *
+ * Revision 2.17 1999/07/01 08:11:50 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.16 1998/11/15 23:55:01 keil
* changes from 2.0
*
@@ -71,7 +83,7 @@
#include "hisax.h"
#include "isdnl2.h"
-const char *l2_revision = "$Revision: 2.16 $";
+const char *l2_revision = "$Revision: 2.20 $";
static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
@@ -106,7 +118,7 @@ static char *strL2State[] =
enum {
EV_L2_UI,
- EV_L2_SABMX,
+ EV_L2_SABME,
EV_L2_DISC,
EV_L2_DM,
EV_L2_UA,
@@ -116,22 +128,25 @@ enum {
EV_L2_DL_DATA,
EV_L2_ACK_PULL,
EV_L2_DL_UNIT_DATA,
- EV_L2_DL_ESTABLISH,
- EV_L2_DL_RELEASE,
+ EV_L2_DL_ESTABLISH_REQ,
+ EV_L2_DL_RELEASE_REQ,
EV_L2_MDL_ASSIGN,
EV_L2_MDL_REMOVE,
EV_L2_MDL_ERROR,
EV_L1_DEACTIVATE,
EV_L2_T200,
EV_L2_T203,
+ EV_L2_SET_OWN_BUSY,
+ EV_L2_CLEAR_OWN_BUSY,
+ EV_L2_FRAME_ERROR,
};
-#define L2_EVENT_COUNT (EV_L2_T203+1)
+#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR+1)
static char *strL2Event[] =
{
"EV_L2_UI",
- "EV_L2_SABMX",
+ "EV_L2_SABME",
"EV_L2_DISC",
"EV_L2_DM",
"EV_L2_UA",
@@ -141,19 +156,35 @@ static char *strL2Event[] =
"EV_L2_DL_DATA",
"EV_L2_ACK_PULL",
"EV_L2_DL_UNIT_DATA",
- "EV_L2_DL_ESTABLISH",
- "EV_L2_DL_RELEASE",
+ "EV_L2_DL_ESTABLISH_REQ",
+ "EV_L2_DL_RELEASE_REQ",
"EV_L2_MDL_ASSIGN",
"EV_L2_MDL_REMOVE",
"EV_L2_MDL_ERROR",
"EV_L1_DEACTIVATE",
"EV_L2_T200",
"EV_L2_T203",
+ "EV_L2_SET_OWN_BUSY",
+ "EV_L2_CLEAR_OWN_BUSY",
+ "EV_L2_FRAME_ERROR",
};
static int l2addrsize(struct Layer2 *l2);
static void
+set_peer_busy(struct Layer2 *l2) {
+ test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
+ if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue))
+ test_and_set_bit(FLG_L2BLOCK, &l2->flag);
+}
+
+static void
+clear_peer_busy(struct Layer2 *l2) {
+ if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag))
+ test_and_clear_bit(FLG_L2BLOCK, &l2->flag);
+}
+
+static void
InitWin(struct Layer2 *l2)
{
int i;
@@ -162,30 +193,45 @@ InitWin(struct Layer2 *l2)
l2->windowar[i] = NULL;
}
-static void
-ReleaseWin(struct Layer2 *l2)
+static int
+freewin1(struct Layer2 *l2)
{
int i, cnt = 0;
for (i = 0; i < MAX_WINDOW; i++) {
if (l2->windowar[i]) {
cnt++;
- dev_kfree_skb(l2->windowar[i]);
+ idev_kfree_skb(l2->windowar[i], FREE_WRITE);
l2->windowar[i] = NULL;
}
}
- if (cnt)
+ return cnt;
+}
+
+inline void
+freewin(struct PStack *st)
+{
+ freewin1(&st->l2);
+}
+
+static void
+ReleaseWin(struct Layer2 *l2)
+{
+ int cnt;
+
+ if((cnt = freewin1(l2)))
printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt);
}
-inline int
+inline unsigned int
cansend(struct PStack *st)
{
- int p1;
+ unsigned int p1;
- p1 = st->l2.vs - st->l2.va;
- if (p1 < 0)
- p1 += (test_bit(FLG_MOD128, &st->l2.flag) ? 128 : 8);
+ if(test_bit(FLG_MOD128, &st->l2.flag))
+ p1 = (st->l2.vs - st->l2.va) % 128;
+ else
+ p1 = (st->l2.vs - st->l2.va) % 8;
return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag));
}
@@ -195,7 +241,7 @@ clear_exception(struct Layer2 *l2)
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);
+ clear_peer_busy(l2);
}
inline int
@@ -244,98 +290,197 @@ enqueue_super(struct PStack *st,
#define enqueue_ui(a, b) enqueue_super(a, b)
inline int
-IsUI(u_char * data, int ext)
+IsUI(u_char * data)
{
return ((data[0] & 0xef) == UI);
}
inline int
-IsUA(u_char * data, int ext)
+IsUA(u_char * data)
{
return ((data[0] & 0xef) == UA);
}
inline int
-IsDM(u_char * data, int ext)
+IsDM(u_char * data)
{
return ((data[0] & 0xef) == DM);
}
inline int
-IsDISC(u_char * data, int ext)
+IsDISC(u_char * data)
{
return ((data[0] & 0xef) == DISC);
}
inline int
-IsRR(u_char * data, int ext)
+IsRR(u_char * data, struct PStack *st)
{
- if (ext)
+ if (test_bit(FLG_MOD128, &st->l2.flag))
return (data[0] == RR);
else
return ((data[0] & 0xf) == 1);
}
inline int
-IsSFrame(u_char * data, int ext)
+IsSFrame(u_char * data, struct PStack *st)
{
register u_char d = *data;
- if (!ext)
+ if (!test_bit(FLG_MOD128, &st->l2.flag))
d &= 0xf;
return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c));
}
inline int
-IsSABMX(u_char * data, int ext)
+IsSABME(u_char * data, struct PStack *st)
{
u_char d = data[0] & ~0x10;
- return (ext ? d == SABME : d == SABM);
+ return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM);
}
inline int
-IsREJ(u_char * data, int ext)
+IsREJ(u_char * data, struct PStack *st)
{
- return (ext ? data[0] == REJ : (data[0] & 0xf) == REJ);
+ return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ);
}
inline int
-IsFRMR(u_char * data, int ext)
+IsFRMR(u_char * data)
{
return ((data[0] & 0xef) == FRMR);
}
inline int
-IsRNR(u_char * data, int ext)
+IsRNR(u_char * data, struct PStack *st)
{
- return (ext ? data[0] == RNR : (data[0] & 0xf) == RNR);
+ return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR);
}
-static int
-legalnr(struct PStack *st, int nr)
+int
+iframe_error(struct PStack *st, struct sk_buff *skb)
{
- struct Layer2 *l2 = &st->l2;
- int lnr, lvs;
+ int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 1 : 0);
+ int rsp = *skb->data & 0x2;
+
+ if (test_bit(FLG_ORIG, &st->l2.flag))
+ rsp = !rsp;
+
+ if (rsp)
+ return 'L';
+
+
+ if (skb->len <= i)
+ return 'N';
+
+ if ((skb->len - i) > st->l2.maxlen)
+ return 'O';
- 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);
+
+ return 0;
+}
+
+int
+super_error(struct PStack *st, struct sk_buff *skb)
+{
+ if (skb->len != l2addrsize(&st->l2) +
+ (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1))
+ return 'N';
+
+ return 0;
+}
+
+int
+unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp)
+{
+ int rsp = (*skb->data & 0x2) >> 1;
+ if (test_bit(FLG_ORIG, &st->l2.flag))
+ rsp = !rsp;
+
+ if (rsp != wantrsp)
+ return 'L';
+
+ if (skb->len != l2addrsize(&st->l2) + 1)
+ return 'N';
+
+ return 0;
+}
+
+int
+UI_error(struct PStack *st, struct sk_buff *skb)
+{
+ int rsp = *skb->data & 0x2;
+ if (test_bit(FLG_ORIG, &st->l2.flag))
+ rsp = !rsp;
+
+ if (rsp)
+ return 'L';
+
+ if (skb->len > st->l2.maxlen + l2addrsize(&st->l2) + 1)
+ return 'O';
+
+ return 0;
+}
+
+int
+FRMR_error(struct PStack *st, struct sk_buff *skb)
+{
+ int headers = l2addrsize(&st->l2) + 1;
+ u_char *datap = skb->data + headers;
+ int rsp = *skb->data & 0x2;
+
+ if (test_bit(FLG_ORIG, &st->l2.flag))
+ rsp = !rsp;
+
+ if (!rsp)
+ return 'L';
+
+ if (test_bit(FLG_MOD128, &st->l2.flag)) {
+ if (skb->len < headers + 5)
+ return 'N';
+ else
+ l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x %2x %2x",
+ datap[0], datap[1], datap[2],
+ datap[3], datap[4]);
+ } else {
+ if (skb->len < headers + 3)
+ return 'N';
+ else
+ l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x",
+ datap[0], datap[1], datap[2]);
+ }
+
+ return 0;
+}
+
+static unsigned int
+legalnr(struct PStack *st, unsigned int nr)
+{
+ struct Layer2 *l2 = &st->l2;
+
+ if(test_bit(FLG_MOD128, &l2->flag))
+ return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128);
+ else
+ return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8);
}
static void
-setva(struct PStack *st, int nr)
+setva(struct PStack *st, unsigned 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);
+ (l2->va)++;
+ if(test_bit(FLG_MOD128, &l2->flag))
+ l2->va %= 128;
+ else
+ l2->va %= 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]);
+ idev_kfree_skb(l2->windowar[l2->sow], FREE_WRITE);
l2->windowar[l2->sow] = NULL;
l2->sow = (l2->sow + 1) % l2->window;
if (st->lli.l2writewakeup && (len >=0))
@@ -356,6 +501,7 @@ send_uframe(struct PStack *st, u_char cmd, u_char cr)
printk(KERN_WARNING "isdl2 can't alloc sbbuff for send_uframe\n");
return;
}
+ SET_SKB_FREE(skb);
memcpy(skb_put(skb, i), tmp, i);
enqueue_super(st, skb);
}
@@ -369,7 +515,7 @@ get_PollFlag(struct PStack * st, struct sk_buff * skb)
inline void
FreeSkb(struct sk_buff *skb)
{
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
}
@@ -383,6 +529,48 @@ get_PollFlagFree(struct PStack *st, struct sk_buff *skb)
return (PF);
}
+inline void
+start_t200(struct PStack *st, int i)
+{
+ FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i);
+ test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
+}
+
+inline void
+restart_t200(struct PStack *st, int i)
+{
+ FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i);
+ test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
+}
+
+inline void
+stop_t200(struct PStack *st, int i)
+{
+ if(test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+ FsmDelTimer(&st->l2.t200, i);
+}
+
+inline void
+st5_dl_release_l2l3(struct PStack *st)
+{
+ int pr;
+
+ if(test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
+ pr = DL_RELEASE | CONFIRM;
+ else
+ pr = DL_RELEASE | INDICATION;
+
+ st->l2.l2l3(st, pr, NULL);
+}
+
+inline void
+lapb_dl_release_l2l3(struct PStack *st, int f)
+{
+ if (test_bit(FLG_LAPB, &st->l2.flag))
+ st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+ st->l2.l2l3(st, DL_RELEASE | f, NULL);
+}
+
static void
establishlink(struct FsmInst *fi)
{
@@ -394,56 +582,91 @@ establishlink(struct FsmInst *fi)
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);
+ restart_t200(st, 1);
+ test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
+ freewin(st);
FsmChangeState(fi, ST_L2_5);
}
static void
-l2_mdl_error(struct FsmInst *fi, int event, void *arg)
+l2_mdl_error_ua(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 | INDICATION, (void *) 'C');
- else
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'D');
- break;
- case EV_L2_DM:
- if (get_PollFlagFree(st, skb))
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
- else {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
- }
- break;
- }
+ if (get_PollFlagFree(st, skb))
+ st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'C');
+ else
+ st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'D');
}
static void
-l2_dl_establish(struct FsmInst *fi, int event, void *arg)
+l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
{
+ struct sk_buff *skb = arg;
struct PStack *st = fi->userdata;
- int state = fi->state;
-
- if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
- FsmChangeState(fi, ST_L2_4);
+ if (get_PollFlagFree(st, skb))
+ st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
+ else {
+ st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
establishlink(fi);
- test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
- } else {
- FsmChangeState(fi, ST_L2_3);
- if (state == ST_L2_1)
- st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
+ test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+ }
+}
+
+static void
+l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
+{
+ struct sk_buff *skb = arg;
+ struct PStack *st = fi->userdata;
+
+ if (get_PollFlagFree(st, skb))
+ st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
+ else {
+ st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
}
+ establishlink(fi);
+ test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+}
+
+static void
+l2_go_st3(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L2_3);
}
static void
-l2_send_ui(struct PStack *st)
+l2_mdl_assign(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ FsmChangeState(fi, ST_L2_3);
+ st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
+}
+
+static void
+l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ skb_queue_tail(&st->l2.ui_queue, skb);
+ FsmChangeState(fi, ST_L2_2);
+ st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
+}
+
+static void
+l2_queue_ui(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ skb_queue_tail(&st->l2.ui_queue, skb);
+}
+
+static void
+tx_ui(struct PStack *st)
{
struct sk_buff *skb;
u_char header[MAX_HEADER_LEN];
@@ -458,18 +681,13 @@ l2_send_ui(struct PStack *st)
}
static void
-l2_put_ui(struct FsmInst *fi, int event, void *arg)
+l2_send_ui(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
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 | INDICATION, NULL);
- }
- if (fi->state > ST_L2_3)
- l2_send_ui(st);
+ tx_ui(st);
}
static void
@@ -479,11 +697,12 @@ l2_got_ui(struct FsmInst *fi, int event, void *arg)
struct sk_buff *skb = arg;
skb_pull(skb, l2headersize(&st->l2, 1));
- if (skb->len > st->l2.maxlen) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'O');
- FreeSkb(skb);
- } else
- st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb);
+ st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb);
+/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * in states 1-3 for broadcast
+ */
+
+
}
static void
@@ -491,277 +710,244 @@ l2_establish(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- if (fi->state != ST_L2_4)
- discard_queue(&st->l2.i_queue);
- if (fi->state != ST_L2_5)
- establishlink(fi);
+ establishlink(fi);
test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
}
static void
-l2_dl_release(struct FsmInst *fi, int event, void *arg)
+l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- if (fi->state == ST_L2_4) {
- st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
- return;
- } else if (fi->state == ST_L2_5) {
- test_and_set_bit(FLG_PEND_REL, &st->l2.flag);
- return;
- }
discard_queue(&st->l2.i_queue);
+ test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
+ test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
+}
+
+static void
+l2_l3_reestablish(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ discard_queue(&st->l2.i_queue);
+ establishlink(fi);
+ test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
+}
+
+static void
+l2_release(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+}
+
+static void
+l2_pend_rel(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ test_and_set_bit(FLG_PEND_REL, &st->l2.flag);
+}
+
+static void
+l2_disconnect(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ discard_queue(&st->l2.i_queue);
+ freewin(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);
+ restart_t200(st, 2);
+}
+
+static void
+l2_start_multi(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
+
+ clear_exception(&st->l2);
+ 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, 3);
+
+ st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
}
static void
-l2_got_SABMX(struct FsmInst *fi, int event, void *arg)
+l2_send_UA(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- int est = 1, state, rsp;
- u_char PollFlag;
+
+ send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
+}
+
+static void
+l2_send_DM(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ send_uframe(st, DM | get_PollFlagFree(st, skb), RSP);
+}
+
+static void
+l2_restart_multi(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int est = 0, state;
state = fi->state;
- rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &st->l2.flag))
- rsp = !rsp;
- if (rsp) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (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 | INDICATION, (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 | INDICATION, (void *) 'F');
- if (st->l2.vs != st->l2.va) {
- discard_queue(&st->l2.i_queue);
- est = 1;
- } else
- est = 0;
+
+ send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
+
+ st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'F');
+
+ if (st->l2.vs != st->l2.va) {
+ discard_queue(&st->l2.i_queue);
+ est = 1;
}
+
clear_exception(&st->l2);
st->l2.vs = 0;
st->l2.va = 0;
st->l2.vr = 0;
st->l2.sow = 0;
FsmChangeState(fi, ST_L2_7);
- if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
- FsmDelTimer(&st->l2.t200, 2);
+ stop_t200(st, 3);
FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
if (est)
st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
- if (ST_L2_8 == state)
+ if ((ST_L2_7==state) || (ST_L2_8 == state))
if (skb_queue_len(&st->l2.i_queue) && cansend(st))
st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
}
static void
-l2_got_disconn(struct FsmInst *fi, int event, void *arg)
+l2_stop_multi(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- u_char PollFlag, cmd = UA;
- int state, rel = 1, cst = 1, rsp;
- state = fi->state;
- rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &st->l2.flag))
- rsp = !rsp;
+ FsmChangeState(fi, ST_L2_4);
+ FsmDelTimer(&st->l2.t203, 3);
+ stop_t200(st, 4);
- if (rsp) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (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 | INDICATION, (void *) 'N');
- FreeSkb(skb);
- if ((state == ST_L2_7) || (state == ST_L2_8))
- establishlink(fi);
- return;
- }
- 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) {
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
- }
-}
+ send_uframe(st, UA | get_PollFlagFree(st, skb), RSP);
+ discard_queue(&st->l2.i_queue);
+ freewin(st);
+ lapb_dl_release_l2l3(st, INDICATION);
+}
static void
-l2_got_ua(struct FsmInst *fi, int event, void *arg)
+l2_connected(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
int pr=-1;
- u_char PollFlag;
- int state,rsp;
- state = fi->state;
- rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &st->l2.flag))
- rsp = !rsp;
-
- if (!rsp) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (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 | INDICATION, (void *) 'N');
- FreeSkb(skb);
- if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
- establishlink(fi);
+ if (!get_PollFlag(st, skb)) {
+ l2_mdl_error_ua(fi, event, arg);
return;
}
- PollFlag = get_PollFlag(st, skb);
- if (!PollFlag) {
- l2_mdl_error(fi, event, arg);
+ FreeSkb(skb);
+
+ if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
+ l2_disconnect(fi, event, arg);
+
+ if (test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) {
+ pr = DL_ESTABLISH | CONFIRM;
+ } else if (st->l2.vs != st->l2.va) {
+ discard_queue(&st->l2.i_queue);
+ pr = DL_ESTABLISH | INDICATION;
+ }
+
+ stop_t200(st, 5);
+
+ st->l2.vr = 0;
+ st->l2.vs = 0;
+ st->l2.va = 0;
+ st->l2.sow = 0;
+ FsmChangeState(fi, ST_L2_7);
+ FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4);
+
+ if (pr != -1)
+ st->l2.l2l3(st, pr, NULL);
+
+ if (skb_queue_len(&st->l2.i_queue) && cansend(st))
+ st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+}
+
+static void
+l2_released(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ if (!get_PollFlag(st, skb)) {
+ l2_mdl_error_ua(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)) {
+ stop_t200(st, 6);
+ lapb_dl_release_l2l3(st, CONFIRM);
+ FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_reestablish(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ if (!get_PollFlagFree(st, skb)) {
+ establishlink(fi);
+ test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
+ }
+}
+
+static void
+l2_st5_dm_release(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ if (get_PollFlagFree(st, skb)) {
+ stop_t200(st, 7);
+ if (!test_bit(FLG_L3_INIT, &st->l2.flag))
discard_queue(&st->l2.i_queue);
- 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)) {
- pr = DL_ESTABLISH | CONFIRM;
- } else if (st->l2.vs != st->l2.va) {
- discard_queue(&st->l2.i_queue);
- pr = DL_ESTABLISH | INDICATION;
- }
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
- if (pr > -1)
- st->l2.l2l3(st, pr, NULL);
- }
- } else { /* ST_L2_6 */
if (test_bit(FLG_LAPB, &st->l2.flag))
st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+ st5_dl_release_l2l3(st);
FsmChangeState(fi, ST_L2_4);
}
}
static void
-l2_got_dm(struct FsmInst *fi, int event, void *arg)
+l2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- u_char PollFlag;
- int state,rsp;
- state = fi->state;
- rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &st->l2.flag))
- rsp = !rsp;
-
- if (!rsp) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (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 | INDICATION, (void *) 'N');
- FreeSkb(skb);
- if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
- establishlink(fi);
- return;
- }
- PollFlag = get_PollFlagFree(st, skb);
- if (!PollFlag) {
- if (fi->state == ST_L2_4) {
- establishlink(fi);
- test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
- FsmChangeState(fi, ST_L2_5);
- } else if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8)) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
- establishlink(fi);
- }
- } else {
- switch (fi->state) {
- case ST_L2_8:
- establishlink(fi);
- case ST_L2_7:
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
- break;
- case ST_L2_4:
- break;
- case ST_L2_5:
- if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
- FsmDelTimer(&st->l2.t200, 2);
- discard_queue(&st->l2.i_queue);
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
- FsmChangeState(fi, ST_L2_4);
- break;
- case ST_L2_6:
- if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
- FsmDelTimer(&st->l2.t200, 2);
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
- FsmChangeState(fi, ST_L2_4);
- break;
- }
+ if (get_PollFlagFree(st, skb)) {
+ stop_t200(st, 8);
+ lapb_dl_release_l2l3(st, CONFIRM);
+ FsmChangeState(fi, ST_L2_4);
}
}
@@ -784,6 +970,7 @@ enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
printk(KERN_WARNING "isdl2 can't alloc sbbuff for enquiry_cr\n");
return;
}
+ SET_SKB_FREE(skb);
memcpy(skb_put(skb, i), tmp, i);
enqueue_super(st, skb);
}
@@ -806,8 +993,7 @@ transmit_enquiry(struct PStack *st)
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);
+ start_t200(st, 9);
}
@@ -818,42 +1004,42 @@ nrerrorrecovery(struct FsmInst *fi)
st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'J');
establishlink(fi);
+ test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
}
static void
-invoke_retransmission(struct PStack *st, int nr)
+invoke_retransmission(struct PStack *st, unsigned int nr)
{
struct Layer2 *l2 = &st->l2;
- int p1;
- long flags;
+ unsigned int p1;
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);
+ (l2->vs)--;
+ if(test_bit(FLG_MOD128, &l2->flag)) {
+ l2->vs %= 128;
+ p1 = (l2->vs - l2->va) % 128;
+ } else {
+ l2->vs %= 8;
+ p1 = (l2->vs - l2->va) % 8;
+ }
p1 = (p1 + l2->sow) % l2->window;
if (test_bit(FLG_LAPB, &l2->flag))
st->l1.bcs->tx_cnt += l2->windowar[p1]->len + l2headersize(l2, 0);
skb_queue_head(&l2->i_queue, l2->windowar[p1]);
l2->windowar[p1] = NULL;
}
- restore_flags(flags);
st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
}
}
static void
-l2_got_st7_super(struct FsmInst *fi, int event, void *arg)
+l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- int PollFlag, nr, rsp, typ = RR;
+ int PollFlag, rsp, typ = RR;
+ unsigned int nr;
struct Layer2 *l2 = &st->l2;
rsp = *skb->data & 0x2;
@@ -861,72 +1047,77 @@ l2_got_st7_super(struct FsmInst *fi, int event, void *arg)
rsp = !rsp;
skb_pull(skb, l2addrsize(l2));
- if (IsRNR(skb->data, test_bit(FLG_MOD128, &l2->flag))) {
- test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
+ if (IsRNR(skb->data, st)) {
+ set_peer_busy(l2);
typ = RNR;
} else
- test_and_clear_bit(FLG_PEER_BUSY, &l2->flag);
- if (IsREJ(skb->data, test_bit(FLG_MOD128, &l2->flag)))
+ clear_peer_busy(l2);
+ if (IsREJ(skb->data, st))
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 {
- if (skb->len >2) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
- establishlink(fi);
- }
- FreeSkb(skb);
- return;
- }
+ PollFlag = (skb->data[1] & 0x1) == 0x1;
+ nr = skb->data[1] >> 1;
} else {
- if (skb->len == 1) {
- PollFlag = (skb->data[0] & 0x10);
- nr = (skb->data[0] >> 5) & 0x7;
- } else {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
- FreeSkb(skb);
- establishlink(fi);
- return;
- }
+ PollFlag = (skb->data[0] & 0x10);
+ nr = (skb->data[0] >> 5) & 0x7;
}
FreeSkb(skb);
- if ((!rsp) && PollFlag)
- enquiry_response(st);
- if (rsp && PollFlag)
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A');
+ if (PollFlag) {
+ if (rsp)
+ st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A');
+ else
+ enquiry_response(st);
+ }
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);
+ stop_t200(st, 10);
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);
+ stop_t200(st, 11);
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(typ != RR) FsmDelTimer(&st->l2.t203, 9);
+ restart_t200(st, 12);
}
if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
} else
nrerrorrecovery(fi);
+}
- if ((fi->userint & LC_FLUSH_WAIT) && rsp && !(skb_queue_len(&st->l2.i_queue))) {
- fi->userint &= ~LC_FLUSH_WAIT;
- st->l2.l2l3(st, DL_FLUSH | INDICATION, NULL);
- }
+static void
+l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ if (test_bit(FLG_LAPB, &st->l2.flag))
+ st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
+ if (!test_bit(FLG_L3_INIT, &st->l2.flag))
+ skb_queue_tail(&st->l2.i_queue, skb);
+ else
+ FreeSkb(skb);
+}
+
+static void
+l2_feed_i_pull(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ if (test_bit(FLG_LAPB, &st->l2.flag))
+ st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
+ skb_queue_tail(&st->l2.i_queue, skb);
+ st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
}
static void
@@ -937,10 +1128,7 @@ l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
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 | REQUEST, NULL);
+ skb_queue_tail(&st->l2.i_queue, skb);
}
static void
@@ -949,54 +1137,30 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
struct Layer2 *l2 = &(st->l2);
- int PollFlag, ns, nr, i, rsp;
-
- rsp = *skb->data & 0x2;
- if (test_bit(FLG_ORIG, &l2->flag))
- rsp = !rsp;
+ int PollFlag, ns, i;
+ unsigned int nr;
- if (rsp) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
- FreeSkb(skb);
- establishlink(fi);
- return;
- }
i = l2addrsize(l2);
if (test_bit(FLG_MOD128, &l2->flag)) {
- if (skb->len <= (i + 1)) {
- FreeSkb(skb);
- return;
- } else if ((skb->len - i - 1) > l2->maxlen) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (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 {
- if (skb->len <= i) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
- FreeSkb(skb);
- establishlink(fi);
- return;
- } else if ((skb->len - i) > l2->maxlen) {
- st->ma.layer(st, MDL_ERROR | INDICATION, (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 (test_bit(FLG_OWN_BUSY, &l2->flag)) {
FreeSkb(skb);
- enquiry_response(st);
+ if(PollFlag) enquiry_response(st);
} else if (l2->vr == ns) {
- l2->vr = (l2->vr + 1) % (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+ (l2->vr)++;
+ if(test_bit(FLG_MOD128, &l2->flag))
+ l2->vr %= 128;
+ else
+ l2->vr %= 8;
test_and_clear_bit(FLG_REJEXC, &l2->flag);
+
if (PollFlag)
enquiry_response(st);
else
@@ -1016,19 +1180,15 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
}
if (legalnr(st, nr)) {
- setva(st, nr);
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);
+ stop_t200(st, 13);
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 if (nr != st->l2.va)
+ restart_t200(st, 14);
}
+ setva(st, nr);
} else {
nrerrorrecovery(fi);
return;
@@ -1053,7 +1213,7 @@ l2_got_tei(struct FsmInst *fi, int event, void *arg)
} else
FsmChangeState(fi, ST_L2_4);
if (skb_queue_len(&st->l2.ui_queue))
- l2_send_ui(st);
+ tx_ui(st);
}
static void
@@ -1071,7 +1231,7 @@ l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G');
if (test_bit(FLG_LAPB, &st->l2.flag))
st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+ st5_dl_release_l2l3(st);
} else {
st->l2.rc++;
FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
@@ -1090,10 +1250,9 @@ l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
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);
+ test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'H');
- if (test_bit(FLG_LAPB, &st->l2.flag))
- st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+ lapb_dl_release_l2l3(st, CONFIRM);
} else {
st->l2.rc++;
FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200,
@@ -1103,7 +1262,7 @@ l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
}
static void
-l2_st78_tout_200(struct FsmInst *fi, int event, void *arg)
+l2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
@@ -1113,12 +1272,28 @@ l2_st78_tout_200(struct FsmInst *fi, int event, void *arg)
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);
+ st->l2.rc = 0;
+ FsmChangeState(fi, ST_L2_8);
+
+ transmit_enquiry(st);
+ st->l2.rc++;
+}
+
+static void
+l2_st8_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 (st->l2.rc == st->l2.N200) {
+ st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'I');
establishlink(fi);
+ test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
} else {
transmit_enquiry(st);
st->l2.rc++;
@@ -1147,7 +1322,9 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
struct sk_buff *skb, *oskb;
struct Layer2 *l2 = &st->l2;
u_char header[MAX_HEADER_LEN];
- int p1, i;
+ int i;
+ int unsigned p1;
+ long flags;
if (!cansend(st))
return;
@@ -1156,14 +1333,17 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
if (!skb)
return;
- p1 = l2->vs - l2->va;
- if (p1 < 0)
- p1 += test_bit(FLG_MOD128, &l2->flag) ? 128 : 8;
+ save_flags(flags);
+ cli();
+ if(test_bit(FLG_MOD128, &l2->flag))
+ p1 = (l2->vs - l2->va) % 128;
+ else
+ p1 = (l2->vs - l2->va) % 8;
p1 = (p1 + l2->sow) % l2->window;
if (l2->windowar[p1]) {
printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n",
p1);
- dev_kfree_skb(l2->windowar[p1]);
+ idev_kfree_skb(l2->windowar[p1], FREE_WRITE);
}
l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC);
@@ -1177,6 +1357,8 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
header[i++] = (l2->vr << 5) | (l2->vs << 1);
l2->vs = (l2->vs + 1) % 8;
}
+ restore_flags(flags);
+
p1 = skb->data - skb->head;
if (p1 >= i)
memcpy(skb_push(skb, i), header, i);
@@ -1185,6 +1367,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
"isdl2 pull_iqueue skb header(%d/%d) too short\n", i, p1);
oskb = skb;
skb = alloc_skb(oskb->len + i, GFP_ATOMIC);
+ SET_SKB_FREE(skb);
memcpy(skb_put(skb, i), header, i);
memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
FreeSkb(oskb);
@@ -1200,74 +1383,58 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
}
static void
-l2_got_st8_super(struct FsmInst *fi, int event, void *arg)
+l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
- int PollFlag, nr, rsp, rnr = 0;
+ int PollFlag, rsp, rnr = 0;
+ unsigned int nr;
struct Layer2 *l2 = &st->l2;
rsp = *skb->data & 0x2;
if (test_bit(FLG_ORIG, &l2->flag))
rsp = !rsp;
+
skb_pull(skb, l2addrsize(l2));
- if (IsRNR(skb->data, test_bit(FLG_MOD128, &l2->flag))) {
- test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
+ if (IsRNR(skb->data, st)) {
+ set_peer_busy(l2);
rnr = 1;
} else
- test_and_clear_bit(FLG_PEER_BUSY, &l2->flag);
+ clear_peer_busy(l2);
+
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 | INDICATION, (void *) 'N');
- FreeSkb(skb);
- establishlink(fi);
- return;
- }
+ PollFlag = (skb->data[1] & 0x1) == 0x1;
+ nr = skb->data[1] >> 1;
} else {
- if (skb->len == 1) {
- PollFlag = (skb->data[0] & 0x10);
- nr = (skb->data[0] >> 5) & 0x7;
- } else {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
- FreeSkb(skb);
- establishlink(fi);
- return;
- }
+ PollFlag = (skb->data[0] & 0x10);
+ nr = (skb->data[0] >> 5) & 0x7;
}
FreeSkb(skb);
if (rsp && PollFlag) {
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
+ restart_t200(st, 15);
+ } else {
+ stop_t200(st, 16);
FsmAddTimer(&l2->t203, l2->T203,
EV_L2_T203, NULL, 5);
+ setva(st, nr);
+ }
invoke_retransmission(st, nr);
FsmChangeState(fi, ST_L2_7);
if (skb_queue_len(&l2->i_queue) && cansend(st))
st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
- else if (fi->userint & LC_FLUSH_WAIT) {
- fi->userint &= ~LC_FLUSH_WAIT;
- st->l2.l2l3(st, DL_FLUSH | INDICATION, NULL);
- }
- }
+ } else
+ nrerrorrecovery(fi);
} else {
if (!rsp && PollFlag)
enquiry_response(st);
if (legalnr(st, nr)) {
setva(st, nr);
- }
+ } else
+ nrerrorrecovery(fi);
}
}
@@ -1278,22 +1445,9 @@ l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
struct sk_buff *skb = arg;
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 | INDICATION, (void *) 'N');
- else
- l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x %2x %2x",
- skb->data[0], skb->data[1], skb->data[2],
- skb->data[3], skb->data[4]);
- } else {
- if (skb->len < 3)
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
- else
- l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x",
- skb->data[0], skb->data[1], skb->data[2]);
- }
+
if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */
- (IsUA(skb->data, 0) && (fi->state == ST_L2_7))) {
+ (IsUA(skb->data) && (fi->state == ST_L2_7))) {
st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'K');
establishlink(fi);
test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
@@ -1302,115 +1456,209 @@ l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
}
static void
+l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ discard_queue(&st->l2.ui_queue);
+ st->l2.tei = -1;
+ FsmChangeState(fi, ST_L2_1);
+}
+
+static void
+l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ discard_queue(&st->l2.ui_queue);
+ st->l2.tei = -1;
+ st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+ FsmChangeState(fi, ST_L2_1);
+}
+
+static void
+l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ discard_queue(&st->l2.i_queue);
+ discard_queue(&st->l2.ui_queue);
+ freewin(st);
+ st->l2.tei = -1;
+ stop_t200(st, 17);
+ st5_dl_release_l2l3(st);
+ FsmChangeState(fi, ST_L2_1);
+}
+
+static void
+l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ discard_queue(&st->l2.ui_queue);
+ st->l2.tei = -1;
+ stop_t200(st, 18);
+ st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+ FsmChangeState(fi, ST_L2_1);
+}
+
+static void
l2_tei_remove(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
discard_queue(&st->l2.i_queue);
discard_queue(&st->l2.ui_queue);
+ freewin(st);
st->l2.tei = -1;
- if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
- FsmDelTimer(&st->l2.t200, 18);
+ stop_t200(st, 17);
FsmDelTimer(&st->l2.t203, 19);
- if (fi->state != ST_L2_4)
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+ st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
FsmChangeState(fi, ST_L2_1);
}
static void
-l2_persistant_da(struct FsmInst *fi, int event, void *arg)
+l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- int rel = DL_RELEASE | INDICATION;
-
discard_queue(&st->l2.i_queue);
discard_queue(&st->l2.ui_queue);
- if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
- FsmDelTimer(&st->l2.t200, 18);
+ if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
+ st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+}
+
+static void
+l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ discard_queue(&st->l2.i_queue);
+ discard_queue(&st->l2.ui_queue);
+ freewin(st);
+ stop_t200(st, 19);
+ st5_dl_release_l2l3(st);
+ FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ discard_queue(&st->l2.ui_queue);
+ stop_t200(st, 20);
+ st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+ FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ discard_queue(&st->l2.i_queue);
+ discard_queue(&st->l2.ui_queue);
+ freewin(st);
+ stop_t200(st, 19);
FsmDelTimer(&st->l2.t203, 19);
- clear_exception(&st->l2);
- switch (fi->state) {
- case ST_L2_1:
- if (!test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
- break;
- case ST_L2_3:
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
- case ST_L2_2:
- FsmChangeState(fi, ST_L2_1);
- break;
- case ST_L2_6:
- rel = DL_RELEASE | CONFIRM;
- case ST_L2_5:
- if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
- rel = DL_RELEASE | CONFIRM;
- case ST_L2_7:
- case ST_L2_8:
- st->l2.l2l3(st, rel, NULL);
- FsmChangeState(fi, ST_L2_4);
- break;
- case ST_L2_4:
- if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
- st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
- break;
+ st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+ FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_set_own_busy(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ if(!test_and_set_bit(FLG_OWN_BUSY, &st->l2.flag)) {
+ enquiry_cr(st, RNR, RSP, 0);
+ test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
}
- test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
- test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag);
+}
+
+static void
+l2_clear_own_busy(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ if(!test_and_clear_bit(FLG_OWN_BUSY, &st->l2.flag)) {
+ enquiry_cr(st, RR, RSP, 0);
+ test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
+ }
+}
+
+static void
+l2_frame_error(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ st->ma.layer(st, MDL_ERROR | INDICATION, arg);
+}
+
+static void
+l2_frame_error_reest(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ st->ma.layer(st, MDL_ERROR | INDICATION, arg);
+ establishlink(fi);
+ test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
}
static struct FsmNode L2FnList[] HISAX_INITDATA =
{
- {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_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_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
+ {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
+ {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish},
+ {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3},
+ {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
+ {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
+ {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release},
+ {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel},
+ {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect},
+ {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect},
+ {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest},
+ {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull},
{ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
- {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_DL_UNIT_DATA, l2_queue_ui_assign},
+ {ST_L2_2, EV_L2_DL_UNIT_DATA, l2_queue_ui},
+ {ST_L2_3, EV_L2_DL_UNIT_DATA, l2_queue_ui},
+ {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_send_ui},
+ {ST_L2_5, EV_L2_DL_UNIT_DATA, l2_send_ui},
+ {ST_L2_6, EV_L2_DL_UNIT_DATA, l2_send_ui},
+ {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui},
+ {ST_L2_8, EV_L2_DL_UNIT_DATA, l2_send_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_2, EV_L2_MDL_ERROR, l2_st24_tei_remove},
+ {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove},
+ {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove},
+ {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove},
+ {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_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_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_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_got_dm},
- {ST_L2_8, EV_L2_DM, l2_got_dm},
+ {ST_L2_4, EV_L2_SABME, l2_start_multi},
+ {ST_L2_5, EV_L2_SABME, l2_send_UA},
+ {ST_L2_6, EV_L2_SABME, l2_send_DM},
+ {ST_L2_7, EV_L2_SABME, l2_restart_multi},
+ {ST_L2_8, EV_L2_SABME, l2_restart_multi},
+ {ST_L2_4, EV_L2_DISC, l2_send_DM},
+ {ST_L2_5, EV_L2_DISC, l2_send_DM},
+ {ST_L2_6, EV_L2_DISC, l2_send_UA},
+ {ST_L2_7, EV_L2_DISC, l2_stop_multi},
+ {ST_L2_8, EV_L2_DISC, l2_stop_multi},
+ {ST_L2_4, EV_L2_UA, l2_mdl_error_ua},
+ {ST_L2_5, EV_L2_UA, l2_connected},
+ {ST_L2_6, EV_L2_UA, l2_released},
+ {ST_L2_7, EV_L2_UA, l2_mdl_error_ua},
+ {ST_L2_8, EV_L2_UA, l2_mdl_error_ua},
+ {ST_L2_4, EV_L2_DM, l2_reestablish},
+ {ST_L2_5, EV_L2_DM, l2_st5_dm_release},
+ {ST_L2_6, EV_L2_DM, l2_st6_dm_release},
+ {ST_L2_7, EV_L2_DM, l2_mdl_error_dm},
+ {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm},
{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},
@@ -1421,22 +1669,31 @@ static struct FsmNode L2FnList[] HISAX_INITDATA =
{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_7, EV_L2_SUPER, l2_got_st7_super},
- {ST_L2_8, EV_L2_SUPER, l2_got_st8_super},
+ {ST_L2_7, EV_L2_SUPER, l2_st7_got_super},
+ {ST_L2_8, EV_L2_SUPER, l2_st8_got_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_st78_tout_200},
- {ST_L2_8, EV_L2_T200, l2_st78_tout_200},
+ {ST_L2_7, EV_L2_T200, l2_st7_tout_200},
+ {ST_L2_8, EV_L2_T200, l2_st8_tout_200},
{ST_L2_7, EV_L2_T203, l2_st7_tout_203},
{ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
- {ST_L2_1, EV_L1_DEACTIVATE, l2_persistant_da},
- {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_L2_SET_OWN_BUSY, l2_set_own_busy},
+ {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
+ {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
+ {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
+ {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error},
+ {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error},
+ {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
+ {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
+ {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
+ {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da},
+ {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
+ {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
+ {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da},
+ {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da},
+ {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da},
{ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da},
{ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da},
};
@@ -1449,6 +1706,7 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
struct sk_buff *skb = arg;
u_char *datap;
int ret = 1, len;
+ int c = 0;
switch (pr) {
case (PH_DATA | INDICATION):
@@ -1457,36 +1715,46 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
if (skb->len > len)
datap += len;
else {
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
+ FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'N');
FreeSkb(skb);
return;
}
- if (!(*datap & 1)) /* I-Frame */
- ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb);
- else if (IsSFrame(datap, test_bit(FLG_MOD128, &st->l2.flag)))
- 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, test_bit(FLG_MOD128, &st->l2.flag)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, skb);
- else if (IsUA(datap, test_bit(FLG_MOD128, &st->l2.flag)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb);
- else if (IsDISC(datap, test_bit(FLG_MOD128, &st->l2.flag)))
- ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb);
- 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 {
- ret = 1;
- if ((st->l2.l2m.state == ST_L2_7) ||
- (st->l2.l2m.state == ST_L2_8))
- establishlink(&st->l2.l2m);
- st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
+ if (!(*datap & 1)) { /* I-Frame */
+ if(!(c = iframe_error(st, skb)))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb);
+ } else if (IsSFrame(datap, st)) { /* S-Frame */
+ if(!(c = super_error(st, skb)))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb);
+ } else if (IsUI(datap)) {
+ if(!(c = UI_error(st, skb)))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb);
+ } else if (IsSABME(datap, st)) {
+ if(!(c = unnum_error(st, skb, CMD)))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_SABME, skb);
+ } else if (IsUA(datap)) {
+ if(!(c = unnum_error(st, skb, RSP)))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb);
+ } else if (IsDISC(datap)) {
+ if(!(c = unnum_error(st, skb, CMD)))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb);
+ } else if (IsDM(datap)) {
+ if(!(c = unnum_error(st, skb, RSP)))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_DM, skb);
+ } else if (IsFRMR(datap)) {
+ if(!(c = FRMR_error(st,skb)))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb);
+ } else {
+ FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'L');
+ FreeSkb(skb);
+ ret = 0;
}
- if (ret) {
+ if(c) {
FreeSkb(skb);
+ FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
+ ret = 0;
}
+ if (ret)
+ FreeSkb(skb);
break;
case (PH_PULL | CONFIRM):
FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
@@ -1501,7 +1769,7 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
case (PH_ACTIVATE | INDICATION):
test_and_set_bit(FLG_L1_ACTIV, &st->l2.flag);
if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
- FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+ FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg);
break;
case (PH_DEACTIVATE | INDICATION):
case (PH_DEACTIVATE | CONFIRM):
@@ -1520,19 +1788,19 @@ isdnl2_l3l2(struct PStack *st, int pr, void *arg)
switch (pr) {
case (DL_DATA | REQUEST):
if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) {
- dev_kfree_skb((struct sk_buff *) arg);
+ idev_kfree_skb((struct sk_buff *) arg, FREE_READ);
}
break;
case (DL_UNIT_DATA | REQUEST):
if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) {
- dev_kfree_skb((struct sk_buff *) arg);
+ idev_kfree_skb((struct sk_buff *) arg, FREE_READ);
}
break;
case (DL_ESTABLISH | REQUEST):
if (test_bit(FLG_L1_ACTIV, &st->l2.flag)) {
if (test_bit(FLG_LAPD, &st->l2.flag) ||
test_bit(FLG_ORIG, &st->l2.flag)) {
- FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+ FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg);
}
} else {
if (test_bit(FLG_LAPD, &st->l2.flag) ||
@@ -1546,10 +1814,7 @@ isdnl2_l3l2(struct PStack *st, int pr, void *arg)
if (test_bit(FLG_LAPB, &st->l2.flag)) {
st->l2.l2l1(st, PH_DEACTIVATE, NULL);
}
- FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
- break;
- case (DL_FLUSH | REQUEST):
- (&st->l2.l2m)->userint |= LC_FLUSH_WAIT;
+ FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE_REQ, arg);
break;
case (MDL_ASSIGN | REQUEST):
FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
@@ -1566,7 +1831,7 @@ isdnl2_l3l2(struct PStack *st, int pr, void *arg)
void
releasestack_isdnl2(struct PStack *st)
{
- FsmDelTimer(&st->l2.t200, 15);
+ FsmDelTimer(&st->l2.t200, 21);
FsmDelTimer(&st->l2.t203, 16);
discard_queue(&st->l2.i_queue);
discard_queue(&st->l2.ui_queue);
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index 4511251e7..458afe920 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -1,4 +1,4 @@
-/* $Id: isdnl3.c,v 2.8 1998/11/15 23:55:04 keil Exp $
+/* $Id: isdnl3.c,v 2.10 1999/07/21 14:46:19 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -11,6 +11,12 @@
* Fritz Elfert
*
* $Log: isdnl3.c,v $
+ * Revision 2.10 1999/07/21 14:46:19 keil
+ * changes from EICON certification
+ *
+ * Revision 2.9 1999/07/01 08:11:53 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.8 1998/11/15 23:55:04 keil
* changes from 2.0
*
@@ -62,7 +68,7 @@
#include "isdnl3.h"
#include <linux/config.h>
-const char *l3_revision = "$Revision: 2.8 $";
+const char *l3_revision = "$Revision: 2.10 $";
static
struct Fsm l3fsm =
@@ -71,6 +77,7 @@ struct Fsm l3fsm =
enum {
ST_L3_LC_REL,
ST_L3_LC_ESTAB_WAIT,
+ ST_L3_LC_REL_DELAY,
ST_L3_LC_REL_WAIT,
ST_L3_LC_ESTAB,
};
@@ -81,6 +88,7 @@ static char *strL3State[] =
{
"ST_L3_LC_REL",
"ST_L3_LC_ESTAB_WAIT",
+ "ST_L3_LC_REL_DELAY",
"ST_L3_LC_REL_WAIT",
"ST_L3_LC_ESTAB",
};
@@ -92,9 +100,10 @@ enum {
EV_RELEASE_REQ,
EV_RELEASE_CNF,
EV_RELEASE_IND,
+ EV_TIMEOUT,
};
-#define L3_EVENT_COUNT (EV_RELEASE_IND+1)
+#define L3_EVENT_COUNT (EV_TIMEOUT+1)
static char *strL3Event[] =
{
@@ -104,6 +113,7 @@ static char *strL3Event[] =
"EV_RELEASE_REQ",
"EV_RELEASE_CNF",
"EV_RELEASE_IND",
+ "EV_TIMEOUT",
};
static void
@@ -142,7 +152,14 @@ findie(u_char * p, int size, u_char ie, int wanted_set)
else {
if (codeset == wanted_set) {
if (*p == ie)
- return (p);
+ { /* improved length check (Werner Cornelius) */
+ if ((pend - p) < 2)
+ return(NULL);
+ if (*(p+1) > (pend - (p+2)))
+ return(NULL);
+ return (p);
+ }
+
if (*p > ie)
return (NULL);
}
@@ -158,15 +175,15 @@ findie(u_char * p, int size, u_char ie, int wanted_set)
int
getcallref(u_char * p)
{
- int l, m = 1, cr = 0;
+ int l, cr = 0;
+
p++; /* prot discr */
+ if (*p & 0xfe) /* wrong callref BRI only 1 octet*/
+ return(-2);
l = 0xf & *p++; /* callref length */
if (!l) /* dummy CallRef */
return(-1);
- while (l--) {
- cr += m * (*p++);
- m *= 8;
- }
+ cr = *p++;
return (cr);
}
@@ -186,8 +203,9 @@ void
newl3state(struct l3_process *pc, int state)
{
if (pc->debug & L3_DEB_STATE)
- l3_debug(pc->st, "newstate cr %d %d --> %d", pc->callref,
- pc->state, state);
+ l3_debug(pc->st, "newstate cr %d %d --> %d",
+ pc->callref & 0x7F,
+ pc->state, state);
pc->state = state;
}
@@ -242,6 +260,7 @@ l3_alloc_skb(int len)
printk(KERN_WARNING "HiSax: No skb for D-channel\n");
return (NULL);
}
+ SET_SKB_FREE(skb);
skb_reserve(skb, MAX_HEADER_LEN);
return (skb);
}
@@ -253,10 +272,17 @@ no_l3_proto(struct PStack *st, int pr, void *arg)
HiSax_putstatus(st->l1.hardware, "L3", "no D protocol");
if (skb) {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
}
}
+static int
+no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
+{
+ printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n",ic->arg & 0xFF);
+ return(-1);
+}
+
#ifdef CONFIG_HISAX_EURO
extern void setstack_dss1(struct PStack *st);
#endif
@@ -300,7 +326,7 @@ struct l3_process
np->next = p;
}
p->next = NULL;
- p->debug = L3_DEB_WARN;
+ p->debug = st->l3.debug;
p->callref = cr;
p->state = 0;
p->chan = NULL;
@@ -323,8 +349,19 @@ release_l3_process(struct l3_process *p)
StopAllL3Timer(p);
if (pp)
pp->next = np->next;
- else
- p->st->l3.proc = np->next;
+ else if (!(p->st->l3.proc = np->next) &&
+ !test_bit(FLG_PTP, &p->st->l2.flag)) {
+ if (p->debug)
+ l3_debug(p->st, "release_l3_process: last process");
+ if (!skb_queue_len(&p->st->l3.squeue)) {
+ if (p->debug)
+ l3_debug(p->st, "release_l3_process: release link");
+ FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL);
+ } else {
+ if (p->debug)
+ l3_debug(p->st, "release_l3_process: not release link");
+ }
+ }
kfree(p);
return;
}
@@ -335,6 +372,17 @@ release_l3_process(struct l3_process *p)
l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref);
};
+static void
+l3ml3p(struct PStack *st, int pr)
+{
+ struct l3_process *p = st->l3.proc;
+
+ while (p) {
+ st->l3.l3ml3(st, pr, p);
+ p = p->next;
+ }
+}
+
void
setstack_l3dc(struct PStack *st, struct Channel *chanp)
{
@@ -349,7 +397,9 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp)
st->l3.l3m.userdata = st;
st->l3.l3m.userint = 0;
st->l3.l3m.printdebug = l3m_debug;
+ FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
strcpy(st->l3.debug_id, "L3DC ");
+ st->lli.l4l3_proto = no_l3_proto_spec;
#ifdef CONFIG_HISAX_EURO
if (st->protocol == ISDN_PTYPE_EURO) {
@@ -369,10 +419,12 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp)
if (st->protocol == ISDN_PTYPE_LEASED) {
st->lli.l4l3 = no_l3_proto;
st->l2.l2l3 = no_l3_proto;
+ st->l3.l3ml3 = no_l3_proto;
printk(KERN_INFO "HiSax: Leased line mode\n");
} else {
st->lli.l4l3 = no_l3_proto;
st->l2.l2l3 = no_l3_proto;
+ st->l3.l3ml3 = no_l3_proto;
sprintf(tmp, "protocol %s not supported",
(st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
(st->protocol == ISDN_PTYPE_EURO) ? "euro" :
@@ -398,6 +450,7 @@ releasestack_isdnl3(struct PStack *st)
kfree(st->l3.global);
st->l3.global = NULL;
}
+ FsmDelTimer(&st->l3.l3m_timer, 54);
discard_queue(&st->l3.squeue);
}
@@ -418,6 +471,8 @@ setstack_l3bc(struct PStack *st, struct Channel *chanp)
st->lli.l4l3 = isdnl3_trans;
}
+#define DREL_TIMER_VALUE 40000
+
static void
lc_activate(struct FsmInst *fi, int event, void *arg)
{
@@ -432,12 +487,49 @@ lc_connect(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
+ int dequeued = 0;
FsmChangeState(fi, ST_L3_LC_ESTAB);
while ((skb = skb_dequeue(&st->l3.squeue))) {
st->l3.l3l2(st, DL_DATA | REQUEST, skb);
+ dequeued++;
}
- st->l3.l3l4(st, DL_ESTABLISH | INDICATION, NULL);
+ if ((!st->l3.proc) && dequeued) {
+ if (st->l3.debug)
+ l3_debug(st, "lc_connect: release link");
+ FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
+ } else
+ l3ml3p(st, DL_ESTABLISH | INDICATION);
+}
+
+static void
+lc_connected(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int dequeued = 0;
+
+ FsmDelTimer(&st->l3.l3m_timer, 51);
+ FsmChangeState(fi, ST_L3_LC_ESTAB);
+ while ((skb = skb_dequeue(&st->l3.squeue))) {
+ st->l3.l3l2(st, DL_DATA | REQUEST, skb);
+ dequeued++;
+ }
+ if ((!st->l3.proc) && dequeued) {
+ if (st->l3.debug)
+ l3_debug(st, "lc_connected: release link");
+ FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
+ } else
+ l3ml3p(st, DL_ESTABLISH | CONFIRM);
+}
+
+static void
+lc_start_delay(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ FsmChangeState(fi, ST_L3_LC_REL_DELAY);
+ FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
}
static void
@@ -445,11 +537,15 @@ lc_release_req(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
- if (fi->state == ST_L3_LC_ESTAB_WAIT)
- FsmChangeState(fi, ST_L3_LC_REL);
- else
+ if (test_bit(FLG_L2BLOCK, &st->l2.flag)) {
+ if (st->l3.debug)
+ l3_debug(st, "lc_release_req: l2 blocked");
+ /* restart release timer */
+ FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
+ } else {
FsmChangeState(fi, ST_L3_LC_REL_WAIT);
- st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
+ st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
+ }
}
static void
@@ -457,23 +553,38 @@ lc_release_ind(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
+ FsmDelTimer(&st->l3.l3m_timer, 52);
FsmChangeState(fi, ST_L3_LC_REL);
discard_queue(&st->l3.squeue);
- st->l3.l3l4(st, DL_RELEASE | INDICATION, NULL);
+ l3ml3p(st, DL_RELEASE | INDICATION);
}
+static void
+lc_release_cnf(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ FsmChangeState(fi, ST_L3_LC_REL);
+ discard_queue(&st->l3.squeue);
+ l3ml3p(st, DL_RELEASE | CONFIRM);
+}
+
+
/* *INDENT-OFF* */
static struct FsmNode L3FnList[] HISAX_INITDATA =
{
{ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate},
{ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect},
{ST_L3_LC_REL, EV_ESTABLISH_CNF, lc_connect},
- {ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connect},
- {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_release_req},
+ {ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connected},
+ {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay},
{ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind},
{ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind},
- {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_release_req},
- {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_ind},
+ {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay},
+ {ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind},
+ {ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected},
+ {ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req},
+ {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_cnf},
{ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate},
};
/* *INDENT-ON* */
diff --git a/drivers/isdn/hisax/isdnl3.h b/drivers/isdn/hisax/isdnl3.h
index a0e518f8c..c7050f5f1 100644
--- a/drivers/isdn/hisax/isdnl3.h
+++ b/drivers/isdn/hisax/isdnl3.h
@@ -1,6 +1,12 @@
-/* $Id: isdnl3.h,v 2.3 1998/11/15 23:55:06 keil Exp $
+/* $Id: isdnl3.h,v 2.5 1999/07/25 16:18:32 keil Exp $
* $Log: isdnl3.h,v $
+ * Revision 2.5 1999/07/25 16:18:32 keil
+ * Fix Suspend/Resume
+ *
+ * Revision 2.4 1999/07/01 08:11:54 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.3 1998/11/15 23:55:06 keil
* changes from 2.0
*
@@ -31,14 +37,16 @@
*/
#define SBIT(state) (1<<state)
-#define ALL_STATES 0x00ffffff
+#define ALL_STATES 0x03ffffff
-#define PROTO_DIS_EURO 0x08
+#define PROTO_DIS_EURO 0x08
#define L3_DEB_WARN 0x01
-#define L3_DEB_PROTERR 0x02
-#define L3_DEB_STATE 0x04
-#define L3_DEB_CHARGE 0x08
+#define L3_DEB_PROTERR 0x02
+#define L3_DEB_STATE 0x04
+#define L3_DEB_CHARGE 0x08
+#define L3_DEB_CHECK 0x10
+#define L3_DEB_SI 0x20
struct stateentry {
int state;
diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
new file mode 100644
index 000000000..dd713921a
--- /dev/null
+++ b/drivers/isdn/hisax/isurf.c
@@ -0,0 +1,270 @@
+/* $Id: isurf.c,v 1.5 1999/08/25 17:00:02 keil Exp $
+
+ * isurf.c low level stuff for Siemens I-Surf/I-Talk cards
+ *
+ * Author Karsten Keil (keil@isdn4linux.de)
+ *
+ * $Log: isurf.c,v $
+ * Revision 1.5 1999/08/25 17:00:02 keil
+ * Make ISAR V32bis modem running
+ * Make LL->HL interface open for additional commands
+ *
+ * Revision 1.4 1999/08/22 20:27:09 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.3 1999/07/12 21:05:18 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.2 1999/07/01 08:07:56 keil
+ * Initial version
+ *
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "isar.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+static const char *ISurf_revision = "$Revision: 1.5 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define ISURF_ISAR_RESET 1
+#define ISURF_ISAC_RESET 2
+#define ISURF_ISAR_EA 4
+#define ISURF_ARCOFI_RESET 8
+#define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
+
+#define ISURF_ISAR_OFFSET 0
+#define ISURF_ISAC_OFFSET 0x100
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+ return (readb(cs->hw.isurf.isac + offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ writeb(value, cs->hw.isurf.isac + offset); mb();
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ register int i;
+ for (i = 0; i < size; i++)
+ data[i] = readb(cs->hw.isurf.isac);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ register int i;
+ for (i = 0; i < size; i++){
+ writeb(data[i], cs->hw.isurf.isac);mb();
+ }
+}
+
+/* ISAR access routines
+ * mode = 0 access with IRQ on
+ * mode = 1 access with IRQ off
+ * mode = 2 access with IRQ off and using last offset
+ */
+
+static u_char
+ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
+{
+ return(readb(cs->hw.isurf.isar + offset));
+}
+
+static void
+WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
+{
+ writeb(value, cs->hw.isurf.isar + offset);mb();
+}
+
+static void
+isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+ int cnt = 5;
+
+ if (!cs) {
+ printk(KERN_WARNING "ISurf: Spurious interrupt!\n");
+ return;
+ }
+
+ val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
+ Start_ISAR:
+ if (val & ISAR_IRQSTA)
+ isar_int_main(cs);
+ val = readb(cs->hw.isurf.isac + ISAC_ISTA);
+ Start_ISAC:
+ if (val)
+ isac_interrupt(cs, val);
+ val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
+ if ((val & ISAR_IRQSTA) && --cnt) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "ISAR IntStat after IntRoutine");
+ goto Start_ISAR;
+ }
+ val = readb(cs->hw.isurf.isac + ISAC_ISTA);
+ if (val && --cnt) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ if (!cnt)
+ printk(KERN_WARNING "ISurf IRQ LOOP\n");
+
+ writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
+ writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb();
+ writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb();
+ writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
+}
+
+void
+release_io_isurf(struct IsdnCardState *cs)
+{
+ release_region(cs->hw.isurf.reset, 1);
+}
+
+static void
+reset_isurf(struct IsdnCardState *cs, u_char chips)
+{
+ long flags;
+
+ printk(KERN_INFO "ISurf: resetting card\n");
+
+ byteout(cs->hw.isurf.reset, chips); /* Reset On */
+ save_flags(flags);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((10*HZ)/1000);
+ byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((10*HZ)/1000);
+ restore_flags(flags);
+}
+
+static int
+ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ reset_isurf(cs, ISURF_RESET);
+ return(0);
+ case CARD_RELEASE:
+ release_io_isurf(cs);
+ return(0);
+ case CARD_INIT:
+ clear_pending_isac_ints(cs);
+ writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb();
+ initisac(cs);
+ initisar(cs);
+ /* Reenable ISAC IRQ */
+ cs->writeisac(cs, ISAC_MASK, 0);
+ /* RESET Receiver and Transmitter */
+ cs->writeisac(cs, ISAC_CMDR, 0x41);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+static int
+isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
+ int ret;
+
+ if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
+ ret = isar_auxcmd(cs, ic);
+ if (!ret) {
+ reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
+ ISURF_ARCOFI_RESET);
+ initisac(cs);
+ cs->writeisac(cs, ISAC_MASK, 0);
+ cs->writeisac(cs, ISAC_CMDR, 0x41);
+ }
+ return(ret);
+ }
+ return(isar_auxcmd(cs, ic));
+}
+
+int __init
+setup_isurf(struct IsdnCard *card)
+{
+ int ver;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, ISurf_revision);
+ printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
+
+ if (cs->typ != ISDN_CTYPE_ISURF)
+ return(0);
+ if (card->para[1] && card->para[2]) {
+ cs->hw.isurf.reset = card->para[1];
+ cs->hw.isurf.isar = card->para[2] + ISURF_ISAR_OFFSET;
+ cs->hw.isurf.isac = card->para[2] + ISURF_ISAC_OFFSET;
+ cs->irq = card->para[0];
+ } else {
+ printk(KERN_WARNING "HiSax: %s port/mem not set\n",
+ CardType[card->typ]);
+ return (0);
+ }
+ if (check_region(cs->hw.isurf.reset, 1)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x already in use\n",
+ CardType[card->typ],
+ cs->hw.isurf.reset);
+ return (0);
+ } else {
+ request_region(cs->hw.isurf.reset, 1, "isurf isdn");
+ }
+
+ printk(KERN_INFO
+ "ISurf: defined at 0x%x 0x%x IRQ %d\n",
+ cs->hw.isurf.reset,
+ cs->hw.isurf.isar,
+ cs->irq);
+
+ cs->cardmsg = &ISurf_card_msg;
+ cs->irq_func = &isurf_interrupt;
+ cs->auxcmd = &isurf_auxcmd;
+ cs->readisac = &ReadISAC;
+ cs->writeisac = &WriteISAC;
+ cs->readisacfifo = &ReadISACfifo;
+ cs->writeisacfifo = &WriteISACfifo;
+ cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
+ cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
+ reset_isurf(cs, ISURF_RESET);
+ test_and_set_bit(HW_ISAR, &cs->HW_Flags);
+ ISACVersion(cs, "ISurf:");
+ cs->BC_Read_Reg = &ReadISAR;
+ cs->BC_Write_Reg = &WriteISAR;
+ cs->BC_Send_Data = &isar_fill_fifo;
+ ver = ISARVersion(cs, "ISurf:");
+ if (ver < 0) {
+ printk(KERN_WARNING
+ "ISurf: wrong ISAR version (ret = %d)\n", ver);
+ release_io_isurf(cs);
+ return (0);
+ }
+ return (1);
+}
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
index 732e2b8a7..389d043a3 100644
--- a/drivers/isdn/hisax/ix1_micro.c
+++ b/drivers/isdn/hisax/ix1_micro.c
@@ -1,4 +1,4 @@
-/* $Id: ix1_micro.c,v 2.7 1998/04/15 16:44:31 keil Exp $
+/* $Id: ix1_micro.c,v 2.8 1999/07/12 21:05:19 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,10 @@
* Beat Doebeli
*
* $Log: ix1_micro.c,v $
+ * Revision 2.8 1999/07/12 21:05:19 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
* Revision 2.7 1998/04/15 16:44:31 keil
* new init code
*
@@ -84,7 +88,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *ix1_revision = "$Revision: 2.7 $";
+const char *ix1_revision = "$Revision: 2.8 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -199,7 +203,7 @@ static void
ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
if (!cs) {
printk(KERN_WARNING "IX1: Spurious interrupt!\n");
@@ -207,16 +211,12 @@ ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
- if (val) {
+ if (val)
hscx_int_main(cs, val);
- stat |= 1;
- }
val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
Start_ISAC:
- if (val) {
+ if (val)
isac_interrupt(cs, val);
- stat |= 2;
- }
val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
@@ -229,16 +229,12 @@ ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
- if (stat & 1) {
- 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) {
- 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);
- }
+ 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.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0);
+ 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);
}
void
@@ -276,9 +272,6 @@ ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
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:
inithscxisac(cs, 3);
return(0);
@@ -289,7 +282,7 @@ ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
-int __init
+int __init
setup_ix1micro(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
@@ -331,6 +324,7 @@ setup_ix1micro(struct IsdnCard *card)
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &ix1_card_msg;
+ cs->irq_func = &ix1micro_interrupt;
ISACVersion(cs, "ix1-Micro:");
if (HscxVersion(cs, "ix1-Micro:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
new file mode 100644
index 000000000..5699f28a7
--- /dev/null
+++ b/drivers/isdn/hisax/jade.c
@@ -0,0 +1,326 @@
+/* $Id: jade.c,v 1.2 1999/07/01 08:07:57 keil Exp $
+ *
+ * jade.c JADE stuff (derived from original hscx.c)
+ *
+ * Author Roland Klabunde (R.Klabunde@Berkom.de)
+ *
+ * $Log: jade.c,v $
+ * Revision 1.2 1999/07/01 08:07:57 keil
+ * Initial version
+ *
+ *
+ */
+
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hscx.h"
+#include "jade.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+
+HISAX_INITFUNC(int
+JadeVersion(struct IsdnCardState *cs, char *s))
+{
+ int ver,i;
+ int to = 50;
+ cs->BC_Write_Reg(cs, -1, 0x50, 0x19);
+ i=0;
+ while (to) {
+ udelay(1);
+ ver = cs->BC_Read_Reg(cs, -1, 0x60);
+ to--;
+ if (ver)
+ break;
+ if (!to) {
+ printk(KERN_INFO "%s JADE version not obtainable\n", s);
+ return (0);
+ }
+ }
+ /* Wait for the JADE */
+ udelay(10);
+ /* Read version */
+ ver = cs->BC_Read_Reg(cs, -1, 0x60);
+ printk(KERN_INFO "%s JADE version: %d\n", s, ver);
+ return (1);
+}
+
+/* Write to indirect accessible jade register set */
+static void
+jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value)
+{
+ int to = 50;
+ long flags;
+ u_char ret;
+ save_flags(flags);
+ cli();
+ /* Write the data */
+ cs->BC_Write_Reg(cs, -1, COMM_JADE+1, value);
+ /* Say JADE we wanna write indirect reg 'reg' */
+ cs->BC_Write_Reg(cs, -1, COMM_JADE, reg);
+ to = 50;
+ /* Wait for RDY goes high */
+ while (to) {
+ udelay(1);
+ ret = cs->BC_Read_Reg(cs, -1, COMM_JADE);
+ to--;
+ if (ret & 1)
+ /* Got acknowledge */
+ break;
+ if (!to) {
+ restore_flags(flags);
+ printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value);
+ return;
+ }
+ }
+ restore_flags(flags);
+}
+
+
+
+void
+modejade(struct BCState *bcs, int mode, int bc)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int jade = bcs->hw.hscx.hscx;
+
+ if (cs->debug & L1_DEB_HSCX) {
+ char tmp[40];
+ sprintf(tmp, "jade %c mode %d ichan %d",
+ 'A' + jade, mode, bc);
+ debugl1(cs, tmp);
+ }
+ bcs->mode = mode;
+ bcs->channel = bc;
+
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO:0x00));
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU|jadeCCR0_ITF));
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR1, 0x00);
+
+ jade_write_indirect(cs, jade_HDLC1SERRXPATH, 0x08);
+ jade_write_indirect(cs, jade_HDLC2SERRXPATH, 0x08);
+ jade_write_indirect(cs, jade_HDLC1SERTXPATH, 0x00);
+ jade_write_indirect(cs, jade_HDLC2SERTXPATH, 0x00);
+
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_XCCR, 0x07);
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_RCCR, 0x07);
+
+ if (bc == 0) {
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x00);
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x00);
+ } else {
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x04);
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x04);
+ }
+ switch (mode) {
+ case (L1_MODE_NULL):
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO);
+ break;
+ case (L1_MODE_TRANS):
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO|jadeMODE_RAC|jadeMODE_XAC));
+ break;
+ case (L1_MODE_HDLC):
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC|jadeMODE_XAC));
+ break;
+ }
+ if (mode) {
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES|jadeRCMD_RMC));
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES);
+ /* Unmask ints */
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0xF8);
+ }
+ else
+ /* Mask ints */
+ cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0x00);
+}
+
+void
+jade_sched_event(struct BCState *bcs, int event)
+{
+ bcs->event |= 1 << event;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void
+jade_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ long flags;
+
+ switch (pr) {
+ case (PH_DATA | REQUEST):
+ save_flags(flags);
+ cli();
+ if (st->l1.bcs->tx_skb) {
+ skb_queue_tail(&st->l1.bcs->squeue, skb);
+ restore_flags(flags);
+ } else {
+ st->l1.bcs->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 | INDICATION):
+ if (st->l1.bcs->tx_skb) {
+ printk(KERN_WARNING "jade_l2l1: this shouldn't happen\n");
+ break;
+ }
+ test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ st->l1.bcs->tx_skb = skb;
+ st->l1.bcs->hw.hscx.count = 0;
+ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+ break;
+ case (PH_PULL | REQUEST):
+ if (!st->l1.bcs->tx_skb) {
+ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ } else
+ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ case (PH_ACTIVATE | REQUEST):
+ test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ modejade(st->l1.bcs, st->l1.mode, st->l1.bc);
+ l1_msg_b(st, pr, arg);
+ break;
+ case (PH_DEACTIVATE | REQUEST):
+ l1_msg_b(st, pr, arg);
+ break;
+ case (PH_DEACTIVATE | CONFIRM):
+ test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ modejade(st->l1.bcs, 0, st->l1.bc);
+ st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+ break;
+ }
+}
+
+void
+close_jadestate(struct BCState *bcs)
+{
+ modejade(bcs, 0, bcs->channel);
+ 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;
+ }
+ if (bcs->blog) {
+ kfree(bcs->blog);
+ bcs->blog = NULL;
+ }
+ discard_queue(&bcs->rqueue);
+ discard_queue(&bcs->squeue);
+ if (bcs->tx_skb) {
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
+ bcs->tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+ }
+}
+
+static int
+open_jadestate(struct IsdnCardState *cs, struct BCState *bcs)
+{
+ 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");
+ test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+ return (1);
+ }
+ if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for bcs->blog\n");
+ test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+ kfree(bcs->hw.hscx.rcvbuf);
+ bcs->hw.hscx.rcvbuf = NULL;
+ return (2);
+ }
+ skb_queue_head_init(&bcs->rqueue);
+ skb_queue_head_init(&bcs->squeue);
+ }
+ bcs->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);
+}
+
+
+int
+setstack_jade(struct PStack *st, struct BCState *bcs)
+{
+ bcs->channel = st->l1.bc;
+ if (open_jadestate(st->l1.hardware, bcs))
+ return (-1);
+ st->l1.bcs = bcs;
+ st->l2.l2l1 = jade_l2l1;
+ setstack_manager(st);
+ bcs->st = st;
+ setstack_l1_B(st);
+ return (0);
+}
+
+HISAX_INITFUNC(void
+clear_pending_jade_ints(struct IsdnCardState *cs))
+{
+ int val;
+ char tmp[64];
+
+ cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
+ cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
+
+ val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR);
+ sprintf(tmp, "jade B ISTA %x", val);
+ debugl1(cs, tmp);
+ val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR);
+ sprintf(tmp, "jade A ISTA %x", val);
+ debugl1(cs, tmp);
+ val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR);
+ sprintf(tmp, "jade B STAR %x", val);
+ debugl1(cs, tmp);
+ val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR);
+ sprintf(tmp, "jade A STAR %x", val);
+ debugl1(cs, tmp);
+ /* Unmask ints */
+ cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8);
+ cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
+}
+
+HISAX_INITFUNC(void
+initjade(struct IsdnCardState *cs))
+{
+ cs->bcs[0].BC_SetStack = setstack_jade;
+ cs->bcs[1].BC_SetStack = setstack_jade;
+ cs->bcs[0].BC_Close = close_jadestate;
+ cs->bcs[1].BC_Close = close_jadestate;
+ cs->bcs[0].hw.hscx.hscx = 0;
+ cs->bcs[1].hw.hscx.hscx = 1;
+
+ /* Stop DSP audio tx/rx */
+ jade_write_indirect(cs, 0x11, 0x0f);
+ jade_write_indirect(cs, 0x17, 0x2f);
+
+ /* Transparent Mode, RxTx inactive, No Test, No RFS/TFS */
+ cs->BC_Write_Reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO);
+ cs->BC_Write_Reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO);
+ /* Power down, 1-Idle, RxTx least significant bit first */
+ cs->BC_Write_Reg(cs, 0, jade_HDLC_CCR0, 0x00);
+ cs->BC_Write_Reg(cs, 1, jade_HDLC_CCR0, 0x00);
+ /* Mask all interrupts */
+ cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
+ cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
+ /* Setup host access to hdlc controller */
+ jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1|jadeINDIRECT_HAH2));
+ /* Unmask HDLC int (don´t forget DSP int later on)*/
+ cs->BC_Write_Reg(cs, -1,jade_INT, (jadeINT_HDLC1|jadeINT_HDLC2));
+
+ /* once again TRANSPARENT */
+ modejade(cs->bcs, 0, 0);
+ modejade(cs->bcs + 1, 0, 0);
+}
+
diff --git a/drivers/isdn/hisax/jade.h b/drivers/isdn/hisax/jade.h
new file mode 100644
index 000000000..bcbe6b291
--- /dev/null
+++ b/drivers/isdn/hisax/jade.h
@@ -0,0 +1,137 @@
+/* $Id: jade.h,v 1.2 1999/07/01 08:07:58 keil Exp $
+ * jade.h JADE specific defines
+ *
+ * Author Roland Klabunde (R.Klabunde@Berkom.de)
+ *
+ *
+ * $Log: jade.h,v $
+ * Revision 1.2 1999/07/01 08:07:58 keil
+ * Initial version
+ *
+ *
+ */
+
+/* All Registers original Siemens Spec */
+#ifndef __JADE_H__
+#define __JADE_H__
+
+/* Special registers for access to indirect accessible JADE regs */
+#define DIRECT_IO_JADE 0x0000 /* Jade direct io access area */
+#define COMM_JADE 0x0040 /* Jade communication area */
+
+/********************************************************************/
+/* JADE-HDLC registers */
+/********************************************************************/
+#define jade_HDLC_RFIFO 0x00 /* R */
+#define jade_HDLC_XFIFO 0x00 /* W */
+
+#define jade_HDLC_STAR 0x20 /* R */
+ #define jadeSTAR_XDOV 0x80
+ #define jadeSTAR_XFW 0x40 /* Does not work*/
+ #define jadeSTAR_XCEC 0x20
+ #define jadeSTAR_RCEC 0x10
+ #define jadeSTAR_BSY 0x08
+ #define jadeSTAR_RNA 0x04
+ #define jadeSTAR_STR 0x02
+ #define jadeSTAR_STX 0x01
+
+#define jade_HDLC_XCMD 0x20 /* W */
+ #define jadeXCMD_XF 0x80
+ #define jadeXCMD_XME 0x40
+ #define jadeXCMD_XRES 0x20
+ #define jadeXCMD_STX 0x01
+
+#define jade_HDLC_RSTA 0x21 /* R */
+ #define jadeRSTA_VFR 0x80
+ #define jadeRSTA_RDO 0x40
+ #define jadeRSTA_CRC 0x20
+ #define jadeRSTA_RAB 0x10
+ #define jadeRSTA_MASK 0xF0
+
+#define jade_HDLC_MODE 0x22 /* RW*/
+ #define jadeMODE_TMO 0x80
+ #define jadeMODE_RAC 0x40
+ #define jadeMODE_XAC 0x20
+ #define jadeMODE_TLP 0x10
+ #define jadeMODE_ERFS 0x02
+ #define jadeMODE_ETFS 0x01
+
+#define jade_HDLC_RBCH 0x24 /* R */
+
+#define jade_HDLC_RBCL 0x25 /* R */
+#define jade_HDLC_RCMD 0x25 /* W */
+ #define jadeRCMD_RMC 0x80
+ #define jadeRCMD_RRES 0x40
+ #define jadeRCMD_RMD 0x20
+ #define jadeRCMD_STR 0x02
+
+#define jade_HDLC_CCR0 0x26 /* RW*/
+ #define jadeCCR0_PU 0x80
+ #define jadeCCR0_ITF 0x40
+ #define jadeCCR0_C32 0x20
+ #define jadeCCR0_CRL 0x10
+ #define jadeCCR0_RCRC 0x08
+ #define jadeCCR0_XCRC 0x04
+ #define jadeCCR0_RMSB 0x02
+ #define jadeCCR0_XMSB 0x01
+
+#define jade_HDLC_CCR1 0x27 /* RW*/
+ #define jadeCCR1_RCS0 0x80
+ #define jadeCCR1_RCONT 0x40
+ #define jadeCCR1_RFDIS 0x20
+ #define jadeCCR1_XCS0 0x10
+ #define jadeCCR1_XCONT 0x08
+ #define jadeCCR1_XFDIS 0x04
+
+#define jade_HDLC_TSAR 0x28 /* RW*/
+#define jade_HDLC_TSAX 0x29 /* RW*/
+#define jade_HDLC_RCCR 0x2A /* RW*/
+#define jade_HDLC_XCCR 0x2B /* RW*/
+
+#define jade_HDLC_ISR 0x2C /* R */
+#define jade_HDLC_IMR 0x2C /* W */
+ #define jadeISR_RME 0x80
+ #define jadeISR_RPF 0x40
+ #define jadeISR_RFO 0x20
+ #define jadeISR_XPR 0x10
+ #define jadeISR_XDU 0x08
+ #define jadeISR_ALLS 0x04
+
+#define jade_INT 0x75
+ #define jadeINT_HDLC1 0x02
+ #define jadeINT_HDLC2 0x01
+ #define jadeINT_DSP 0x04
+#define jade_INTR 0x70
+
+/********************************************************************/
+/* Indirect accessible JADE registers of common interest */
+/********************************************************************/
+#define jade_CHIPVERSIONNR 0x00 /* Does not work*/
+
+#define jade_HDLCCNTRACCESS 0x10
+ #define jadeINDIRECT_HAH1 0x02
+ #define jadeINDIRECT_HAH2 0x01
+
+#define jade_HDLC1SERRXPATH 0x1D
+#define jade_HDLC1SERTXPATH 0x1E
+#define jade_HDLC2SERRXPATH 0x1F
+#define jade_HDLC2SERTXPATH 0x20
+ #define jadeINDIRECT_SLIN1 0x10
+ #define jadeINDIRECT_SLIN0 0x08
+ #define jadeINDIRECT_LMOD1 0x04
+ #define jadeINDIRECT_LMOD0 0x02
+ #define jadeINDIRECT_HHR 0x01
+ #define jadeINDIRECT_HHX 0x01
+
+#define jade_RXAUDIOCH1CFG 0x11
+#define jade_RXAUDIOCH2CFG 0x14
+#define jade_TXAUDIOCH1CFG 0x17
+#define jade_TXAUDIOCH2CFG 0x1A
+
+extern int JadeVersion(struct IsdnCardState *cs, char *s);
+extern void jade_sched_event(struct BCState *bcs, int event);
+extern void modejade(struct BCState *bcs, int mode, int bc);
+extern void clear_pending_jade_ints(struct IsdnCardState *cs);
+extern void initjade(struct IsdnCardState *cs);
+
+#endif /* __JADE_H__ */
diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c
new file mode 100644
index 000000000..9cfcc7d6d
--- /dev/null
+++ b/drivers/isdn/hisax/jade_irq.c
@@ -0,0 +1,247 @@
+/* $Id: jade_irq.c,v 1.2 1999/07/01 08:07:59 keil Exp $
+ *
+ * jade_irq.c Low level JADE IRQ stuff (derived from original hscx_irq.c)
+ *
+ * Author Roland Klabunde (R.Klabunde@Berkom.de)
+ *
+ * $Log: jade_irq.c,v $
+ * Revision 1.2 1999/07/01 08:07:59 keil
+ * Initial version
+ *
+ *
+ */
+
+static inline void
+waitforCEC(struct IsdnCardState *cs, int jade, int reg)
+{
+ int to = 50;
+ int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC);
+ while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n");
+}
+
+
+static inline void
+waitforXFW(struct IsdnCardState *cs, int jade)
+{
+ /* Does not work on older jade versions, don't care */
+}
+
+static inline void
+WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ waitforCEC(cs, jade, reg);
+ WRITEJADE(cs, jade, reg, data);
+ restore_flags(flags);
+}
+
+
+
+static void
+jade_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, "jade_empty_fifo");
+
+ if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "jade_empty_fifo: incoming packet too large");
+ WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
+ bcs->hw.hscx.rcvidx = 0;
+ return;
+ }
+ ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+ bcs->hw.hscx.rcvidx += count;
+ save_flags(flags);
+ cli();
+ READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
+ WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
+ restore_flags(flags);
+ if (cs->debug & L1_DEB_HSCX_FIFO) {
+ char *t = bcs->blog;
+
+ t += sprintf(t, "jade_empty_fifo %c cnt %d",
+ bcs->hw.hscx.hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(cs, bcs->blog);
+ }
+}
+
+static void
+jade_fill_fifo(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int more, count;
+ int fifo_size = 32;
+ u_char *ptr;
+ long flags;
+
+ if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+ debugl1(cs, "jade_fill_fifo");
+
+ if (!bcs->tx_skb)
+ return;
+ if (bcs->tx_skb->len <= 0)
+ return;
+
+ more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+ if (bcs->tx_skb->len > fifo_size) {
+ more = !0;
+ count = fifo_size;
+ } else
+ count = bcs->tx_skb->len;
+
+ waitforXFW(cs, bcs->hw.hscx.hscx);
+ save_flags(flags);
+ cli();
+ ptr = bcs->tx_skb->data;
+ skb_pull(bcs->tx_skb, count);
+ bcs->tx_cnt -= count;
+ bcs->hw.hscx.count += count;
+ WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
+ WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME));
+ restore_flags(flags);
+ if (cs->debug & L1_DEB_HSCX_FIFO) {
+ char *t = bcs->blog;
+
+ t += sprintf(t, "jade_fill_fifo %c cnt %d",
+ bcs->hw.hscx.hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(cs, bcs->blog);
+ }
+}
+
+
+static inline void
+jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
+{
+ u_char r;
+ struct BCState *bcs = cs->bcs + jade;
+ struct sk_buff *skb;
+ int fifo_size = 32;
+ int count;
+ int i_jade = (int) jade; /* To satisfy the compiler */
+
+ if (!test_bit(BC_FLG_INIT, &bcs->Flag))
+ return;
+
+ if (val & 0x80) { /* RME */
+ r = READJADE(cs, i_jade, jade_HDLC_RSTA);
+ if ((r & 0xf0) != 0xa0) {
+ if (!(r & 0x80))
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "JADE %s invalid frame", (jade ? "B":"A"));
+ if ((r & 0x40) && bcs->mode)
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "JADE %c RDO mode=%d", 'A'+jade, bcs->mode);
+ if (!(r & 0x20))
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "JADE %c CRC error", 'A'+jade);
+ WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC);
+ } else {
+ count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
+ if (count == 0)
+ count = fifo_size;
+ jade_empty_fifo(bcs, count);
+ if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+ if (cs->debug & L1_DEB_HSCX_FIFO)
+ debugl1(cs, "HX Frame %d", count);
+ if (!(skb = dev_alloc_skb(count)))
+ printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B":"A"));
+ else {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
+ skb_queue_tail(&bcs->rqueue, skb);
+ }
+ }
+ }
+ bcs->hw.hscx.rcvidx = 0;
+ jade_sched_event(bcs, B_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ jade_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 {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
+ skb_queue_tail(&bcs->rqueue, skb);
+ }
+ bcs->hw.hscx.rcvidx = 0;
+ jade_sched_event(bcs, B_RCVBUFREADY);
+ }
+ }
+ if (val & 0x10) { /* XPR */
+ if (bcs->tx_skb) {
+ if (bcs->tx_skb->len) {
+ jade_fill_fifo(bcs);
+ return;
+ } else {
+ if (bcs->st->lli.l1writewakeup &&
+ (PACKET_NOACK != bcs->tx_skb->pkt_type))
+ bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
+ bcs->hw.hscx.count = 0;
+ bcs->tx_skb = NULL;
+ }
+ }
+ if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+ bcs->hw.hscx.count = 0;
+ test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+ jade_fill_fifo(bcs);
+ } else {
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ jade_sched_event(bcs, B_XMTBUFREADY);
+ }
+ }
+}
+
+static inline void
+jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
+{
+ struct BCState *bcs;
+ bcs = cs->bcs + jade;
+
+ if (val & jadeISR_RFO) {
+ /* handled with RDO */
+ val &= ~jadeISR_RFO;
+ }
+ if (val & jadeISR_XDU) {
+ /* relevant in HDLC mode only */
+ /* don't reset XPR here */
+ if (bcs->mode == 1)
+ jade_fill_fifo(bcs);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (bcs->tx_skb) {
+ skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+ bcs->tx_cnt += bcs->hw.hscx.count;
+ bcs->hw.hscx.count = 0;
+ }
+ WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "JADE %c EXIR %x Lost TX", 'A'+jade, val);
+ }
+ }
+ if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "JADE %c interrupt %x", 'A'+jade, val);
+ jade_interrupt(cs, val, jade);
+ }
+}
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
index db6ceca76..ba8d95dbd 100644
--- a/drivers/isdn/hisax/l3_1tr6.c
+++ b/drivers/isdn/hisax/l3_1tr6.c
@@ -1,4 +1,4 @@
-/* $Id: l3_1tr6.c,v 2.8 1998/11/15 23:55:08 keil Exp $
+/* $Id: l3_1tr6.c,v 2.9 1999/07/01 08:11:55 keil Exp $
* German 1TR6 D-channel protocol
*
@@ -10,6 +10,9 @@
*
*
* $Log: l3_1tr6.c,v $
+ * Revision 2.9 1999/07/01 08:11:55 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.8 1998/11/15 23:55:08 keil
* changes from 2.0
*
@@ -56,7 +59,7 @@
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.8 $";
+const char *l3_1tr6_revision = "$Revision: 2.9 $";
#define MsgHead(ptr, cref, mty, dis) \
*ptr++ = dis; \
@@ -91,14 +94,14 @@ l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
l3_1tr6_release_req(pc, 0, NULL);
}
static void
l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb)
{
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
if (pc->st->l3.debug & L3_DEB_WARN)
l3_debug(pc->st, msg);
l3_1tr6_release_req(pc, 0, NULL);
@@ -248,7 +251,7 @@ l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
pc->para.spv = 1;
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
/* Signal all services, linklevel takes care of Service-Indicator */
if (bcfound) {
@@ -287,7 +290,7 @@ l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg)
l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb);
return;
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
L3AddTimer(&pc->timer, T304, CC_T304);
pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
}
@@ -318,7 +321,7 @@ l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg)
l3_1tr6_error(pc, "missing call sent WE0_chanID", skb);
return;
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
L3AddTimer(&pc->timer, T310, CC_T310);
newl3state(pc, 3);
pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
@@ -329,7 +332,7 @@ l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
L3DelTimer(&pc->timer); /* T304 */
newl3state(pc, 4);
pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
@@ -360,7 +363,7 @@ l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
}
} else if (pc->st->l3.debug & L3_DEB_CHARGE)
l3_debug(pc->st, "charging info not found");
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
}
@@ -369,7 +372,7 @@ l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
}
static void
@@ -383,7 +386,7 @@ l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg)
return;
}
newl3state(pc, 10);
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
pc->para.chargeinfo = 0;
pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
}
@@ -407,11 +410,11 @@ l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg)
pc->para.loc = 0;
}
} else {
- pc->para.cause = -1;
+ pc->para.cause = NO_CAUSE;
l3_1tr6_error(pc, "missing REL cause", skb);
return;
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
StopAllL3Timer(pc);
newl3state(pc, 0);
l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
@@ -424,10 +427,10 @@ l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
StopAllL3Timer(pc);
newl3state(pc, 0);
- pc->para.cause = -1;
+ pc->para.cause = NO_CAUSE;
pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
release_l3_process(pc);
}
@@ -475,13 +478,13 @@ l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
} else {
if (pc->st->l3.debug & L3_DEB_WARN)
l3_debug(pc->st, "cause not found");
- pc->para.cause = -1;
+ pc->para.cause = NO_CAUSE;
}
if (!findie(skb->data, skb->len, WE6_date, 6)) {
l3_1tr6_error(pc, "missing connack date", skb);
return;
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
newl3state(pc, 12);
pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
}
@@ -496,7 +499,7 @@ l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg)
l3_1tr6_error(pc, "missing connack date", skb);
return;
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
newl3state(pc, 10);
pc->para.chargeinfo = 0;
L3DelTimer(&pc->timer);
@@ -567,6 +570,9 @@ l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
case 0x10:
clen = 0;
break;
+ case 0x11:
+ cause = CAUSE_UserBusy;
+ break;
case 0x15:
cause = CAUSE_CallRejected;
break;
@@ -620,7 +626,7 @@ l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg)
u_char clen = 1;
L3DelTimer(&pc->timer);
- if (pc->para.cause > 0)
+ if (pc->para.cause != NO_CAUSE)
cause = pc->para.cause;
/* Map DSS1 causes */
switch (cause & 0x7f) {
@@ -679,6 +685,24 @@ l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
release_l3_process(pc);
}
+
+static void
+l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg)
+{
+ pc->para.cause = CAUSE_LocalProcErr;
+ l3_1tr6_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+}
+
+static void
+l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg)
+{
+ newl3state(pc, 0);
+ pc->para.cause = 0x1b; /* Destination out of order */
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ release_l3_process(pc);
+}
+
/* *INDENT-OFF* */
static struct stateentry downstl[] =
{
@@ -689,8 +713,6 @@ static struct stateentry downstl[] =
CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req},
{SBIT(12),
CC_RELEASE | REQUEST, l3_1tr6_release_req},
- {ALL_STATES,
- CC_DLRL | REQUEST, l3_1tr6_reset},
{SBIT(6),
CC_IGNORE | REQUEST, l3_1tr6_reset},
{SBIT(6),
@@ -751,11 +773,22 @@ static struct stateentry datastln1[] =
{SBIT(19),
MT_N1_REL_ACK, l3_1tr6_rel_ack}
};
-/* *INDENT-ON* */
#define DATASTLN1_LEN \
(sizeof(datastln1) / sizeof(struct stateentry))
+static struct stateentry manstatelist[] =
+{
+ {SBIT(2),
+ DL_ESTABLISH | INDICATION, l3_1tr6_dl_reset},
+ {ALL_STATES,
+ DL_RELEASE | INDICATION, l3_1tr6_dl_release},
+};
+
+#define MANSLLEN \
+ (sizeof(manstatelist) / sizeof(struct stateentry))
+/* *INDENT-ON* */
+
static void
up1tr6(struct PStack *st, int pr, void *arg)
{
@@ -778,20 +811,20 @@ up1tr6(struct PStack *st, int pr, void *arg)
}
if (skb->len < 4) {
if (st->l3.debug & L3_DEB_PROTERR) {
- sprintf(tmp, "up1tr6 len only %ld", skb->len);
+ sprintf(tmp, "up1tr6 len only %d", skb->len);
l3_debug(st, tmp);
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
return;
}
if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
if (st->l3.debug & L3_DEB_PROTERR) {
- sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %ld",
+ sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
skb->data[0], skb->len);
l3_debug(st, tmp);
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
return;
}
if (skb->data[1] != 1) {
@@ -799,13 +832,13 @@ up1tr6(struct PStack *st, int pr, void *arg)
sprintf(tmp, "up1tr6 CR len not 1");
l3_debug(st, tmp);
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
return;
}
cr = skb->data[2];
mt = skb->data[3];
if (skb->data[0] == PROTO_DIS_N0) {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "up1tr6%s N0 mt %x unhandled",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt);
@@ -820,11 +853,11 @@ up1tr6(struct PStack *st, int pr, void *arg)
sprintf(tmp, "up1tr6 no roc mem");
l3_debug(st, tmp);
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
return;
}
} else {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
return;
}
} else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) ||
@@ -832,7 +865,7 @@ up1tr6(struct PStack *st, int pr, void *arg)
(mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) ||
(mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) ||
(mt == MT_N1_INFO)) {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
return;
} else {
if (!(proc = new_l3_process(st, cr))) {
@@ -840,7 +873,7 @@ up1tr6(struct PStack *st, int pr, void *arg)
sprintf(tmp, "up1tr6 no roc mem");
l3_debug(st, tmp);
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
return;
}
mt = MT_N1_INVALID;
@@ -851,7 +884,7 @@ up1tr6(struct PStack *st, int pr, void *arg)
((1 << proc->state) & datastln1[i].state))
break;
if (i == DATASTLN1_LEN) {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
@@ -879,7 +912,7 @@ down1tr6(struct PStack *st, int pr, void *arg)
struct Channel *chan;
char tmp[80];
- if (((DL_ESTABLISH | REQUEST)== pr) || ((DL_RELEASE | REQUEST)== pr)) {
+ if ((DL_ESTABLISH | REQUEST)== pr) {
l3_msg(st, pr, NULL);
return;
} else if ((CC_SETUP | REQUEST) == pr) {
@@ -918,6 +951,34 @@ down1tr6(struct PStack *st, int pr, void *arg)
}
}
+static void
+man1tr6(struct PStack *st, int pr, void *arg)
+{
+ int i;
+ struct l3_process *proc = arg;
+
+ if (!proc) {
+ printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr);
+ return;
+ }
+ for (i = 0; i < MANSLLEN; i++)
+ if ((pr == manstatelist[i].primitive) &&
+ ((1 << proc->state) & manstatelist[i].state))
+ break;
+ if (i == MANSLLEN) {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled",
+ proc->callref & 0x7f, proc->state, pr);
+ }
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "cr %d man1tr6 state %d prim %d",
+ proc->callref & 0x7f, proc->state, pr);
+ }
+ manstatelist[i].rout(proc, pr, arg);
+ }
+}
+
void
setstack_1tr6(struct PStack *st)
{
@@ -925,6 +986,7 @@ setstack_1tr6(struct PStack *st)
st->lli.l4l3 = down1tr6;
st->l2.l2l3 = up1tr6;
+ st->l3.l3ml3 = man1tr6;
st->l3.N303 = 0;
strcpy(tmp, l3_1tr6_revision);
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 0808d32a0..22a5de9fa 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.12 1998/11/15 23:55:10 keil Exp $
+/* $Id: l3dss1.c,v 2.19 1999/08/25 16:55:23 keil Exp $
* EURO/DSS1 D-channel protocol
*
@@ -13,6 +13,24 @@
* Fritz Elfert
*
* $Log: l3dss1.c,v $
+ * Revision 2.19 1999/08/25 16:55:23 keil
+ * Fix for test case TC10011
+ *
+ * Revision 2.18 1999/08/11 20:54:39 keil
+ * High layer compatibility is valid in SETUP
+ *
+ * Revision 2.17 1999/07/25 16:18:25 keil
+ * Fix Suspend/Resume
+ *
+ * Revision 2.16 1999/07/21 14:46:23 keil
+ * changes from EICON certification
+ *
+ * Revision 2.14 1999/07/09 08:30:08 keil
+ * cosmetics
+ *
+ * Revision 2.13 1999/07/01 08:11:58 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.12 1998/11/15 23:55:10 keil
* changes from 2.0
*
@@ -72,29 +90,227 @@
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.12 $";
+const char *dss1_revision = "$Revision: 2.19 $";
+
+#define EXT_BEARER_CAPS 1
#define MsgHead(ptr, cref, mty) \
*ptr++ = 0x8; \
- *ptr++ = 0x1; \
- *ptr++ = cref^0x80; \
+ if (cref == -1) { \
+ *ptr++ = 0x0; \
+ } else { \
+ *ptr++ = 0x1; \
+ *ptr++ = cref^0x80; \
+ } \
*ptr++ = mty
-#if HISAX_DE_AOC
+/**********************************************/
+/* get a new invoke id for remote operations. */
+/* Only a return value != 0 is valid */
+/**********************************************/
+static unsigned char new_invoke_id(struct PStack *p)
+{
+ unsigned char retval;
+ int flags,i;
+
+ i = 32; /* maximum search depth */
+
+ save_flags(flags);
+ cli();
+
+ retval = p->prot.dss1.last_invoke_id + 1; /* try new id */
+ while ((i) && (p->prot.dss1.invoke_used[retval >> 3] == 0xFF)) {
+ p->prot.dss1.last_invoke_id = (retval & 0xF8) + 8;
+ i--;
+ }
+ if (i) {
+ while (p->prot.dss1.invoke_used[retval >> 3] & (1 << (retval & 7)))
+ retval++;
+ } else
+ retval = 0;
+ p->prot.dss1.last_invoke_id = retval;
+ p->prot.dss1.invoke_used[retval >> 3] |= (1 << (retval & 7));
+ restore_flags(flags);
+
+ return(retval);
+} /* new_invoke_id */
+
+/*************************/
+/* free a used invoke id */
+/*************************/
+static void free_invoke_id(struct PStack *p, unsigned char id)
+{ int flags;
+
+ if (!id) return; /* 0 = invalid value */
+
+ save_flags(flags);
+ cli();
+ p->prot.dss1.invoke_used[id >> 3] &= ~(1 << (id & 7));
+ restore_flags(flags);
+} /* free_invoke_id */
+
+
+/**********************************************************/
+/* create a new l3 process and fill in dss1 specific data */
+/**********************************************************/
+static struct l3_process
+*dss1_new_l3_process(struct PStack *st, int cr)
+{ struct l3_process *proc;
+
+ if (!(proc = new_l3_process(st, cr)))
+ return(NULL);
+
+ proc->prot.dss1.invoke_id = 0;
+ proc->prot.dss1.remote_operation = 0;
+ proc->prot.dss1.uus1_data[0] = '\0';
+
+ return(proc);
+} /* dss1_new_l3_process */
+
+/************************************************/
+/* free a l3 process and all dss1 specific data */
+/************************************************/
static void
-l3dss1_parse_facility(struct l3_process *pc, u_char * p)
+dss1_release_l3_process(struct l3_process *p)
+{
+ free_invoke_id(p->st,p->prot.dss1.invoke_id);
+ release_l3_process(p);
+} /* dss1_release_l3_process */
+
+/********************************************************/
+/* search a process with invoke id id and dummy callref */
+/********************************************************/
+static struct l3_process *
+l3dss1_search_dummy_proc(struct PStack *st, int id)
+{ struct l3_process *pc = st->l3.proc; /* start of processes */
+
+ if (!id) return(NULL);
+
+ while (pc)
+ { if ((pc->callref == -1) && (pc->prot.dss1.invoke_id == id))
+ return(pc);
+ pc = pc->next;
+ }
+ return(NULL);
+} /* l3dss1_search_dummy_proc */
+
+/*******************************************************************/
+/* called when a facility message with a dummy callref is received */
+/* and a return result is delivered. id specifies the invoke id. */
+/*******************************************************************/
+static void
+l3dss1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
+{ isdn_ctrl ic;
+ struct IsdnCardState *cs;
+ struct l3_process *pc = NULL;
+
+ if ((pc = l3dss1_search_dummy_proc(st, id)))
+ { L3DelTimer(&pc->timer); /* remove timer */
+
+ cs = pc->st->l1.hardware;
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_PROT;
+ ic.arg = DSS1_STAT_INVOKE_RES;
+ ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id;
+ ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id;
+ ic.parm.dss1_io.proc = pc->prot.dss1.proc;
+ ic.parm.dss1_io.timeout= 0;
+ ic.parm.dss1_io.datalen = nlen;
+ ic.parm.dss1_io.data = p;
+ free_invoke_id(pc->st, pc->prot.dss1.invoke_id);
+ pc->prot.dss1.invoke_id = 0; /* reset id */
+
+ cs->iif.statcallb(&ic);
+ dss1_release_l3_process(pc);
+ }
+ else
+ l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen);
+} /* l3dss1_dummy_return_result */
+
+/*******************************************************************/
+/* called when a facility message with a dummy callref is received */
+/* and a return error is delivered. id specifies the invoke id. */
+/*******************************************************************/
+static void
+l3dss1_dummy_error_return(struct PStack *st, int id, ulong error)
+{ isdn_ctrl ic;
+ struct IsdnCardState *cs;
+ struct l3_process *pc = NULL;
+
+ if ((pc = l3dss1_search_dummy_proc(st, id)))
+ { L3DelTimer(&pc->timer); /* remove timer */
+
+ cs = pc->st->l1.hardware;
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_PROT;
+ ic.arg = DSS1_STAT_INVOKE_ERR;
+ ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id;
+ ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id;
+ ic.parm.dss1_io.proc = pc->prot.dss1.proc;
+ ic.parm.dss1_io.timeout= error;
+ ic.parm.dss1_io.datalen = 0;
+ ic.parm.dss1_io.data = NULL;
+ free_invoke_id(pc->st, pc->prot.dss1.invoke_id);
+ pc->prot.dss1.invoke_id = 0; /* reset id */
+
+ cs->iif.statcallb(&ic);
+ dss1_release_l3_process(pc);
+ }
+ else
+ l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error);
+} /* l3dss1_error_return */
+
+/*******************************************************************/
+/* called when a facility message with a dummy callref is received */
+/* and a invoke is delivered. id specifies the invoke id. */
+/*******************************************************************/
+static void
+l3dss1_dummy_invoke(struct PStack *st, int cr, int id,
+ int ident, u_char *p, u_char nlen)
+{ isdn_ctrl ic;
+ struct IsdnCardState *cs;
+
+ l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d",
+ (cr == -1) ? "local" : "broadcast",id,ident,nlen);
+ if (cr >= -1) return; /* ignore local data */
+
+ cs = st->l1.hardware;
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_PROT;
+ ic.arg = DSS1_STAT_INVOKE_BRD;
+ ic.parm.dss1_io.hl_id = id;
+ ic.parm.dss1_io.ll_id = 0;
+ ic.parm.dss1_io.proc = ident;
+ ic.parm.dss1_io.timeout= 0;
+ ic.parm.dss1_io.datalen = nlen;
+ ic.parm.dss1_io.data = p;
+
+ cs->iif.statcallb(&ic);
+} /* l3dss1_dummy_invoke */
+
+static void
+l3dss1_parse_facility(struct PStack *st, struct l3_process *pc,
+ int cr, u_char * p)
{
int qd_len = 0;
+ unsigned char nlen = 0, ilen, cp_tag;
+ int ident, id;
+ ulong err_ret;
+
+ if (pc)
+ st = pc->st; /* valid Stack */
+ else
+ if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */
p++;
qd_len = *p++;
if (qd_len == 0) {
- l3_debug(pc->st, "qd_len == 0");
+ l3_debug(st, "qd_len == 0");
return;
}
if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */
- l3_debug(pc->st, "supplementary service != 0x11");
+ l3_debug(st, "supplementary service != 0x11");
return;
}
while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */
@@ -102,72 +318,92 @@ l3dss1_parse_facility(struct l3_process *pc, u_char * p)
qd_len--;
}
if (qd_len < 2) {
- l3_debug(pc->st, "qd_len < 2");
+ l3_debug(st, "qd_len < 2");
return;
}
p++;
qd_len--;
if ((*p & 0xE0) != 0xA0) { /* class and form */
- l3_debug(pc->st, "class and form != 0xA0");
+ l3_debug(st, "class and form != 0xA0");
return;
}
- switch (*p & 0x1F) { /* component tag */
- case 1: /* invoke */
- {
- unsigned char nlen = 0, 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--;
- }
+
+ cp_tag = *p & 0x1F; /* remember tag value */
+ p++;
+ qd_len--;
+ if (qd_len < 1)
+ { l3_debug(st, "qd_len < 1");
+ return;
+ }
+ if (*p & 0x80)
+ { /* length format indefinite or limited */
+ nlen = *p++ & 0x7F; /* number of len bytes or indefinite */
+ if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) ||
+ (nlen > 1))
+ { l3_debug(st, "length format error or not implemented");
+ return;
+ }
+ if (nlen == 1)
+ { nlen = *p++; /* complete length */
+ qd_len--;
+ }
+ else
+ { qd_len -= 2; /* trailing null bytes */
+ if ((*(p+qd_len)) || (*(p+qd_len+1)))
+ { l3_debug(st,"length format indefinite error");
+ return;
+ }
+ nlen = qd_len;
+ }
+ }
+ else
+ { nlen = *p++;
+ qd_len--;
+ }
+ if (qd_len < nlen)
+ { l3_debug(st, "qd_len < nlen");
+ return;
+ }
+ qd_len -= nlen;
+
+ if (nlen < 2)
+ { l3_debug(st, "nlen < 2");
+ return;
+ }
+ if (*p != 0x02)
+ { /* invoke identifier tag */
+ l3_debug(st, "invoke identifier tag !=0x02");
+ return;
+ }
+ p++;
+ nlen--;
+ if (*p & 0x80)
+ { /* length format */
+ l3_debug(st, "invoke id length format 2");
+ return;
+ }
+ ilen = *p++;
+ nlen--;
+ if (ilen > nlen || ilen == 0)
+ { l3_debug(st, "ilen > nlen || ilen == 0");
+ return;
+ }
+ nlen -= ilen;
+ id = 0;
+ while (ilen > 0)
+ { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */
+ ilen--;
+ }
+
+ switch (cp_tag) { /* component tag */
+ case 1: /* invoke */
if (nlen < 2) {
- l3_debug(pc->st, "nlen < 2 22");
+ l3_debug(st, "nlen < 2 22");
return;
}
if (*p != 0x02) { /* operation value */
- l3_debug(pc->st, "operation value !=0x02");
+ l3_debug(st, "operation value !=0x02");
return;
}
p++;
@@ -175,7 +411,7 @@ l3dss1_parse_facility(struct l3_process *pc, u_char * p)
ilen = *p++;
nlen--;
if (ilen > nlen || ilen == 0) {
- l3_debug(pc->st, "ilen > nlen || ilen == 0 22");
+ l3_debug(st, "ilen > nlen || ilen == 0 22");
return;
}
nlen -= ilen;
@@ -185,11 +421,18 @@ l3dss1_parse_facility(struct l3_process *pc, u_char * p)
ilen--;
}
+ if (!pc)
+ { l3dss1_dummy_invoke(st, cr, id, ident, p, nlen);
+ return;
+ }
+#if HISAX_DE_AOC
+ {
+
#define FOO1(s,a,b) \
while(nlen > 1) { \
int ilen = p[1]; \
if(nlen < ilen+2) { \
- l3_debug(pc->st, "FOO1 nlen < ilen+2"); \
+ l3_debug(st, "FOO1 nlen < ilen+2"); \
return; \
} \
nlen -= ilen+2; \
@@ -203,8 +446,6 @@ l3dss1_parse_facility(struct l3_process *pc, u_char * p)
}
switch (ident) {
- default:
- break;
case 0x22: /* during */
FOO1("1A", 0x30, FOO1("1C", 0xA1, FOO1("1D", 0x30, FOO1("1E", 0x02, ( {
ident = 0;
@@ -215,14 +456,14 @@ l3dss1_parse_facility(struct l3_process *pc, u_char * p)
}
if (ident > pc->para.chargeinfo) {
pc->para.chargeinfo = ident;
- pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
+ st->l3.l3l4(st, CC_CHARGE | INDICATION, pc);
}
- if (pc->st->l3.debug & L3_DEB_CHARGE) {
+ if (st->l3.debug & L3_DEB_CHARGE) {
if (*(p + 2) == 0) {
- l3_debug(pc->st, "charging info during %d", pc->para.chargeinfo);
+ l3_debug(st, "charging info during %d", pc->para.chargeinfo);
}
else {
- l3_debug(pc->st, "charging info final %d", pc->para.chargeinfo);
+ l3_debug(st, "charging info final %d", pc->para.chargeinfo);
}
}
}
@@ -238,113 +479,548 @@ l3dss1_parse_facility(struct l3_process *pc, u_char * p)
}
if (ident > pc->para.chargeinfo) {
pc->para.chargeinfo = ident;
- pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
+ st->l3.l3l4(st, CC_CHARGE | INDICATION, pc);
}
- if (pc->st->l3.debug & L3_DEB_CHARGE) {
- l3_debug(pc->st, "charging info final %d", pc->para.chargeinfo);
+ if (st->l3.debug & L3_DEB_CHARGE) {
+ l3_debug(st, "charging info final %d", pc->para.chargeinfo);
}
}
))))))
break;
+ default:
+ l3_debug(st, "invoke break invalid ident %02x",ident);
+ break;
}
#undef FOO1
}
+#else not HISAX_DE_AOC
+ l3_debug(st, "invoke break");
+#endif not HISAX_DE_AOC
break;
case 2: /* return result */
- l3_debug(pc->st, "return result break");
+ /* if no process available handle separately */
+ if (!pc)
+ { if (cr == -1)
+ l3dss1_dummy_return_result(st, id, p, nlen);
+ return;
+ }
+ if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id))
+ { /* Diversion successfull */
+ free_invoke_id(st,pc->prot.dss1.invoke_id);
+ pc->prot.dss1.remote_result = 0; /* success */
+ pc->prot.dss1.invoke_id = 0;
+ pc->redir_result = pc->prot.dss1.remote_result;
+ st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successfull */
+ else
+ l3_debug(st,"return error unknown identifier");
break;
case 3: /* return error */
- l3_debug(pc->st, "return error break");
+ err_ret = 0;
+ if (nlen < 2)
+ { l3_debug(st, "return error nlen < 2");
+ return;
+ }
+ if (*p != 0x02)
+ { /* result tag */
+ l3_debug(st, "invoke error tag !=0x02");
+ return;
+ }
+ p++;
+ nlen--;
+ if (*p > 4)
+ { /* length format */
+ l3_debug(st, "invoke return errlen > 4 ");
+ return;
+ }
+ ilen = *p++;
+ nlen--;
+ if (ilen > nlen || ilen == 0)
+ { l3_debug(st, "error return ilen > nlen || ilen == 0");
+ return;
+ }
+ nlen -= ilen;
+ while (ilen > 0)
+ { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */
+ ilen--;
+ }
+ /* if no process available handle separately */
+ if (!pc)
+ { if (cr == -1)
+ l3dss1_dummy_error_return(st, id, err_ret);
+ return;
+ }
+ if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id))
+ { /* Deflection error */
+ free_invoke_id(st,pc->prot.dss1.invoke_id);
+ pc->prot.dss1.remote_result = err_ret; /* result */
+ pc->prot.dss1.invoke_id = 0;
+ pc->redir_result = pc->prot.dss1.remote_result;
+ st->l3.l3l4(st, CC_REDIR | INDICATION, pc);
+ } /* Deflection error */
+ else
+ l3_debug(st,"return result unknown identifier");
break;
default:
- l3_debug(pc->st, "default break");
+ l3_debug(st, "facility default break tag=0x%02x",cp_tag);
break;
}
}
-#endif
+
+static void
+l3dss1_message(struct l3_process *pc, u_char mt)
+{
+ struct sk_buff *skb;
+ u_char *p;
+
+ if (!(skb = l3_alloc_skb(4)))
+ return;
+ p = skb_put(skb, 4);
+ MsgHead(p, pc->callref, mt);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3dss1_message_cause(struct l3_process *pc, u_char mt, u_char cause)
+{
+ struct sk_buff *skb;
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+
+ MsgHead(p, pc->callref, mt);
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = cause | 0x80;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3dss1_status_send(struct l3_process *pc, u_char pr, void *arg)
+{
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ struct sk_buff *skb;
+
+ MsgHead(p, pc->callref, MT_STATUS);
+
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = pc->para.cause | 0x80;
+
+ *p++ = IE_CALL_STATE;
+ *p++ = 0x1;
+ *p++ = pc->state & 0x3f;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
+{
+ /* 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
+ * MT_STATUS_ENQUIRE in the NULL state is handled too
+ */
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ struct sk_buff *skb;
+
+ switch (pc->para.cause) {
+ case 81: /* invalid callreference */
+ case 88: /* incomp destination */
+ case 96: /* mandory IE missing */
+ case 100: /* invalid IE contents */
+ case 101: /* incompatible Callstate */
+ MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = pc->para.cause | 0x80;
+ break;
+ default:
+ printk(KERN_ERR "HiSax l3dss1_msg_without_setup wrong cause %d\n",
+ pc->para.cause);
+ return;
+ }
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+ dss1_release_l3_process(pc);
+}
+
+static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
+ IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
+static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
+ IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
+static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
+ IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_CONNECT_PN,
+ IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
+static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, -1};
+static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
+ IE_PROGRESS, IE_DISPLAY, IE_USER_USER, -1};
+static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD,
+ IE_CALLED_PN, -1};
+static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
+ IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
+static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, IE_USER_USER, -1};
+/* a RELEASE_COMPLETE with errors don't require special actions
+static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_USER_USER, -1};
+*/
+static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY,
+ IE_DISPLAY, -1};
+static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY,
+ IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
+ IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_CALLING_PN,
+ IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_LLC, IE_HLC,
+ IE_USER_USER, -1};
+static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
+ IE_PROGRESS, IE_DISPLAY, -1};
+static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
+ IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
+static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1};
+static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+/* not used
+ * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY,
+ * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+ * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1};
+ * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND |
+ * IE_MANDATORY, -1};
+ */
+static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1};
+static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1};
+static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1};
+
+struct ie_len {
+ int ie;
+ int len;
+};
+
+static
+struct ie_len max_ie_len[] = {
+ {IE_SEGMENT, 4},
+ {IE_BEARER, 12},
+ {IE_CAUSE, 32},
+ {IE_CALL_ID, 10},
+ {IE_CALL_STATE, 3},
+ {IE_CHANNEL_ID, 34},
+ {IE_FACILITY, 255},
+ {IE_PROGRESS, 4},
+ {IE_NET_FAC, 255},
+ {IE_NOTIFY, 3},
+ {IE_DISPLAY, 82},
+ {IE_DATE, 8},
+ {IE_KEYPAD, 34},
+ {IE_SIGNAL, 3},
+ {IE_INFORATE, 6},
+ {IE_E2E_TDELAY, 11},
+ {IE_TDELAY_SEL, 5},
+ {IE_PACK_BINPARA, 3},
+ {IE_PACK_WINSIZE, 4},
+ {IE_PACK_SIZE, 4},
+ {IE_CUG, 7},
+ {IE_REV_CHARGE, 3},
+ {IE_CALLING_PN, 24},
+ {IE_CALLING_SUB, 23},
+ {IE_CALLED_PN, 24},
+ {IE_CALLED_SUB, 23},
+ {IE_REDIR_NR, 255},
+ {IE_TRANS_SEL, 255},
+ {IE_RESTART_IND, 3},
+ {IE_LLC, 18},
+ {IE_HLC, 5},
+ {IE_USER_USER, 131},
+ {-1,0},
+};
+
+static int
+getmax_ie_len(u_char ie) {
+ int i = 0;
+ while (max_ie_len[i].ie != -1) {
+ if (max_ie_len[i].ie == ie)
+ return(max_ie_len[i].len);
+ i++;
+ }
+ return(255);
+}
+
+static int
+ie_in_set(struct l3_process *pc, u_char ie, int *checklist) {
+ int ret = 1;
+
+ while (*checklist != -1) {
+ if ((*checklist & 0xff) == ie) {
+ if (ie & 0x80)
+ return(-ret);
+ else
+ return(ret);
+ }
+ ret++;
+ checklist++;
+ }
+ return(0);
+}
static int
-l3dss1_check_messagetype_validity(int mt)
+check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
+{
+ int *cl = checklist;
+ u_char mt;
+ u_char *p, ie;
+ int l, newpos, oldpos;
+ int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
+
+ p = skb->data;
+ /* skip cr */
+ p++;
+ l = (*p++) & 0xf;
+ p += l;
+ mt = *p++;
+ oldpos = 0;
+/* shift codeset procedure not implemented in the moment */
+ while ((p - skb->data) < skb->len) {
+ if ((newpos = ie_in_set(pc, *p, cl))) {
+ if (newpos > 0) {
+ if (newpos < oldpos)
+ err_seq++;
+ else
+ oldpos = newpos;
+ }
+ } else {
+ if (ie_in_set(pc, *p, comp_required))
+ err_compr++;
+ else
+ err_ureg++;
+ }
+ ie = *p++;
+ if (ie & 0x80) {
+ l = 1;
+ } else {
+ l = *p++;
+ p += l;
+ l += 2;
+ }
+ if (l > getmax_ie_len(ie))
+ err_len++;
+ }
+ if (err_compr | err_ureg | err_len | err_seq) {
+ if (pc->debug & L3_DEB_CHECK)
+ l3_debug(pc->st, "check_infoelements mt %x %d/%d/%d/%d",
+ mt, err_compr, err_ureg, err_len, err_seq);
+ if (err_compr)
+ return(ERR_IE_COMPREHENSION);
+ if (err_ureg)
+ return(ERR_IE_UNRECOGNIZED);
+ if (err_len)
+ return(ERR_IE_LENGTH);
+ if (err_seq)
+ return(ERR_IE_SEQUENCE);
+ }
+ return(0);
+}
+
+/* verify if a message type exists and contain no IE error */
+static int
+l3dss1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg)
{
-/* verify if a message type exists */
switch (mt) {
case MT_ALERTING:
case MT_CALL_PROCEEDING:
case MT_CONNECT:
case MT_CONNECT_ACKNOWLEDGE:
+ case MT_DISCONNECT:
+ case MT_INFORMATION:
+ case MT_FACILITY:
+ case MT_NOTIFY:
case MT_PROGRESS:
+ case MT_RELEASE:
+ case MT_RELEASE_COMPLETE:
case MT_SETUP:
case MT_SETUP_ACKNOWLEDGE:
- case MT_RESUME:
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:
+ if (pc->debug & L3_DEB_CHECK)
+ l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) OK", mt);
+ break;
+ case MT_RESUME: /* RESUME only in user->net */
+ case MT_SUSPEND: /* SUSPEND only in user->net */
+ default:
+ if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN))
+ l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) fail", mt);
+ pc->para.cause = 97;
+ l3dss1_status_send(pc, 0, NULL);
return(1);
+ }
+ return(0);
+}
+
+static void
+l3dss1_std_ie_err(struct l3_process *pc, int ret) {
+
+ if (pc->debug & L3_DEB_CHECK)
+ l3_debug(pc->st, "check_infoelements ret %d", ret);
+ switch(ret) {
+ case 0:
+ break;
+ case ERR_IE_COMPREHENSION:
+ pc->para.cause = 96;
+ l3dss1_status_send(pc, 0, NULL);
+ break;
+ case ERR_IE_UNRECOGNIZED:
+ pc->para.cause = 99;
+ l3dss1_status_send(pc, 0, NULL);
+ break;
+ case ERR_IE_LENGTH:
+ pc->para.cause = 100;
+ l3dss1_status_send(pc, 0, NULL);
+ break;
+ case ERR_IE_SEQUENCE:
default:
- return(0);
+ break;
}
+}
+
+static int
+l3dss1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) {
+ u_char *p;
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+ p++;
+ if (*p != 1) { /* len for BRI = 1 */
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "wrong chid len %d", *p);
+ return (-2);
+ }
+ p++;
+ if (*p & 0x60) { /* only base rate interface */
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "wrong chid %x", *p);
+ return (-3);
+ }
+ return(*p & 0x3);
+ } else
+ return(-1);
+}
+
+static int
+l3dss1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
+ u_char l, i=0;
+ u_char *p;
+
+ p = skb->data;
+ pc->para.cause = 31;
+ pc->para.loc = 0;
+ if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+ p++;
+ l = *p++;
+ if (l>30)
+ return(1);
+ if (l) {
+ pc->para.loc = *p++;
+ l--;
+ } else {
+ return(2);
+ }
+ if (l && !(pc->para.loc & 0x80)) {
+ l--;
+ p++; /* skip recommendation */
+ }
+ if (l) {
+ pc->para.cause = *p++;
+ l--;
+ if (!(pc->para.cause & 0x80))
+ return(3);
+ } else
+ return(4);
+ while (l && (i<6)) {
+ pc->para.diag[i++] = *p++;
+ l--;
+ }
+ } else
+ return(-1);
return(0);
}
static void
-l3dss1_message(struct l3_process *pc, u_char mt)
+l3dss1_msg_with_uus(struct l3_process *pc, u_char cmd)
{
struct sk_buff *skb;
- u_char *p;
+ u_char tmp[16+40];
+ u_char *p = tmp;
+ int l;
- if (!(skb = l3_alloc_skb(4)))
+ MsgHead(p, pc->callref, cmd);
+
+ if (pc->prot.dss1.uus1_data[0])
+ { *p++ = IE_USER_USER; /* UUS info element */
+ *p++ = strlen(pc->prot.dss1.uus1_data) + 1;
+ *p++ = 0x04; /* IA5 chars */
+ strcpy(p,pc->prot.dss1.uus1_data);
+ p += strlen(pc->prot.dss1.uus1_data);
+ pc->prot.dss1.uus1_data[0] = '\0';
+ }
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
return;
- p = skb_put(skb, 4);
- MsgHead(p, pc->callref, mt);
+ memcpy(skb_put(skb, l), tmp, l);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
+} /* l3dss1_msg_with_uus */
static void
l3dss1_release_req(struct l3_process *pc, u_char pr, void *arg)
{
StopAllL3Timer(pc);
newl3state(pc, 19);
- l3dss1_message(pc, MT_RELEASE);
+ if (!pc->prot.dss1.uus1_data[0])
+ l3dss1_message(pc, MT_RELEASE);
+ else
+ l3dss1_msg_with_uus(pc, MT_RELEASE);
L3AddTimer(&pc->timer, T308, CC_T308_1);
}
static void
l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
{
- u_char *p;
struct sk_buff *skb = arg;
- int cause = -1;
+ int ret;
- p = skb->data;
- pc->para.loc = 0;
- if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
- p++;
- if (*p++ == 2)
- pc->para.loc = *p++;
- cause = *p & 0x7f;
- }
- dev_kfree_skb(skb);
+ if ((ret = l3dss1_get_cause(pc, skb))>0) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret);
+ } else if (ret < 0)
+ pc->para.cause = NO_CAUSE;
StopAllL3Timer(pc);
- pc->para.cause = cause;
newl3state(pc, 0);
pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
- release_l3_process(pc);
+ dss1_release_l3_process(pc);
}
#if EXT_BEARER_CAPS
@@ -574,9 +1250,8 @@ DecodeSI2(struct sk_buff *skb)
break;
case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption
-
- return DecodeSyncParams(176, p[5]); // V.120
-
+ if (p[1] > 3)
+ return DecodeSyncParams(176, p[5]); // V.120
break;
}
}
@@ -594,6 +1269,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
u_char tmp[128];
u_char *p = tmp;
u_char channel = 0;
+ u_char send_keypad;
u_char screen = 0x80;
u_char *teln;
u_char *msn;
@@ -603,13 +1279,17 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
MsgHead(p, pc->callref, MT_SETUP);
+ teln = pc->para.setup.phone;
+ send_keypad = (strchr(teln,'*') || strchr(teln,'#')) ? 1 : 0;
/*
* Set Bearer Capability, Map info from 1TR6-convention to EDSS1
*/
#if HISAX_EURO_SENDCOMPLETE
- *p++ = 0xa1; /* complete indicator */
+ if (!send_keypad)
+ *p++ = 0xa1; /* complete indicator */
#endif
- switch (pc->para.setup.si1) {
+ if (!send_keypad)
+ switch (pc->para.setup.si1) {
case 1: /* Telephony */
*p++ = 0x4; /* BC-IE-code */
*p++ = 0x3; /* Length */
@@ -625,12 +1305,26 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
*p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
*p++ = 0x90; /* Circuit-Mode 64kbps */
break;
- }
+ }
+ else { *p++ = 0x4; /* assumptions for bearer services with keypad */
+ *p++ = 0x3;
+ *p++ = 0x80;
+ *p++ = 0x90;
+ *p++ = 0xa3;
+ *p++ = 0x18; /* no specific channel */
+ *p++ = 0x01;
+ *p++ = 0x83;
+ *p++ = 0x2C; /* IE keypad */
+ *p++ = strlen(teln);
+ while (*teln)
+ *p++ = (*teln++) & 0x7F;
+ }
+
+
/*
* What about info2? Mapping to High-Layer-Compatibility?
*/
- teln = pc->para.setup.phone;
- if (*teln) {
+ if ((*teln) && (!send_keypad)) {
/* parse number for special things */
if (!isdigit(*teln)) {
switch (0x5f & *teln) {
@@ -650,7 +1344,8 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
case 'D':
screen = 0x80;
break;
- default:
+
+ default:
if (pc->debug & L3_DEB_WARN)
l3_debug(pc->st, "Wrong MSN Code");
break;
@@ -703,24 +1398,33 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
} 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;
- }
+
+ if (!send_keypad) {
+ *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;
+ }
+ }
#if EXT_BEARER_CAPS
- if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
+ if (send_keypad) { /* special handling independant of si2 */
+ *p++ = 0x7c;
+ *p++ = 0x03;
+ *p++ = 0x80;
+ *p++ = 0x90;
+ *p++ = 0xa3;
+ } else if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
*p++ = 0x7c;
*p++ = 0x04;
@@ -767,74 +1471,136 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
static void
l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg)
{
- u_char *p;
struct sk_buff *skb = arg;
-
+ int id, ret;
+
+ if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) {
+ if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer with wrong chid %x", id);
+ pc->para.cause = 100;
+ l3dss1_status_send(pc, pr, NULL);
+ return;
+ }
+ pc->para.bchannel = id;
+ } else if (1 == pc->state) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
+ if (id == -1)
+ pc->para.cause = 96;
+ else
+ pc->para.cause = 100;
+ l3dss1_status_send(pc, pr, NULL);
+ return;
+ }
+ /* Now we are on none mandatory IEs */
+ ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3dss1_std_ie_err(pc, ret);
+ return;
+ }
L3DelTimer(&pc->timer);
- p = skb->data;
- 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(pc, 3);
L3AddTimer(&pc->timer, T310, CC_T310);
+ if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+ l3dss1_std_ie_err(pc, ret);
pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
}
static void
l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
{
- u_char *p;
struct sk_buff *skb = arg;
-
+ int id, ret;
+
+ if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) {
+ if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer with wrong chid %x", id);
+ pc->para.cause = 100;
+ l3dss1_status_send(pc, pr, NULL);
+ return;
+ }
+ pc->para.bchannel = id;
+ } else {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
+ if (id == -1)
+ pc->para.cause = 96;
+ else
+ pc->para.cause = 100;
+ l3dss1_status_send(pc, pr, NULL);
+ return;
+ }
+ /* Now we are on none mandatory IEs */
+ ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3dss1_std_ie_err(pc, ret);
+ return;
+ }
L3DelTimer(&pc->timer);
- p = skb->data;
- 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(pc, 2);
L3AddTimer(&pc->timer, T304, CC_T304);
+ if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+ l3dss1_std_ie_err(pc, ret);
pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
}
static void
l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg)
{
- u_char *p;
struct sk_buff *skb = arg;
- int cause = -1;
+ u_char *p;
+ int ret;
+ u_char cause = 0;
StopAllL3Timer(pc);
- p = skb->data;
- pc->para.loc = 0;
- if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
- p++;
- if (*p++ == 2)
- pc->para.loc = *p++;
- cause = *p & 0x7f;
- }
- dev_kfree_skb(skb);
+ if ((ret = l3dss1_get_cause(pc, skb))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "DISC get_cause ret(%d)", ret);
+ if (ret < 0)
+ cause = 96;
+ else if (ret > 0)
+ cause = 100;
+ }
+ if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
+ l3dss1_parse_facility(pc->st, pc, pc->callref, p);
+ ret = check_infoelements(pc, skb, ie_DISCONNECT);
+ if (ERR_IE_COMPREHENSION == ret)
+ cause = 96;
+ else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret))
+ cause = 99;
+ ret = pc->state;
newl3state(pc, 12);
- pc->para.cause = cause;
- pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
+ if (cause)
+ newl3state(pc, 19);
+ if (11 != ret)
+ pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
+ else if (!cause)
+ l3dss1_release_req(pc, pr, NULL);
+ if (cause) {
+ l3dss1_message_cause(pc, MT_RELEASE, cause);
+ L3AddTimer(&pc->timer, T308, CC_T308_1);
+ }
}
static void
l3dss1_connect(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
+ int ret;
- dev_kfree_skb(skb);
+ ret = check_infoelements(pc, skb, ie_CONNECT);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3dss1_std_ie_err(pc, ret);
+ return;
+ }
L3DelTimer(&pc->timer); /* T310 */
newl3state(pc, 10);
pc->para.chargeinfo = 0;
+ /* here should inserted COLP handling KKe */
+ if (ret)
+ l3dss1_std_ie_err(pc, ret);
pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
}
@@ -842,143 +1608,139 @@ static void
l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
+ int ret;
- dev_kfree_skb(skb);
+ ret = check_infoelements(pc, skb, ie_ALERTING);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3dss1_std_ie_err(pc, ret);
+ return;
+ }
L3DelTimer(&pc->timer); /* T304 */
newl3state(pc, 4);
+ if (ret)
+ l3dss1_std_ie_err(pc, ret);
pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
}
static void
-l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
-{
- /* 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
- * 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 88: /* 0x58 incomp destination */
- 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);
- l3_msg(pc->st, DL_DATA | REQUEST, 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;
+ u_char *p;
int bcfound = 0;
char tmp[80];
struct sk_buff *skb = arg;
+ int id;
+ int err = 0;
- /* ETS 300-104 1.3.4 and 1.3.5
- * we need to detect unknown inform. element from 0 to 7
+ /*
+ * Bearer Capabilities
*/
p = skb->data;
- 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);
+ /* only the first occurence 'll be detected ! */
+ if ((p = findie(p, skb->len, 0x04, 0))) {
+ if ((p[1] < 2) || (p[1] > 11))
+ err = 1;
+ else {
+ pc->para.setup.si2 = 0;
+ switch (p[2] & 0x7f) {
+ case 0x00: /* Speech */
+ case 0x10: /* 3.1 Khz audio */
+ pc->para.setup.si1 = 1;
+ break;
+ case 0x08: /* Unrestricted digital information */
+ pc->para.setup.si1 = 7;
+/* JIM, 05.11.97 I wanna set service indicator 2 */
+#if EXT_BEARER_CAPS
+ pc->para.setup.si2 = DecodeSI2(skb);
+#endif
+ break;
+ case 0x09: /* Restricted digital information */
+ pc->para.setup.si1 = 2;
+ break;
+ case 0x11:
+ /* Unrestr. digital information with
+ * tones/announcements ( or 7 kHz audio
+ */
+ pc->para.setup.si1 = 3;
+ break;
+ case 0x18: /* Video */
+ pc->para.setup.si1 = 4;
+ break;
+ default:
+ err = 2;
+ break;
+ }
+ switch (p[3] & 0x7f) {
+ case 0x40: /* packed mode */
+ pc->para.setup.si1 = 8;
+ break;
+ case 0x10: /* 64 kbit */
+ case 0x11: /* 2*64 kbit */
+ case 0x13: /* 384 kbit */
+ case 0x15: /* 1536 kbit */
+ case 0x17: /* 1920 kbit */
+ pc->para.moderate = p[3] & 0x7f;
+ break;
+ default:
+ err = 3;
+ break;
+ }
+ }
+ if (pc->debug & L3_DEB_SI)
+ l3_debug(pc->st, "SI=%d, AI=%d",
+ pc->para.setup.si1, pc->para.setup.si2);
+ if (err) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)",
+ p[1], p[2], p[3]);
+ pc->para.cause = 100;
+ l3dss1_msg_without_setup(pc, pr, NULL);
+ return;
+ }
+ } else {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup without bearer capabilities");
+ /* ETS 300-104 1.3.3 */
+ pc->para.cause = 96;
l3dss1_msg_without_setup(pc, pr, NULL);
return;
}
/*
* Channel Identification
*/
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
- pc->para.bchannel = p[2] & 0x3;
- if (pc->para.bchannel)
+ if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) {
+ if ((pc->para.bchannel = id)) {
+ if ((3 == id) && (0x10 == pc->para.moderate)) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "setup with wrong chid %x",
+ id);
+ pc->para.cause = 100;
+ l3dss1_msg_without_setup(pc, pr, NULL);
+ return;
+ }
bcfound++;
- 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, call waiting");
+ bcfound++;
+ }
} else {
if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup without bchannel");
- pc->para.cause = 0x60;
- dev_kfree_skb(skb);
+ l3_debug(pc->st, "setup with wrong chid ret %d", id);
+ if (id == -1)
+ pc->para.cause = 96;
+ else
+ pc->para.cause = 100;
l3dss1_msg_without_setup(pc, pr, NULL);
return;
}
- /*
- * Bearer Capabilities
- */
- p = skb->data;
- if ((p = findie(p, skb->len, 0x04, 0))) {
- pc->para.setup.si2 = 0;
- switch (p[2] & 0x1f) {
- case 0x00:
- /* Speech */
- case 0x10:
- /* 3.1 Khz audio */
- pc->para.setup.si1 = 1;
- break;
- case 0x08:
- /* Unrestricted digital information */
- pc->para.setup.si1 = 7;
-/* JIM, 05.11.97 I wanna set service indicator 2 */
-#if EXT_BEARER_CAPS
- pc->para.setup.si2 = DecodeSI2(skb);
- printk(KERN_DEBUG "HiSax: SI=%d, AI=%d\n",
- pc->para.setup.si1, pc->para.setup.si2);
-#endif
- break;
- case 0x09:
- /* Restricted digital information */
- pc->para.setup.si1 = 2;
- break;
- case 0x11:
- /* Unrestr. digital information with tones/announcements */
- pc->para.setup.si1 = 3;
- break;
- case 0x18:
- /* Video */
- pc->para.setup.si1 = 4;
- break;
- default:
- pc->para.setup.si1 = 0;
- }
- } 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);
+ /* Now we are on none mandatory IEs */
+ err = check_infoelements(pc, skb, ie_SETUP);
+ if (ERR_IE_COMPREHENSION == err) {
+ pc->para.cause = 96;
l3dss1_msg_without_setup(pc, pr, NULL);
return;
}
-
p = skb->data;
if ((p = findie(p, skb->len, 0x70, 0)))
iecpy(pc->para.setup.eazmsn, p, 1);
@@ -1020,62 +1782,28 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
} else if (pc->debug & L3_DEB_WARN)
l3_debug(pc->st, "wrong calling subaddress");
}
- dev_kfree_skb(skb);
-
- if (bcfound) {
- if ((pc->para.setup.si1 != 7) && (pc->debug & L3_DEB_WARN)) {
- l3_debug(pc->st, "non-digital call: %s -> %s",
- pc->para.setup.phone, pc->para.setup.eazmsn);
- }
- if ((pc->para.setup.si1 != 7) &&
- test_bit(FLG_PTP, &pc->st->l2.flag)) {
- pc->para.cause = 0x58;
- l3dss1_msg_without_setup(pc, pr, NULL);
- return;
- }
- newl3state(pc, 6);
- pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
- } else
- release_l3_process(pc);
+ newl3state(pc, 6);
+ if (err) /* STATUS for none mandatory IE errors after actions are taken */
+ l3dss1_std_ie_err(pc, err);
+ pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
}
static void
l3dss1_reset(struct l3_process *pc, u_char pr, void *arg)
{
- release_l3_process(pc);
-}
-
-static void
-l3dss1_setup_rsp(struct l3_process *pc, u_char pr,
- void *arg)
-{
- newl3state(pc, 8);
- l3dss1_message(pc, MT_CONNECT);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T313, CC_T313);
-}
-
-static void
-l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
-{
- struct sk_buff *skb = arg;
-
- dev_kfree_skb(skb);
- newl3state(pc, 10);
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+ dss1_release_l3_process(pc);
}
static void
l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb;
- u_char tmp[16];
+ u_char tmp[16+40];
u_char *p = tmp;
int l;
- u_char cause = 0x10;
+ u_char cause = 16;
- if (pc->para.cause > 0)
+ if (pc->para.cause != NO_CAUSE)
cause = pc->para.cause;
StopAllL3Timer(pc);
@@ -1087,6 +1815,15 @@ l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
*p++ = 0x80;
*p++ = cause | 0x80;
+ if (pc->prot.dss1.uus1_data[0])
+ { *p++ = IE_USER_USER; /* UUS info element */
+ *p++ = strlen(pc->prot.dss1.uus1_data) + 1;
+ *p++ = 0x04; /* IA5 chars */
+ strcpy(p,pc->prot.dss1.uus1_data);
+ p += strlen(pc->prot.dss1.uus1_data);
+ pc->prot.dss1.uus1_data[0] = '\0';
+ }
+
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
@@ -1097,15 +1834,49 @@ l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
}
static void
+l3dss1_setup_rsp(struct l3_process *pc, u_char pr,
+ void *arg)
+{
+ if (!pc->para.bchannel)
+ { if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "D-chan connect for waiting call");
+ l3dss1_disconnect_req(pc, pr, arg);
+ return;
+ }
+ newl3state(pc, 8);
+ l3dss1_message(pc, MT_CONNECT);
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T313, CC_T313);
+}
+
+static void
+l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int ret;
+
+ ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3dss1_std_ie_err(pc, ret);
+ return;
+ }
+ newl3state(pc, 10);
+ L3DelTimer(&pc->timer);
+ if (ret)
+ l3dss1_std_ie_err(pc, ret);
+ pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+}
+
+static void
l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb;
u_char tmp[16];
u_char *p = tmp;
int l;
- u_char cause = 0x95;
+ u_char cause = 21;
- if (pc->para.cause > 0)
+ if (pc->para.cause != NO_CAUSE)
cause = pc->para.cause;
MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
@@ -1113,7 +1884,7 @@ l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg)
*p++ = IE_CAUSE;
*p++ = 0x2;
*p++ = 0x80;
- *p++ = cause;
+ *p++ = cause | 0x80;
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
@@ -1122,38 +1893,41 @@ l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg)
l3_msg(pc->st, DL_DATA | REQUEST, skb);
pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
- release_l3_process(pc);
+ dss1_release_l3_process(pc);
}
static void
l3dss1_release(struct l3_process *pc, u_char pr, void *arg)
{
- u_char *p;
struct sk_buff *skb = arg;
- int cause = -1;
+ u_char *p;
+ int ret, cause=0;
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
- p++;
- if (*p++ == 2)
- pc->para.loc = *p++;
- cause = *p & 0x7f;
- }
- p = skb->data;
- if ((p = findie(p, skb->len, IE_FACILITY, 0))) {
-#if HISAX_DE_AOC
- l3dss1_parse_facility(pc, p);
-#else
- p = NULL;
-#endif
- }
- dev_kfree_skb(skb);
StopAllL3Timer(pc);
- pc->para.cause = cause;
- l3dss1_message(pc, MT_RELEASE_COMPLETE);
+ if ((ret = l3dss1_get_cause(pc, skb))>0) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "REL get_cause ret(%d)", ret);
+ } else if (ret<0)
+ pc->para.cause = NO_CAUSE;
+ if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
+ l3dss1_parse_facility(pc->st, pc, pc->callref, p);
+ }
+ if ((ret<0) && (pc->state != 11))
+ cause = 96;
+ else if (ret>0)
+ cause = 100;
+ ret = check_infoelements(pc, skb, ie_RELEASE);
+ if (ERR_IE_COMPREHENSION == ret)
+ cause = 96;
+ else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause))
+ cause = 99;
+ if (cause)
+ l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
+ else
+ l3dss1_message(pc, MT_RELEASE_COMPLETE);
pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
- release_l3_process(pc);
+ dss1_release_l3_process(pc);
}
static void
@@ -1161,66 +1935,358 @@ l3dss1_alert_req(struct l3_process *pc, u_char pr,
void *arg)
{
newl3state(pc, 7);
- l3dss1_message(pc, MT_ALERTING);
+ if (!pc->prot.dss1.uus1_data[0])
+ l3dss1_message(pc, MT_ALERTING);
+ else
+ l3dss1_msg_with_uus(pc, MT_ALERTING);
}
static void
-l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg)
+l3dss1_proceed_req(struct l3_process *pc, u_char pr,
+ void *arg)
{
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- struct sk_buff *skb = arg;
+ newl3state(pc, 9);
+ l3dss1_message(pc, MT_CALL_PROCEEDING);
+ pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
+}
- dev_kfree_skb(skb);
+/********************************************/
+/* deliver a incoming display message to HL */
+/********************************************/
+static void
+l3dss1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
+{ u_char len;
+ isdn_ctrl ic;
+ struct IsdnCardState *cs;
+ char *p;
+
+ if (*infp++ != IE_DISPLAY) return;
+ if ((len = *infp++) > 80) return; /* total length <= 82 */
+ if (!pc->chan) return;
+
+ p = ic.parm.display;
+ while (len--)
+ *p++ = *infp++;
+ *p = '\0';
+ ic.command = ISDN_STAT_DISPLAY;
+ cs = pc->st->l1.hardware;
+ ic.driver = cs->myid;
+ ic.arg = pc->chan->chan;
+ cs->iif.statcallb(&ic);
+} /* l3dss1_deliver_display */
- MsgHead(p, pc->callref, MT_STATUS);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 0x9E; /* answer status enquire */
+static void
+l3dss1_progress(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int err = 0;
+ u_char *p;
- *p++ = 0x14; /* CallState */
- *p++ = 0x1;
- *p++ = pc->state & 0x3f;
+ if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) {
+ if (p[1] != 2) {
+ err = 1;
+ pc->para.cause = 100;
+ } else if (p[2] & 0x60) {
+ switch (p[2]) {
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x84:
+ case 0x85:
+ case 0x87:
+ case 0x8a:
+ switch (p[3]) {
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x88:
+ break;
+ default:
+ err = 2;
+ pc->para.cause = 100;
+ break;
+ }
+ break;
+ default:
+ err = 3;
+ pc->para.cause = 100;
+ break;
+ }
+ }
+ } else {
+ pc->para.cause = 96;
+ err = 4;
+ }
+ if (err) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "progress error %d", err);
+ l3dss1_status_send(pc, pr, NULL);
+ return;
+ }
+ /* Now we are on none mandatory IEs */
+ err = check_infoelements(pc, skb, ie_PROGRESS);
+ if (err)
+ l3dss1_std_ie_err(pc, err);
+ if (ERR_IE_COMPREHENSION != err)
+ pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
+}
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
+static void
+l3dss1_notify(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ int err = 0;
+ u_char *p;
+
+ if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) {
+ if (p[1] != 1) {
+ err = 1;
+ pc->para.cause = 100;
+ } else {
+ switch (p[2]) {
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ break;
+ default:
+ pc->para.cause = 100;
+ err = 2;
+ break;
+ }
+ }
+ } else {
+ pc->para.cause = 96;
+ err = 3;
+ }
+ if (err) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "notify error %d", err);
+ l3dss1_status_send(pc, pr, NULL);
return;
- memcpy(skb_put(skb, l), tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
+ }
+ /* Now we are on none mandatory IEs */
+ err = check_infoelements(pc, skb, ie_NOTIFY);
+ if (err)
+ l3dss1_std_ie_err(pc, err);
+ if (ERR_IE_COMPREHENSION != err)
+ pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
}
static void
-l3dss1_status_req(struct l3_process *pc, u_char pr, void *arg)
+l3dss1_status_enq(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;
+ int ret;
struct sk_buff *skb = arg;
- dev_kfree_skb(skb);
+ ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY);
+ l3dss1_std_ie_err(pc, ret);
+ pc->para.cause = 30; /* response to STATUS_ENQUIRY */
+ l3dss1_status_send(pc, pr, NULL);
+}
- MsgHead(p, pc->callref, MT_STATUS);
+static void
+l3dss1_information(struct l3_process *pc, u_char pr, void *arg)
+{
+ int ret;
+ struct sk_buff *skb = arg;
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 0x62 | 0x80; /* status sending */
+ ret = check_infoelements(pc, skb, ie_INFORMATION);
+ l3dss1_std_ie_err(pc, ret);
+}
- *p++ = 0x14; /* CallState */
- *p++ = 0x1;
- *p++ = pc->state & 0x3f;
+/******************************/
+/* handle deflection requests */
+/******************************/
+static void l3dss1_redir_req(struct l3_process *pc, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[128];
+ u_char *p = tmp;
+ u_char *subp;
+ u_char len_phone = 0;
+ u_char len_sub = 0;
+ int l;
+
+
+ strcpy(pc->prot.dss1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */
+ if (!pc->chan->setup.phone[0])
+ { pc->para.cause = -1;
+ l3dss1_disconnect_req(pc,pr,arg); /* disconnect immediately */
+ return;
+ } /* only uus */
+
+ if (pc->prot.dss1.invoke_id)
+ free_invoke_id(pc->st,pc->prot.dss1.invoke_id);
+
+ if (!(pc->prot.dss1.invoke_id = new_invoke_id(pc->st)))
+ return;
+
+ MsgHead(p, pc->callref, MT_FACILITY);
+
+ for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */
+ if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */
+
+ *p++ = 0x1c; /* Facility info element */
+ *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */
+ *p++ = 0x91; /* remote operations protocol */
+ *p++ = 0xa1; /* invoke component */
+
+ *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */
+ *p++ = 0x02; /* invoke id tag, integer */
+ *p++ = 0x01; /* length */
+ *p++ = pc->prot.dss1.invoke_id; /* invoke id */
+ *p++ = 0x02; /* operation value tag, integer */
+ *p++ = 0x01; /* length */
+ *p++ = 0x0D; /* Call Deflect */
+
+ *p++ = 0x30; /* sequence phone number */
+ *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */
+
+ *p++ = 0x30; /* Deflected to UserNumber */
+ *p++ = len_phone+2+len_sub; /* length */
+ *p++ = 0x80; /* NumberDigits */
+ *p++ = len_phone; /* length */
+ for (l = 0; l < len_phone; l++)
+ *p++ = pc->chan->setup.phone[l];
+
+ if (len_sub)
+ { *p++ = 0x04; /* called party subadress */
+ *p++ = len_sub - 2;
+ while (*subp) *p++ = *subp++;
+ }
+
+ *p++ = 0x01; /* screening identifier */
+ *p++ = 0x01;
+ *p++ = pc->chan->setup.screen;
l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
+ if (!(skb = l3_alloc_skb(l))) return;
memcpy(skb_put(skb, l), tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
-}
+
+ l3_msg(pc->st, DL_DATA | REQUEST, skb);
+} /* l3dss1_redir_req */
+
+/********************************************/
+/* handle deflection request in early state */
+/********************************************/
+static void l3dss1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
+{
+ l3dss1_proceed_req(pc,pr,arg);
+ l3dss1_redir_req(pc,pr,arg);
+} /* l3dss1_redir_req_early */
+
+/***********************************************/
+/* handle special commands for this protocol. */
+/* Examples are call independant services like */
+/* remote operations with dummy callref. */
+/***********************************************/
+static int l3dss1_cmd_global(struct PStack *st, isdn_ctrl *ic)
+{ u_char id;
+ u_char temp[265];
+ u_char *p = temp;
+ int i, l, proc_len;
+ struct sk_buff *skb;
+ struct l3_process *pc = NULL;
+
+ switch (ic->arg)
+ { case DSS1_CMD_INVOKE:
+ if (ic->parm.dss1_io.datalen < 0) return(-2); /* invalid parameter */
+
+ for (proc_len = 1, i = ic->parm.dss1_io.proc >> 8; i; i++)
+ i = i >> 8; /* add one byte */
+ l = ic->parm.dss1_io.datalen + proc_len + 8; /* length excluding ie header */
+ if (l > 255)
+ return(-2); /* too long */
+
+ if (!(id = new_invoke_id(st)))
+ return(0); /* first get a invoke id -> return if no available */
+
+ i = -1;
+ MsgHead(p, i, MT_FACILITY); /* build message head */
+ *p++ = 0x1C; /* Facility IE */
+ *p++ = l; /* length of ie */
+ *p++ = 0x91; /* remote operations */
+ *p++ = 0xA1; /* invoke */
+ *p++ = l - 3; /* length of invoke */
+ *p++ = 0x02; /* invoke id tag */
+ *p++ = 0x01; /* length is 1 */
+ *p++ = id; /* invoke id */
+ *p++ = 0x02; /* operation */
+ *p++ = proc_len; /* length of operation */
+
+ for (i = proc_len; i; i--)
+ *p++ = (ic->parm.dss1_io.proc >> (i-1)) & 0xFF;
+ memcpy(p, ic->parm.dss1_io.data, ic->parm.dss1_io.datalen); /* copy data */
+ l = (p - temp) + ic->parm.dss1_io.datalen; /* total length */
+
+ if (ic->parm.dss1_io.timeout > 0)
+ if (!(pc = dss1_new_l3_process(st, -1)))
+ { free_invoke_id(st, id);
+ return(-2);
+ }
+ pc->prot.dss1.ll_id = ic->parm.dss1_io.ll_id; /* remember id */
+ pc->prot.dss1.proc = ic->parm.dss1_io.proc; /* and procedure */
+
+ if (!(skb = l3_alloc_skb(l)))
+ { free_invoke_id(st, id);
+ if (pc) dss1_release_l3_process(pc);
+ return(-2);
+ }
+ memcpy(skb_put(skb, l), temp, l);
+
+ if (pc)
+ { pc->prot.dss1.invoke_id = id; /* remember id */
+ L3AddTimer(&pc->timer, ic->parm.dss1_io.timeout, CC_TDSS1_IO | REQUEST);
+ }
+
+ l3_msg(st, DL_DATA | REQUEST, skb);
+ ic->parm.dss1_io.hl_id = id; /* return id */
+ return(0);
+
+ case DSS1_CMD_INVOKE_ABORT:
+ if ((pc = l3dss1_search_dummy_proc(st, ic->parm.dss1_io.hl_id)))
+ { L3DelTimer(&pc->timer); /* remove timer */
+ dss1_release_l3_process(pc);
+ return(0);
+ }
+ else
+ { l3_debug(st, "l3dss1_cmd_global abort unknown id");
+ return(-2);
+ }
+ break;
+
+ default:
+ l3_debug(st, "l3dss1_cmd_global unknown cmd 0x%lx", ic->arg);
+ return(-1);
+ } /* switch ic-> arg */
+ return(-1);
+} /* l3dss1_cmd_global */
+
+static void
+l3dss1_io_timer(struct l3_process *pc)
+{ isdn_ctrl ic;
+ struct IsdnCardState *cs = pc->st->l1.hardware;
+
+ L3DelTimer(&pc->timer); /* remove timer */
+
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_PROT;
+ ic.arg = DSS1_STAT_INVOKE_ERR;
+ ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id;
+ ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id;
+ ic.parm.dss1_io.proc = pc->prot.dss1.proc;
+ ic.parm.dss1_io.timeout= -1;
+ ic.parm.dss1_io.datalen = 0;
+ ic.parm.dss1_io.data = NULL;
+ free_invoke_id(pc->st, pc->prot.dss1.invoke_id);
+ pc->prot.dss1.invoke_id = 0; /* reset id */
+
+ cs->iif.statcallb(&ic);
+
+ dss1_release_l3_process(pc);
+} /* l3dss1_io_timer */
static void
l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg)
@@ -1241,13 +2307,18 @@ l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg)
*/
pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
newl3state(pc, 0);
- release_l3_process(pc);
+ dss1_release_l3_process(pc);
} else {
pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
}
}
static void
+l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg)
+{
+}
+
+static void
l3dss1_t303(struct l3_process *pc, u_char pr, void *arg)
{
if (pc->N303 > 0) {
@@ -1256,8 +2327,9 @@ l3dss1_t303(struct l3_process *pc, u_char pr, void *arg)
l3dss1_setup_req(pc, pr, arg);
} else {
L3DelTimer(&pc->timer);
+ l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
- release_l3_process(pc);
+ dss1_release_l3_process(pc);
}
}
@@ -1265,7 +2337,7 @@ static void
l3dss1_t304(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->para.cause = 0xE6;
+ pc->para.cause = 102;
l3dss1_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
@@ -1278,18 +2350,18 @@ l3dss1_t305(struct l3_process *pc, u_char pr, void *arg)
u_char *p = tmp;
int l;
struct sk_buff *skb;
- u_char cause = 0x90;
+ u_char cause = 16;
L3DelTimer(&pc->timer);
- if (pc->para.cause > 0)
- cause = pc->para.cause | 0x80;
+ if (pc->para.cause != NO_CAUSE)
+ cause = pc->para.cause;
MsgHead(p, pc->callref, MT_RELEASE);
*p++ = IE_CAUSE;
*p++ = 0x2;
*p++ = 0x80;
- *p++ = cause;
+ *p++ = cause | 0x80;
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
@@ -1304,7 +2376,7 @@ static void
l3dss1_t310(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->para.cause = 0xE6;
+ pc->para.cause = 102;
l3dss1_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
}
@@ -1313,7 +2385,7 @@ static void
l3dss1_t313(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->para.cause = 0xE6;
+ pc->para.cause = 102;
l3dss1_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
}
@@ -1332,14 +2404,14 @@ l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
- release_l3_process(pc);
+ dss1_release_l3_process(pc);
}
static void
l3dss1_t318(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->para.cause = 0x66; /* Timer expiry */
+ pc->para.cause = 102; /* Timer expiry */
pc->para.loc = 0; /* local */
pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
newl3state(pc, 19);
@@ -1351,7 +2423,7 @@ static void
l3dss1_t319(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->para.cause = 0x66; /* Timer expiry */
+ pc->para.cause = 102; /* Timer expiry */
pc->para.loc = 0; /* local */
pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
newl3state(pc, 10);
@@ -1361,69 +2433,80 @@ static void
l3dss1_restart(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_DLRL | INDICATION, pc);
- release_l3_process(pc);
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ dss1_release_l3_process(pc);
}
static void
l3dss1_status(struct l3_process *pc, u_char pr, void *arg)
{
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))) {
+ int ret;
+ u_char cause = 0, callState = 0;
+
+ if ((ret = l3dss1_get_cause(pc, skb))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "STATUS get_cause ret(%d)",ret);
+ if (ret < 0)
+ cause = 96;
+ else if (ret > 0)
+ cause = 100;
+ }
+ if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) {
p++;
if (1 == *p++) {
callState = *p;
- t += sprintf(t, "peer state %x", *p);
+ if (!ie_in_set(pc, *p, l3_valid_states))
+ cause = 100;
} else
- t += sprintf(t, "peer state len error");
+ cause = 100;
} else
- sprintf(t, "no peer state");
- l3_debug(pc->st, tmp);
- if (((cause & 0x7f) == 0x6f) && (callState == 0)) {
+ cause = 96;
+ if (!cause) { /* no error before */
+ ret = check_infoelements(pc, skb, ie_STATUS);
+ if (ERR_IE_COMPREHENSION == ret)
+ cause = 96;
+ else if (ERR_IE_UNRECOGNIZED == ret)
+ cause = 99;
+ }
+ if (cause) {
+ u_char tmp;
+
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause);
+ tmp = pc->para.cause;
+ pc->para.cause = cause;
+ l3dss1_status_send(pc, 0, NULL);
+ if (cause == 99)
+ pc->para.cause = tmp;
+ else
+ return;
+ }
+ cause = pc->para.cause;
+ if (((cause & 0x7f) == 111) && (callState == 0)) {
/* ETS 300-104 7.6.1, 8.6.1, 10.6.1...
- * if received MT_STATUS with cause == 0x6f and call
+ * if received MT_STATUS with cause == 111 and call
* state == 0, then we must set down layer 3
*/
- l3dss1_release_ind(pc, pr, arg);
- } else
- dev_kfree_skb(skb);
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ newl3state(pc, 0);
+ dss1_release_l3_process(pc);
+ }
}
static void
l3dss1_facility(struct l3_process *pc, u_char pr, void *arg)
{
- u_char *p;
struct sk_buff *skb = arg;
-
- p = skb->data;
- if ((p = findie(p, skb->len, IE_FACILITY, 0))) {
-#if HISAX_DE_AOC
- l3dss1_parse_facility(pc, p);
-#else
- p = NULL;
-#endif
+ int ret;
+
+ ret = check_infoelements(pc, skb, ie_FACILITY);
+ l3dss1_std_ie_err(pc, ret);
+ {
+ u_char *p;
+ if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
+ l3dss1_parse_facility(pc->st, pc, pc->callref, p);
}
}
@@ -1438,14 +2521,14 @@ l3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
MsgHead(p, pc->callref, MT_SUSPEND);
- *p++ = IE_CALLID;
+ *p++ = IE_CALL_ID;
l = *msg++;
if (l && (l <= 10)) { /* Max length 10 octets */
*p++ = l;
for (i = 0; i < l; i++)
*p++ = *msg++;
} else {
- l3_debug(pc->st, "SUS wrong CALLID len %d", l);
+ l3_debug(pc->st, "SUS wrong CALL_ID len %d", l);
return;
}
l = p - tmp;
@@ -1461,34 +2544,45 @@ static void
l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
+ int ret;
L3DelTimer(&pc->timer);
newl3state(pc, 0);
- dev_kfree_skb(skb);
- pc->para.cause = -1;
+ pc->para.cause = NO_CAUSE;
pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
- release_l3_process(pc);
+ /* We don't handle suspend_ack for IE errors now */
+ if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "SUSPACK check ie(%d)",ret);
+ dss1_release_l3_process(pc);
}
static void
l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
{
- u_char *p;
struct sk_buff *skb = arg;
- int cause = -1;
+ int ret;
- L3DelTimer(&pc->timer);
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
- p++;
- if (*p++ == 2)
- pc->para.loc = *p++;
- cause = *p & 0x7f;
+ if ((ret = l3dss1_get_cause(pc, skb))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret);
+ if (ret < 0)
+ pc->para.cause = 96;
+ else
+ pc->para.cause = 100;
+ l3dss1_status_send(pc, pr, NULL);
+ return;
}
- dev_kfree_skb(skb);
- pc->para.cause = cause;
+ ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3dss1_std_ie_err(pc, ret);
+ return;
+ }
+ L3DelTimer(&pc->timer);
pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
newl3state(pc, 10);
+ if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+ l3dss1_std_ie_err(pc, ret);
}
static void
@@ -1502,14 +2596,14 @@ l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg)
MsgHead(p, pc->callref, MT_RESUME);
- *p++ = IE_CALLID;
+ *p++ = IE_CALL_ID;
l = *msg++;
if (l && (l <= 10)) { /* Max length 10 octets */
*p++ = l;
for (i = 0; i < l; i++)
*p++ = *msg++;
} else {
- l3_debug(pc->st, "RES wrong CALLID len %d", l);
+ l3_debug(pc->st, "RES wrong CALL_ID len %d", l);
return;
}
l = p - tmp;
@@ -1518,48 +2612,70 @@ l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg)
memcpy(skb_put(skb, l), tmp, l);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
newl3state(pc, 17);
- L3AddTimer(&pc->timer, T319, CC_T319);
+ L3AddTimer(&pc->timer, T318, CC_T318);
}
static void
l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
{
- u_char *p;
struct sk_buff *skb = arg;
-
+ int id, ret;
+
+ if ((id = l3dss1_get_channel_id(pc, skb)) > 0) {
+ if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "resume ack with wrong chid %x", id);
+ pc->para.cause = 100;
+ l3dss1_status_send(pc, pr, NULL);
+ return;
+ }
+ pc->para.bchannel = id;
+ } else if (1 == pc->state) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "resume ack without chid (ret %d)", id);
+ pc->para.cause = 96;
+ l3dss1_status_send(pc, pr, NULL);
+ return;
+ }
+ ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3dss1_std_ie_err(pc, ret);
+ return;
+ }
L3DelTimer(&pc->timer);
- p = skb->data;
- 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, "resume ack without bchannel");
- } else if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "resume ack without bchannel");
- dev_kfree_skb(skb);
pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
newl3state(pc, 10);
+ if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+ l3dss1_std_ie_err(pc, ret);
}
static void
l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
{
- u_char *p;
struct sk_buff *skb = arg;
- int cause = -1;
+ int ret;
- L3DelTimer(&pc->timer);
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
- p++;
- if (*p++ == 2)
- pc->para.loc = *p++;
- cause = *p & 0x7f;
+ if ((ret = l3dss1_get_cause(pc, skb))) {
+ if (pc->debug & L3_DEB_WARN)
+ l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret);
+ if (ret < 0)
+ pc->para.cause = 96;
+ else
+ pc->para.cause = 100;
+ l3dss1_status_send(pc, pr, NULL);
+ return;
}
- dev_kfree_skb(skb);
- pc->para.cause = cause;
- newl3state(pc, 0);
+ ret = check_infoelements(pc, skb, ie_RESUME_REJECT);
+ if (ERR_IE_COMPREHENSION == ret) {
+ l3dss1_std_ie_err(pc, ret);
+ return;
+ }
+ L3DelTimer(&pc->timer);
pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
- release_l3_process(pc);
+ newl3state(pc, 0);
+ if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+ l3dss1_std_ie_err(pc, ret);
+ dss1_release_l3_process(pc);
}
static void
@@ -1589,7 +2705,6 @@ l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
if (pc->st->l3.debug)
l3_debug(pc->st, "Restart for channel %d", chan);
}
- dev_kfree_skb(skb);
newl3state(pc, 2);
up = pc->st->l3.proc;
while (up) {
@@ -1616,6 +2731,41 @@ l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
newl3state(pc, 0);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
}
+
+static void
+l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
+{
+ pc->para.cause = 0x29; /* Temporary failure */
+ l3dss1_disconnect_req(pc, pr, NULL);
+ pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+}
+
+static void
+l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg)
+{
+ newl3state(pc, 0);
+ pc->para.cause = 0x1b; /* Destination out of order */
+ pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+ release_l3_process(pc);
+}
+
+static void
+l3dss1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+ L3AddTimer(&pc->timer, T309, CC_T309);
+ l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL);
+}
+
+static void
+l3dss1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
+{
+ L3DelTimer(&pc->timer);
+
+ pc->para.cause = 0x1F; /* normal, unspecified */
+ l3dss1_status_send(pc, 0, NULL);
+}
+
/* *INDENT-OFF* */
static struct stateentry downstatelist[] =
{
@@ -1623,24 +2773,32 @@ static struct stateentry downstatelist[] =
CC_SETUP | REQUEST, l3dss1_setup_req},
{SBIT(0),
CC_RESUME | REQUEST, l3dss1_resume_req},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10),
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10),
CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
{SBIT(12),
CC_RELEASE | REQUEST, l3dss1_release_req},
{ALL_STATES,
- CC_DLRL | REQUEST, l3dss1_reset},
- {ALL_STATES,
CC_RESTART | REQUEST, l3dss1_restart},
{SBIT(6),
CC_IGNORE | REQUEST, l3dss1_reset},
{SBIT(6),
CC_REJECT | REQUEST, l3dss1_reject_req},
{SBIT(6),
+ CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req},
+ {SBIT(6) | SBIT(9),
CC_ALERTING | REQUEST, l3dss1_alert_req},
- {SBIT(6) | SBIT(7),
+ {SBIT(6) | SBIT(7) | SBIT(9),
CC_SETUP | RESPONSE, l3dss1_setup_rsp},
{SBIT(10),
CC_SUSPEND | REQUEST, l3dss1_suspend_req},
+ {SBIT(6),
+ CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req},
+ {SBIT(7) | SBIT(9),
+ CC_REDIR | REQUEST, l3dss1_redir_req},
+ {SBIT(6),
+ CC_REDIR | REQUEST, l3dss1_redir_req_early},
+ {SBIT(9) | SBIT(25),
+ CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
{SBIT(1),
CC_T303, l3dss1_t303},
{SBIT(2),
@@ -1659,6 +2817,8 @@ static struct stateentry downstatelist[] =
CC_T308_1, l3dss1_t308_1},
{SBIT(19),
CC_T308_2, l3dss1_t308_2},
+ {SBIT(10),
+ CC_T309, l3dss1_dl_release},
};
#define DOWNSLLEN \
@@ -1674,37 +2834,36 @@ static struct stateentry datastatelist[] =
MT_STATUS, l3dss1_release_ind},
{ALL_STATES,
MT_STATUS, l3dss1_status},
- {SBIT(0) | SBIT(6),
+ {SBIT(0),
MT_SETUP, l3dss1_setup},
+ {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) |
+ SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+ MT_SETUP, l3dss1_dummy},
{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),
+ {SBIT(2) | SBIT(3),
MT_ALERTING, l3dss1_alerting},
- {SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
- MT_ALERTING, l3dss1_status_req},
+ {SBIT(2) | SBIT(3),
+ MT_PROGRESS, l3dss1_progress},
+ {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
+ SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+ MT_INFORMATION, l3dss1_information},
+ {SBIT(10) | SBIT(11) | SBIT(15),
+ MT_NOTIFY, l3dss1_notify},
{SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
- SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
+ SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
MT_RELEASE_COMPLETE, l3dss1_release_cmpl},
- {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(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25),
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) | SBIT(15),
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25),
MT_DISCONNECT, l3dss1_disconnect},
- {SBIT(11),
- MT_DISCONNECT, l3dss1_release_req},
+ {SBIT(19),
+ MT_DISCONNECT, l3dss1_dummy},
{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(15),
@@ -1715,8 +2874,6 @@ static struct stateentry datastatelist[] =
MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack},
{SBIT(17),
MT_RESUME_REJECT, l3dss1_resume_rej},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(19),
- MT_INVALID, l3dss1_status_req},
};
#define DATASLLEN \
@@ -1734,26 +2891,56 @@ static struct stateentry globalmes_list[] =
};
#define GLOBALM_LEN \
(sizeof(globalmes_list) / sizeof(struct stateentry))
+
+static struct stateentry manstatelist[] =
+{
+ {SBIT(2),
+ DL_ESTABLISH | INDICATION, l3dss1_dl_reset},
+ {SBIT(10),
+ DL_ESTABLISH | CONFIRM, l3dss1_dl_reest_status},
+ {SBIT(10),
+ DL_RELEASE | INDICATION, l3dss1_dl_reestablish},
+ {ALL_STATES,
+ DL_RELEASE | INDICATION, l3dss1_dl_release},
+};
+
+#define MANSLLEN \
+ (sizeof(manstatelist) / sizeof(struct stateentry))
/* *INDENT-ON* */
static void
global_handler(struct PStack *st, int mt, struct sk_buff *skb)
{
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
int i;
struct l3_process *proc = st->l3.global;
+ proc->callref = skb->data[2]; /* cr flag */
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) {
l3_debug(st, "dss1 global state %d mt %x unhandled",
proc->state, mt);
}
- return;
+ MsgHead(p, proc->callref, MT_STATUS);
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = 81 |0x80; /* invalid cr */
+ *p++ = 0x14; /* CallState */
+ *p++ = 0x1;
+ *p++ = proc->state & 0x3f;
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ l3_msg(proc->st, DL_DATA | REQUEST, skb);
} else {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "dss1 global %d mt %x",
@@ -1768,6 +2955,7 @@ dss1up(struct PStack *st, int pr, void *arg)
{
int i, mt, cr, cause, callState;
char *ptr;
+ u_char *p;
struct sk_buff *skb = arg;
struct l3_process *proc;
@@ -1782,23 +2970,57 @@ dss1up(struct PStack *st, int pr, void *arg)
l3_msg(st, pr, arg);
return;
break;
+ default:
+ printk(KERN_ERR "HiSax dss1up unknown pr=%04x\n", pr);
+ return;
+ }
+ if (skb->len < 3) {
+ l3_debug(st, "dss1up frame too short(%d)", skb->len);
+ idev_kfree_skb(skb, FREE_READ);
+ return;
}
+
if (skb->data[0] != PROTO_DIS_EURO) {
if (st->l3.debug & L3_DEB_PROTERR) {
l3_debug(st, "dss1up%sunexpected discriminator %x message len %d",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
skb->data[0], skb->len);
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
return;
}
cr = getcallref(skb->data);
+ if (skb->len < ((skb->data[1] & 0x0f) + 3)) {
+ l3_debug(st, "dss1up frame too short(%d)", skb->len);
+ idev_kfree_skb(skb, FREE_READ);
+ return;
+ }
mt = skb->data[skb->data[1] + 2];
- if (!cr) { /* Global CallRef */
- global_handler(st, mt, skb);
+ if (st->l3.debug & L3_DEB_STATE)
+ l3_debug(st, "dss1up cr %d", cr);
+ if (cr == -2) { /* wrong Callref */
+ if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "dss1up wrong Callref");
+ idev_kfree_skb(skb, FREE_READ);
return;
} else if (cr == -1) { /* Dummy Callref */
- dev_kfree_skb(skb);
+ if (mt == MT_FACILITY)
+ if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
+ l3dss1_parse_facility(st, NULL,
+ (pr == (DL_DATA | INDICATION)) ? -1 : -2, p);
+ idev_kfree_skb(skb, FREE_READ);
+ return;
+ }
+ if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "dss1up dummy Callref (no facility msg or ie)");
+ idev_kfree_skb(skb, FREE_READ);
+ return;
+ } else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) ||
+ (((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) { /* Global CallRef */
+ if (st->l3.debug & L3_DEB_STATE)
+ l3_debug(st, "dss1up Global CallRef");
+ global_handler(st, mt, skb);
+ idev_kfree_skb(skb, FREE_READ);
return;
} else if (!(proc = getl3proc(st, cr))) {
/* No transaction process exist, that means no call with
@@ -1806,12 +3028,19 @@ dss1up(struct PStack *st, int pr, void *arg)
*/
if (mt == MT_SETUP) {
/* Setup creates a new transaction process */
- if (!(proc = new_l3_process(st, cr))) {
+ if (skb->data[2] & 0x80) {
+ /* Setup with wrong CREF flag */
+ if (st->l3.debug & L3_DEB_STATE)
+ l3_debug(st, "dss1up wrong CRef flag");
+ idev_kfree_skb(skb, FREE_READ);
+ return;
+ }
+ if (!(proc = dss1_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);
+ idev_kfree_skb(skb, FREE_READ);
return;
}
} else if (mt == MT_STATUS) {
@@ -1829,62 +3058,60 @@ dss1up(struct PStack *st, int pr, void *arg)
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.1
+ * if setup has not been made and a message type
+ * MT_STATUS is received with call state == 0,
+ * we must send nothing
+ */
+ if (callState != 0) {
/* ETS 300-104 part 2.4.2
* if setup has not been made and a message type
* MT_STATUS is received with call state != 0,
* we must send MT_RELEASE_COMPLETE cause 101
*/
- dev_kfree_skb(skb);
- if ((proc = new_l3_process(st, cr))) {
- proc->para.cause = 0x65; /* 101 */
+ if ((proc = dss1_new_l3_process(st, cr))) {
+ proc->para.cause = 101;
l3dss1_msg_without_setup(proc, 0, NULL);
}
- return;
}
+ idev_kfree_skb(skb, FREE_READ);
+ return;
} else if (mt == MT_RELEASE_COMPLETE) {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
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 */
+ idev_kfree_skb(skb, FREE_READ);
+ if ((proc = dss1_new_l3_process(st, cr))) {
+ proc->para.cause = 81;
l3dss1_msg_without_setup(proc, 0, 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 ;-) */
}
+ if (l3dss1_check_messagetype_validity(proc, mt, skb)) {
+ idev_kfree_skb(skb, FREE_READ);
+ return;
+ }
+ if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
+ l3dss1_deliver_display(proc, pr, p); /* Display IE included */
for (i = 0; i < DATASLLEN; i++)
if ((mt == datastatelist[i].primitive) &&
((1 << proc->state) & datastatelist[i].state))
break;
if (i == DATASLLEN) {
- dev_kfree_skb(skb);
if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "dss1up%sstate %d mt %x unhandled",
+ l3_debug(st, "dss1up%sstate %d mt %#x unhandled",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
proc->state, mt);
}
- return;
+ if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) {
+ proc->para.cause = 101;
+ l3dss1_status_send(proc, pr, skb);
+ }
} else {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "dss1up%sstate %d mt %x",
@@ -1893,6 +3120,8 @@ dss1up(struct PStack *st, int pr, void *arg)
}
datastatelist[i].rout(proc, pr, skb);
}
+ idev_kfree_skb(skb, FREE_READ);
+ return;
}
static void
@@ -1902,14 +3131,14 @@ dss1down(struct PStack *st, int pr, void *arg)
struct l3_process *proc;
struct Channel *chan;
- if (((DL_ESTABLISH | REQUEST) == pr) || ((DL_RELEASE | REQUEST) == pr)) {
+ if ((DL_ESTABLISH | REQUEST) == pr) {
l3_msg(st, pr, NULL);
return;
} else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) {
chan = arg;
cr = newcallref();
cr |= 0x80;
- if ((proc = new_l3_process(st, cr))) {
+ if ((proc = dss1_new_l3_process(st, cr))) {
proc->chan = chan;
chan->proc = proc;
proc->para.setup = chan->setup;
@@ -1922,32 +3151,75 @@ dss1down(struct PStack *st, int pr, void *arg)
printk(KERN_ERR "HiSax dss1down without proc pr=%04x\n", pr);
return;
}
+
+ if ( pr == (CC_TDSS1_IO | REQUEST)) {
+ l3dss1_io_timer(proc); /* timer expires */
+ return;
+ }
+
for (i = 0; i < DOWNSLLEN; i++)
if ((pr == downstatelist[i].primitive) &&
((1 << proc->state) & downstatelist[i].state))
break;
if (i == DOWNSLLEN) {
if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "dss1down state %d prim %d unhandled",
+ l3_debug(st, "dss1down state %d prim %#x unhandled",
proc->state, pr);
}
} else {
if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "dss1down state %d prim %d",
+ l3_debug(st, "dss1down state %d prim %#x",
proc->state, pr);
}
downstatelist[i].rout(proc, pr, arg);
}
}
+static void
+dss1man(struct PStack *st, int pr, void *arg)
+{
+ int i;
+ struct l3_process *proc = arg;
+
+ if (!proc) {
+ printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr);
+ return;
+ }
+ for (i = 0; i < MANSLLEN; i++)
+ if ((pr == manstatelist[i].primitive) &&
+ ((1 << proc->state) & manstatelist[i].state))
+ break;
+ if (i == MANSLLEN) {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "cr %d dss1man state %d prim %#x unhandled",
+ proc->callref & 0x7f, proc->state, pr);
+ }
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ l3_debug(st, "cr %d dss1man state %d prim %#x",
+ proc->callref & 0x7f, proc->state, pr);
+ }
+ manstatelist[i].rout(proc, pr, arg);
+ }
+}
+
void
setstack_dss1(struct PStack *st)
{
char tmp[64];
+ int i;
st->lli.l4l3 = dss1down;
+ st->lli.l4l3_proto = l3dss1_cmd_global;
st->l2.l2l3 = dss1up;
+ st->l3.l3ml3 = dss1man;
st->l3.N303 = 1;
+ st->prot.dss1.last_invoke_id = 0;
+ st->prot.dss1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */
+ i = 1;
+ while (i < 32)
+ st->prot.dss1.invoke_used[i++] = 0;
+
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 {
@@ -1957,6 +3229,8 @@ setstack_dss1(struct PStack *st)
st->l3.global->debug = L3_DEB_WARN;
st->l3.global->st = st;
st->l3.global->N303 = 1;
+ st->l3.global->prot.dss1.invoke_id = 0;
+
L3InitTimer(st->l3.global, &st->l3.global->timer);
}
strcpy(tmp, dss1_revision);
diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h
index 10e612482..268b5376f 100644
--- a/drivers/isdn/hisax/l3dss1.h
+++ b/drivers/isdn/hisax/l3dss1.h
@@ -1,8 +1,11 @@
-/* $Id: l3dss1.h,v 1.6 1998/03/19 13:18:50 keil Exp $
+/* $Id: l3dss1.h,v 1.7 1999/07/01 08:12:02 keil Exp $
*
* DSS1 (Euro) D-channel protocol defines
*
* $Log: l3dss1.h,v $
+ * Revision 1.7 1999/07/01 08:12:02 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.6 1998/03/19 13:18:50 keil
* Start of a CAPI like interface for supplementary Service
* first service: SUSPEND
@@ -25,10 +28,14 @@
*
*
*/
+
+#ifndef l3dss1_process
+
#define T303 4000
#define T304 30000
#define T305 30000
#define T308 4000
+#define T309 40000
#define T310 30000
#define T313 4000
#define T318 4000
@@ -38,39 +45,99 @@
* 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_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_SEGMENT 0x00
+#define IE_BEARER 0x04
+#define IE_CAUSE 0x08
+#define IE_CALL_ID 0x10
+#define IE_CALL_STATE 0x14
+#define IE_CHANNEL_ID 0x18
+#define IE_FACILITY 0x1c
+#define IE_PROGRESS 0x1e
+#define IE_NET_FAC 0x20
+#define IE_NOTIFY 0x27
+#define IE_DISPLAY 0x28
+#define IE_DATE 0x29
+#define IE_KEYPAD 0x2c
+#define IE_SIGNAL 0x34
+#define IE_INFORATE 0x40
+#define IE_E2E_TDELAY 0x42
+#define IE_TDELAY_SEL 0x43
+#define IE_PACK_BINPARA 0x44
+#define IE_PACK_WINSIZE 0x45
+#define IE_PACK_SIZE 0x46
+#define IE_CUG 0x47
+#define IE_REV_CHARGE 0x4a
+#define IE_CONNECT_PN 0x4c
+#define IE_CONNECT_SUB 0x4d
+#define IE_CALLING_PN 0x6c
+#define IE_CALLING_SUB 0x6d
+#define IE_CALLED_PN 0x70
+#define IE_CALLED_SUB 0x71
+#define IE_REDIR_NR 0x74
+#define IE_TRANS_SEL 0x78
+#define IE_RESTART_IND 0x79
+#define IE_LLC 0x7c
+#define IE_HLC 0x7d
+#define IE_USER_USER 0x7e
+#define IE_ESCAPE 0x7f
+#define IE_SHIFT 0x90
+#define IE_MORE_DATA 0xa0
+#define IE_COMPLETE 0xa1
+#define IE_CONGESTION 0xb0
+#define IE_REPEAT 0xd0
+
+#define IE_MANDATORY 0x0100
+/* mandatory not in every case */
+#define IE_MANDATORY_1 0x0200
+
+#define ERR_IE_COMPREHENSION 1
+#define ERR_IE_UNRECOGNIZED -1
+#define ERR_IE_LENGTH -2
+#define ERR_IE_SEQUENCE -3
+
+#else /* only l3dss1_process */
+
+/* l3dss1 specific data in l3 process */
+typedef struct
+ { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
+ ulong ll_id; /* remebered ll id */
+ u_char remote_operation; /* handled remote operation, 0 = not active */
+ int proc; /* rememered procedure */
+ ulong remote_result; /* result of remote operation for statcallb */
+ char uus1_data[35]; /* data send during alerting or disconnect */
+ } dss1_proc_priv;
-#define MT_INVALID 0xff
+/* l3dss1 specific data in protocol stack */
+typedef struct
+ { unsigned char last_invoke_id; /* last used value for invoking */
+ unsigned char invoke_used[32]; /* 256 bits for 256 values */
+ } dss1_stk_priv;
-#define IE_BEARER 0x04
-#define IE_CAUSE 0x08
-#define IE_CALLID 0x10
-#define IE_FACILITY 0x1c
-#define IE_CALL_STATE 0x14
-#define IE_CHANNEL_ID 0x18
-#define IE_RESTART_IND 0x79
+#endif /* only l3dss1_process */
diff --git a/drivers/isdn/hisax/lmgr.c b/drivers/isdn/hisax/lmgr.c
index d6ef0b630..6097fe547 100644
--- a/drivers/isdn/hisax/lmgr.c
+++ b/drivers/isdn/hisax/lmgr.c
@@ -1,4 +1,4 @@
-/* $Id: lmgr.c,v 1.5 1998/11/15 23:55:12 keil Exp $
+/* $Id: lmgr.c,v 1.6 1999/07/01 08:12:04 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
*
@@ -6,6 +6,9 @@
* Layermanagement module
*
* $Log: lmgr.c,v $
+ * Revision 1.6 1999/07/01 08:12:04 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.5 1998/11/15 23:55:12 keil
* changes from 2.0
*
@@ -50,7 +53,7 @@ hisax_manager(struct PStack *st, int pr, void *arg)
case (MDL_ERROR | INDICATION):
Code = (long) arg;
HiSax_putstatus(st->l1.hardware, "manager: MDL_ERROR",
- "%c %s\n", (char)Code,
+ " %c %s", (char)Code,
test_bit(FLG_LAPD, &st->l2.flag) ?
"D-channel" : "B-channel");
if (test_bit(FLG_LAPD, &st->l2.flag))
diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc
index 49888c55d..481a7dc72 100644
--- a/drivers/isdn/hisax/md5sums.asc
+++ b/drivers/isdn/hisax/md5sums.asc
@@ -2,28 +2,30 @@
# This are valid md5sums for certificated HiSax driver.
# The certification is valid only if the md5sums of all files match.
-# The certification is valid only for ELSA QuickStep cards in the moment.
+# The certification is valid only for ELSA QuickStep cards and
+# Eicon Technology Diva 2.01 PCI cards in the moment.
# Read ../../../Documentation/isdn/HiSax.cert for more informations.
#
-a273c532aec063574273ee519975cd9a isac.c
-27c5c5bfa2ceabf02e2e6d686b03abde isdnl1.c
-8c89ac659d3188ab997fb575da22b566 isdnl2.c
-d0fa912aa284b8fd19fed86b65999f6f isdnl3.c
-1bce120740b615006286ad9b2d7fcdcb tei.c
-8845f88dd17917d9b58badeff1605057 callc.c
-f3ec2a634f06074d16167aaba02b6dc1 cert.c
-71840ec8189f42b0db86fb38e5e5984c l3dss1.c
-1882de8bea921b9ccd98fbe77267aa04 l3_1tr6.c
-3bd7af3a11693d028300278744d0da09 elsa.c
+0cc164fadd4ec0e2983ec9735e209cbd isac.c
+5fe8cb5526c78c91f61b0a94a423ea5d isdnl1.c
+3b9522e8bf9e1c3e7848d729fc3dc05d isdnl2.c
+f4184a50e35e5b568608e6cb7a693319 isdnl3.c
+ef70f4269fdc2ca15100f9b776afaa0d tei.c
+65be616dd9d0e06c788d4fdd0fe5fe0a callc.c
+bf9605b36429898f7be6630034e83230 cert.c
+97c5e31c2739665b9c2976a30ce0b357 l3dss1.c
+b674eee9314a7cc413971c84003cf1d2 l3_1tr6.c
+51b2ef1efb221bb09fd08ab28bd2c565 elsa.c
+24cda374da44b57f6a1bb215424267b5 diva.c
# end of md5sums
-----BEGIN PGP SIGNATURE-----
Version: 2.6.3i
Charset: noconv
-iQCVAwUBNrl5JDpxHvX/mS9tAQHm8wP+Nk64UJ2abdDG/igXZSrwcYhX/Kp7cxt9
-ccYp+aaur+pALA0lxwY3xcLt9u36fCYuTLHAVmQoiC9Vbemj37yzM2rUpz9nkw/7
-D6gLqZs2jxVpAwVVJgp0JwDONKXaRX6Lt2EPD9PTW6vxRWEu0HqGhM5hrtd/o4rV
-mC1W7Wj13XM=
-=LdhT
+iQCVAwUBN8RgFjpxHvX/mS9tAQFzFQP/dOgnppDIm5ug1hnlWjQ/0BVurKEEJ64r
+DYDHwkcog+0gVE/EB1A7WUDqpFEnj52OZeoVinCfdVuVjP8IkrAJ8dCONsnXjBXz
+pzM+FunP1LFxuv2TVM0f642j98JxS8rObGWH8ZwY36P2QfNp47zorO2F9WvdCkuz
+sxJUtMUOlQ8=
+=8uEP
-----END PGP SIGNATURE-----
diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
index 4f1474624..fa85bbd27 100644
--- a/drivers/isdn/hisax/mic.c
+++ b/drivers/isdn/hisax/mic.c
@@ -1,4 +1,4 @@
-/* $Id: mic.c,v 1.7 1998/04/15 16:44:32 keil Exp $
+/* $Id: mic.c,v 1.8 1999/07/12 21:05:20 keil Exp $
* mic.c low level stuff for mic cards
*
@@ -8,6 +8,10 @@
*
*
* $Log: mic.c,v $
+ * Revision 1.8 1999/07/12 21:05:20 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
* Revision 1.7 1998/04/15 16:44:32 keil
* new init code
*
@@ -40,7 +44,7 @@
extern const char *CardType[];
-const char *mic_revision = "$Revision: 1.7 $";
+const char *mic_revision = "$Revision: 1.8 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -158,7 +162,7 @@ static void
mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
if (!cs) {
printk(KERN_WARNING "mic: Spurious interrupt!\n");
@@ -166,16 +170,12 @@ mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
- if (val) {
+ 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) {
+ 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)
@@ -188,16 +188,12 @@ mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
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);
- }
+ 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.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0);
+ 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);
}
void
@@ -218,9 +214,6 @@ mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
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 */
inithscxisac(cs, 3);
@@ -231,7 +224,7 @@ mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __init
setup_mic(struct IsdnCard *card)
{
int bytecnt;
@@ -273,6 +266,7 @@ setup_mic(struct IsdnCard *card)
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &mic_card_msg;
+ cs->irq_func = &mic_interrupt;
ISACVersion(cs, "mic:");
if (HscxVersion(cs, "mic:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 75696ad2c..d88442e37 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -1,4 +1,4 @@
-/* $Id: netjet.c,v 1.8 1998/11/15 23:55:14 keil Exp $
+/* $Id: netjet.c,v 1.13 1999/08/11 21:01:31 keil Exp $
* netjet.c low level stuff for Traverse Technologie NETJet ISDN cards
*
@@ -6,8 +6,25 @@
*
* Thanks to Traverse Technologie Australia for documents and informations
*
- *
* $Log: netjet.c,v $
+ * Revision 1.13 1999/08/11 21:01:31 keil
+ * new PCI codefix
+ *
+ * Revision 1.12 1999/08/10 16:02:00 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 1.11 1999/08/07 17:32:00 keil
+ * Asymetric buffers for improved ping times. Interframe spacing
+ * fix for NJ<->NJ thoughput. Matt Henderson - www.traverse.com.au
+ *
+ *
+ * Revision 1.10 1999/07/12 21:05:22 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.9 1999/07/01 08:12:05 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.8 1998/11/15 23:55:14 keil
* changes from 2.0
*
@@ -42,12 +59,23 @@
#include "hscx.h"
#include "isdnl1.h"
#include <linux/pci.h>
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
#include <linux/interrupt.h>
#include <linux/ppp_defs.h>
+#ifndef bus_to_virt
+#define bus_to_virt (u_int *)
+#endif
+
+#ifndef virt_to_bus
+#define virt_to_bus (u_int)
+#endif
+
extern const char *CardType[];
-const char *NETjet_revision = "$Revision: 1.8 $";
+const char *NETjet_revision = "$Revision: 1.13 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -83,7 +111,8 @@ const char *NETjet_revision = "$Revision: 1.8 $";
#define NETJET_IRQM0_WRITE_1 0x01
#define NETJET_IRQM0_WRITE_2 0x02
-#define NETJET_DMA_SIZE 512
+#define NETJET_DMA_TXSIZE 512
+#define NETJET_DMA_RXSIZE 128
#define HDLC_ZERO_SEARCH 0
#define HDLC_FLAG_SEARCH 1
@@ -211,7 +240,7 @@ mode_tiger(struct BCState *bcs, int mode, int bc)
switch (mode) {
case (L1_MODE_NULL):
fill_mem(bcs, bcs->hw.tiger.send,
- NETJET_DMA_SIZE, bc, 0xff);
+ NETJET_DMA_TXSIZE, bc, 0xff);
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "Tiger stat rec %d/%d send %d",
bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err,
@@ -228,7 +257,7 @@ mode_tiger(struct BCState *bcs, int mode, int bc)
break;
case (L1_MODE_HDLC):
fill_mem(bcs, bcs->hw.tiger.send,
- NETJET_DMA_SIZE, bc, 0xff);
+ NETJET_DMA_TXSIZE, bc, 0xff);
bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH;
bcs->hw.tiger.r_tot = 0;
bcs->hw.tiger.r_bitcnt = 0;
@@ -237,14 +266,14 @@ mode_tiger(struct BCState *bcs, int mode, int bc)
bcs->hw.tiger.s_tot = 0;
if (! cs->hw.njet.dmactrl) {
fill_mem(bcs, bcs->hw.tiger.send,
- NETJET_DMA_SIZE, !bc, 0xff);
+ NETJET_DMA_TXSIZE, !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;
+ bcs->hw.tiger.free = NETJET_DMA_TXSIZE;
test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
break;
}
@@ -363,6 +392,7 @@ static int make_raw_data(struct BCState *bcs) {
s_val |= 0x80;
}
bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
+ bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix
}
bcs->hw.tiger.sendcnt = s_cnt;
bcs->tx_cnt -= bcs->tx_skb->len;
@@ -376,6 +406,7 @@ static void got_frame(struct BCState *bcs, int count) {
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "TIGER: receive out of memory\n");
else {
+ SET_SKB_FREE(skb);
memcpy(skb_put(skb, count), bcs->hw.tiger.rcvbuf, count);
skb_queue_tail(&bcs->rqueue, skb);
}
@@ -393,7 +424,7 @@ 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;
+ u_int *pend = bcs->hw.tiger.rec +NETJET_DMA_RXSIZE -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;
@@ -548,7 +579,7 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
static void read_tiger(struct IsdnCardState *cs) {
u_int *p;
- int cnt = NETJET_DMA_SIZE/2;
+ int cnt = NETJET_DMA_RXSIZE/2;
if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) {
debugl1(cs,"tiger warn read double dma %x/%x",
@@ -559,7 +590,7 @@ static void read_tiger(struct IsdnCardState *cs) {
cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ);
}
if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ_1)
- p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1;
+ p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1;
else
p = cs->bcs[0].hw.tiger.rec + cnt - 1;
if (cs->bcs[0].mode == L1_MODE_HDLC)
@@ -616,12 +647,12 @@ static void fill_dma(struct BCState *bcs)
cnt = bcs->hw.tiger.s_end - p;
if (cnt < 2) {
p = bcs->hw.tiger.send + 1;
- cnt = NETJET_DMA_SIZE/2 - 2;
+ cnt = NETJET_DMA_TXSIZE/2 - 2;
} else {
p++;
p++;
- if (cnt <= (NETJET_DMA_SIZE/2))
- cnt += NETJET_DMA_SIZE/2;
+ if (cnt <= (NETJET_DMA_TXSIZE/2))
+ cnt += NETJET_DMA_TXSIZE/2;
cnt--;
cnt--;
}
@@ -674,12 +705,12 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->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))
+ if (bcs->hw.tiger.free > (NETJET_DMA_TXSIZE/2))
test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
else {
test_and_clear_bit(BC_FLG_HALF, &bcs->Flag);
@@ -719,7 +750,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
}
static void write_tiger(struct IsdnCardState *cs) {
- u_int *p, cnt = NETJET_DMA_SIZE/2;
+ u_int *p, cnt = NETJET_DMA_TXSIZE/2;
if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) {
debugl1(cs,"tiger warn write double dma %x/%x",
@@ -730,7 +761,7 @@ static void write_tiger(struct IsdnCardState *cs) {
cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE);
}
if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE_1)
- p = cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1;
+ p = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1;
else
p = cs->bcs[0].hw.tiger.send + cnt - 1;
if (cs->bcs[0].mode == L1_MODE_HDLC)
@@ -811,7 +842,7 @@ close_tigerstate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
@@ -858,45 +889,45 @@ setstack_tiger(struct PStack *st, struct BCState *bcs)
}
-void __init
+void __init
inittiger(struct IsdnCardState *cs)
{
- if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_SIZE * sizeof(unsigned int),
+ if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * 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[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE/2 - 1;
+ cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 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));
+ memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_TXSIZE * sizeof(unsigned int));
debugl1(cs, "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));
+ (u_int)(cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1));
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),
+ if (!(cs->bcs[0].hw.tiger.rec = kmalloc(NETJET_DMA_RXSIZE * sizeof(unsigned int),
GFP_KERNEL | GFP_DMA))) {
printk(KERN_WARNING
"HiSax: No memory for tiger.rec\n");
return;
}
debugl1(cs, "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));
+ (u_int)(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1));
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));
+ memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_RXSIZE * 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),
+ outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE/2 - 1),
cs->hw.njet.base + NETJET_DMA_WRITE_IRQ);
- outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1),
+ outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1),
cs->hw.njet.base + NETJET_DMA_WRITE_END);
debugl1(cs, "tiger: dmacfg %x/%x pulse=%d",
inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
@@ -1030,9 +1061,6 @@ NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg)
case CARD_RELEASE:
release_io_netjet(cs);
return(0);
- case CARD_SETIRQ:
- return(request_irq(cs->irq, &netjet_interrupt,
- I4L_IRQ_FLAG | SA_SHIRQ, "HiSax", cs));
case CARD_INIT:
inittiger(cs);
clear_pending_isac_ints(cs);
@@ -1046,23 +1074,31 @@ NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-
-
+#ifdef COMPAT_HAS_NEW_PCI
static struct pci_dev *dev_netjet __initdata = NULL;
+#else
+static int pci_index __initdata = 0;
+#endif
-int __init
+int __init
setup_netjet(struct IsdnCard *card)
{
int bytecnt;
struct IsdnCardState *cs = card->cs;
char tmp[64];
-
+#if CONFIG_PCI
+#ifndef COMPAT_HAS_NEW_PCI
+ u_char pci_bus, pci_device_fn, pci_irq;
+ u_int pci_ioaddr, found;
+#endif
+#endif
strcpy(tmp, NETjet_revision);
printk(KERN_INFO "HiSax: Traverse Tech. NETjet driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_NETJET)
return(0);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
#if CONFIG_PCI
+#ifdef COMPAT_HAS_NEW_PCI
if (!pci_present()) {
printk(KERN_ERR "Netjet: no PCI bus present\n");
return(0);
@@ -1071,22 +1107,57 @@ setup_netjet(struct IsdnCard *card)
PCI_NETJET_ID, dev_netjet))) {
cs->irq = dev_netjet->irq;
if (!cs->irq) {
+ printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.njet.base = get_pcibase(dev_netjet, 0)
+ & PCI_BASE_ADDRESS_IO_MASK;
+ if (!cs->hw.njet.base) {
+ printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ } else {
+ printk(KERN_WARNING "NETjet: No PCI card found\n");
+ return(0);
+ }
+#else
+ 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
+ continue;
+ /* 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);
+ }
+ pci_index++;
+ if (!pci_irq) {
printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n");
return(0);
}
- cs->hw.njet.base = dev_netjet->base_address[0] &
- PCI_BASE_ADDRESS_IO_MASK;
- if (!cs->hw.njet.base) {
+ if (!pci_ioaddr) {
printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n");
return(0);
}
- cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
- cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+ cs->hw.njet.base = pci_ioaddr & PCI_BASE_ADDRESS_IO_MASK;
+ cs->irq = pci_irq;
+#endif /* COMPAT_HAS_NEW_PCI */
+ cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+ cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
bytecnt = 256;
- } else {
- printk(KERN_WARNING "NETjet: No PCI card found\n");
- return(0);
- }
#else
printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n");
printk(KERN_WARNING "NETjet: unable to config NETJET PCI\n");
@@ -1114,6 +1185,8 @@ setup_netjet(struct IsdnCard *card)
cs->BC_Write_Reg = &dummywr;
cs->BC_Send_Data = &fill_dma;
cs->cardmsg = &NETjet_card_msg;
+ cs->irq_func = &netjet_interrupt;
+ cs->irq_flags |= SA_SHIRQ;
ISACVersion(cs, "NETjet:");
return (1);
}
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index 4a4f0d7c3..7574a8e8f 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -1,4 +1,4 @@
-/* $Id: niccy.c,v 1.4 1998/04/16 19:16:48 keil Exp $
+/* $Id: niccy.c,v 1.8 1999/08/11 21:01:33 keil Exp $
* niccy.c low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
* compatible (SAGEM cybermodem)
@@ -8,6 +8,19 @@
* Thanks to Dr. Neuhaus and SAGEM for informations
*
* $Log: niccy.c,v $
+ * Revision 1.8 1999/08/11 21:01:33 keil
+ * new PCI codefix
+ *
+ * Revision 1.7 1999/08/10 16:02:04 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 1.6 1999/07/12 21:05:23 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.5 1999/07/01 08:12:07 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.4 1998/04/16 19:16:48 keil
* need config.h
*
@@ -27,9 +40,12 @@
#include "hscx.h"
#include "isdnl1.h"
#include <linux/pci.h>
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
extern const char *CardType[];
-const char *niccy_revision = "$Revision: 1.4 $";
+const char *niccy_revision = "$Revision: 1.8 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -154,7 +170,7 @@ static void
niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
if (!cs) {
printk(KERN_WARNING "Niccy: Spurious interrupt!\n");
@@ -169,16 +185,12 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
- if (val) {
+ 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) {
+ 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)
@@ -191,16 +203,12 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
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);
- }
+ 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.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
+ 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);
}
void
@@ -235,8 +243,6 @@ niccy_reset(struct IsdnCardState *cs)
static int
niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- int imode;
-
switch (mt) {
case CARD_RESET:
niccy_reset(cs);
@@ -244,14 +250,6 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
case CARD_RELEASE:
release_io_niccy(cs);
return(0);
- case CARD_SETIRQ:
- if (cs->subtyp == NICCY_PCI)
- imode = I4L_IRQ_FLAG | SA_SHIRQ;
- else
- imode = I4L_IRQ_FLAG;
- return(request_irq(cs->irq, &niccy_interrupt,
- imode, "HiSax", cs));
- break;
case CARD_INIT:
niccy_reset(cs);
return(0);
@@ -261,9 +259,13 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
+#ifdef COMPAT_HAS_NEW_PCI
static struct pci_dev *niccy_dev __initdata = NULL;
+#else
+static int pci_index __initdata = 0;
+#endif
-int __init
+int __init
setup_niccy(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
@@ -304,40 +306,85 @@ setup_niccy(struct IsdnCard *card)
} else {
#if CONFIG_PCI
u_int pci_ioaddr;
-
+#ifdef COMPAT_HAS_NEW_PCI
if (!pci_present()) {
printk(KERN_ERR "Niccy: no PCI bus present\n");
return(0);
}
-
cs->subtyp = 0;
if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS,
PCI_NICCY_ID, niccy_dev))) {
/* get IRQ */
if (!niccy_dev->irq) {
printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->irq = niccy_dev->irq;
+ if (!get_pcibase(niccy_dev, 0)) {
+ printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
+ return(0);
+ }
+ cs->hw.niccy.cfg_reg = get_pcibase(niccy_dev, 0) & PCI_BASE_ADDRESS_IO_MASK;
+ if (!get_pcibase(niccy_dev, 1)) {
+ printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ pci_ioaddr = get_pcibase(niccy_dev, 1) & PCI_BASE_ADDRESS_IO_MASK;
+ cs->subtyp = NICCY_PCI;
+ } else {
+ printk(KERN_WARNING "Niccy: No PCI card found\n");
return(0);
}
- cs->irq = niccy_dev->irq;
- if (!niccy_dev->base_address[0]) {
+#else
+ u_char pci_bus, pci_device_fn, pci_irq;
+
+ 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
+ continue;
+ /* get IRQ */
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq);
+
+ /* get IO pci AMCC address */
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ if (!pci_ioaddr) {
printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
+ return(0);
+ }
+ cs->hw.niccy.cfg_reg = pci_ioaddr & ~3 ;
+ /* get IO address */
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, &pci_ioaddr);
+ if (cs->subtyp)
+ break;
+ }
+ if (!cs->subtyp) {
+ printk(KERN_WARNING "Niccy: No PCI card found\n");
return(0);
}
- cs->hw.niccy.cfg_reg = niccy_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
- if (!niccy_dev->base_address[1]) {
+ pci_index++;
+ 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 = niccy_dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
+ pci_ioaddr &= ~3; /* remove io/mem flag */
+ cs->irq = pci_irq;
+#endif /* COMPAT_HAS_NEW_PCI */
+ cs->irq_flags |= SA_SHIRQ;
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->subtyp = NICCY_PCI;
- } else {
- printk(KERN_WARNING "Niccy: No PCI card found\n");
- return(0);
- }
if (check_region((cs->hw.niccy.isac), 4)) {
printk(KERN_WARNING
"HiSax: %s data port %x-%x already in use\n",
@@ -376,6 +423,7 @@ setup_niccy(struct IsdnCard *card)
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &niccy_card_msg;
+ cs->irq_func = &niccy_interrupt;
ISACVersion(cs, "Niccy:");
if (HscxVersion(cs, "Niccy:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c
index 479880bb3..d8dfb2ee3 100644
--- a/drivers/isdn/hisax/s0box.c
+++ b/drivers/isdn/hisax/s0box.c
@@ -1,4 +1,4 @@
-/* $Id: s0box.c,v 2.1 1998/04/15 16:38:24 keil Exp $
+/* $Id: s0box.c,v 2.2 1999/07/12 21:05:25 keil Exp $
* s0box.c low level stuff for Creatix S0BOX
*
@@ -13,7 +13,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *s0box_revision = "$Revision: 2.1 $";
+const char *s0box_revision = "$Revision: 2.2 $";
static inline void
writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
@@ -148,9 +148,9 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
static void
s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
-#define MAXCOUNT 20
+#define MAXCOUNT 5
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
int count = 0;
if (!cs) {
@@ -159,16 +159,12 @@ s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
Start_HSCX:
- if (val) {
+ if (val)
hscx_int_main(cs, val);
- stat |= 1;
- }
val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
Start_ISAC:
- if (val) {
+ if (val)
isac_interrupt(cs, val);
- stat |= 2;
- }
count++;
val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
if (val && count < MAXCOUNT) {
@@ -184,16 +180,12 @@ s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
if (count >= MAXCOUNT)
printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count);
- if (stat & 1) {
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
- }
- if (stat & 2) {
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0);
- }
+ writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
+ writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
+ writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0);
+ writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
+ writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
}
void
@@ -211,9 +203,6 @@ S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
case CARD_RELEASE:
release_io_s0box(cs);
break;
- case CARD_SETIRQ:
- return(request_irq(cs->irq, &s0box_interrupt,
- I4L_IRQ_FLAG, "HiSax", cs));
case CARD_INIT:
inithscxisac(cs, 3);
break;
@@ -223,8 +212,8 @@ S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-__initfunc(int
-setup_s0box(struct IsdnCard *card))
+int __init
+setup_s0box(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
@@ -266,6 +255,7 @@ setup_s0box(struct IsdnCard *card))
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &S0Box_card_msg;
+ cs->irq_func = &s0box_interrupt;
ISACVersion(cs, "S0Box:");
if (HscxVersion(cs, "S0Box:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
new file mode 100644
index 000000000..0d524faa8
--- /dev/null
+++ b/drivers/isdn/hisax/saphir.c
@@ -0,0 +1,326 @@
+/* $Id: saphir.c,v 1.3 1999/07/12 21:05:26 keil Exp $
+
+ * saphir.c low level stuff for HST Saphir 1
+ *
+ * Author Karsten Keil (keil@isdn4linux.de)
+ *
+ * Thanks to HST High Soft Tech GmbH
+ *
+ *
+ * $Log: saphir.c,v $
+ * Revision 1.3 1999/07/12 21:05:26 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.2 1999/07/01 08:07:55 keil
+ * Initial version
+ *
+ *
+ */
+
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+static char *saphir_rev = "$Revision: 1.3 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define ISAC_DATA 0
+#define HSCX_DATA 1
+#define ADDRESS_REG 2
+#define IRQ_REG 3
+#define SPARE_REG 4
+#define RESET_REG 5
+
+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.saphir.ale, cs->hw.saphir.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+ writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+ writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+ return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
+ offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+ writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
+ offset + (hscx ? 0x40 : 0), value);
+}
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \
+ cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \
+ cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \
+ cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \
+ cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *cs = dev_id;
+ u_char val;
+
+ if (!cs) {
+ printk(KERN_WARNING "saphir: Spurious interrupt!\n");
+ return;
+ }
+ val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
+ Start_HSCX:
+ if (val)
+ hscx_int_main(cs, val);
+ val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
+ Start_ISAC:
+ if (val)
+ isac_interrupt(cs, val);
+ val = readreg(cs->hw.saphir.ale, cs->hw.saphir.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.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
+ if (val) {
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ /* Watchdog */
+ if (cs->hw.saphir.timer.function) {
+ del_timer(&cs->hw.saphir.timer);
+ cs->hw.saphir.timer.expires = jiffies + 1*HZ;
+ add_timer(&cs->hw.saphir.timer);
+ } else
+ printk(KERN_WARNING "saphir: Spurious timer!\n");
+ writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF);
+ writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0);
+ writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0);
+ writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0);
+}
+
+static void
+SaphirWatchDog(struct IsdnCardState *cs)
+{
+ /* 5 sec WatchDog, so read at least every 4 sec */
+ cs->readisac(cs, ISAC_RBCH);
+ del_timer(&cs->hw.saphir.timer);
+ cs->hw.saphir.timer.expires = jiffies + 1*HZ;
+ add_timer(&cs->hw.saphir.timer);
+}
+
+void
+release_io_saphir(struct IsdnCardState *cs)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
+ del_timer(&cs->hw.saphir.timer);
+ cs->hw.saphir.timer.function = NULL;
+ restore_flags(flags);
+ if (cs->hw.saphir.cfg_reg)
+ release_region(cs->hw.saphir.cfg_reg, 6);
+}
+
+static int
+saphir_reset(struct IsdnCardState *cs)
+{
+ long flags;
+ u_char irq_val;
+
+ switch(cs->irq) {
+ case 5: irq_val = 0;
+ break;
+ case 3: irq_val = 1;
+ break;
+ case 11:
+ irq_val = 2;
+ break;
+ case 12:
+ irq_val = 3;
+ break;
+ case 15:
+ irq_val = 4;
+ break;
+ default:
+ printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n",
+ cs->irq);
+ return (1);
+ }
+ byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
+ save_flags(flags);
+ sti();
+ byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((30*HZ)/1000); /* Timeout 30ms */
+ byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((30*HZ)/1000); /* Timeout 30ms */
+ restore_flags(flags);
+ byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
+ byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02);
+ return (0);
+}
+
+static int
+saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ switch (mt) {
+ case CARD_RESET:
+ saphir_reset(cs);
+ return(0);
+ case CARD_RELEASE:
+ release_io_saphir(cs);
+ return(0);
+ case CARD_INIT:
+ inithscxisac(cs, 3);
+ return(0);
+ case CARD_TEST:
+ return(0);
+ }
+ return(0);
+}
+
+
+int __init
+setup_saphir(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, saphir_rev);
+ printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_HSTSAPHIR)
+ return (0);
+
+ /* IO-Ports */
+ cs->hw.saphir.cfg_reg = card->para[1];
+ cs->hw.saphir.isac = card->para[1] + ISAC_DATA;
+ cs->hw.saphir.hscx = card->para[1] + HSCX_DATA;
+ cs->hw.saphir.ale = card->para[1] + ADDRESS_REG;
+ cs->irq = card->para[0];
+ if (check_region((cs->hw.saphir.cfg_reg), 6)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.saphir.cfg_reg,
+ cs->hw.saphir.cfg_reg + 5);
+ return (0);
+ } else
+ request_region(cs->hw.saphir.cfg_reg,6, "saphir");
+
+ printk(KERN_INFO
+ "HiSax: %s config irq:%d io:0x%X\n",
+ CardType[cs->typ], cs->irq,
+ cs->hw.saphir.cfg_reg);
+
+ cs->hw.saphir.timer.function = (void *) SaphirWatchDog;
+ cs->hw.saphir.timer.data = (long) cs;
+ init_timer(&cs->hw.saphir.timer);
+ cs->hw.saphir.timer.expires = jiffies + 4*HZ;
+ add_timer(&cs->hw.saphir.timer);
+ if (saphir_reset(cs)) {
+ release_io_saphir(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 = &saphir_card_msg;
+ cs->irq_func = &saphir_interrupt;
+ ISACVersion(cs, "saphir:");
+ if (HscxVersion(cs, "saphir:")) {
+ printk(KERN_WARNING
+ "saphir: wrong HSCX versions check IO address\n");
+ release_io_saphir(cs);
+ return (0);
+ }
+ return (1);
+}
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index 105c9a380..2640555b2 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -1,4 +1,4 @@
-/* $Id: sedlbauer.c,v 1.9 1998/11/15 23:55:20 keil Exp $
+/* $Id: sedlbauer.c,v 1.16 1999/08/29 18:23:01 niemann Exp $
* sedlbauer.c low level stuff for Sedlbauer cards
* includes support for the Sedlbauer speed star (speed star II),
@@ -17,6 +17,30 @@
* Edgar Toernig
*
* $Log: sedlbauer.c,v $
+ * Revision 1.16 1999/08/29 18:23:01 niemann
+ * Fixed typo in errormsg
+ *
+ * Revision 1.15 1999/08/25 17:00:00 keil
+ * Make ISAR V32bis modem running
+ * Make LL->HL interface open for additional commands
+ *
+ * Revision 1.14 1999/08/11 20:59:22 keil
+ * new PCI codefix
+ * fix IRQ problem while unload
+ *
+ * Revision 1.13 1999/08/10 16:02:08 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 1.12 1999/08/05 20:43:22 keil
+ * ISAR analog modem support
+ *
+ * Revision 1.11 1999/07/12 21:05:27 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.10 1999/07/01 08:12:09 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.9 1998/11/15 23:55:20 keil
* changes from 2.0
*
@@ -76,10 +100,13 @@
#include "isar.h"
#include "isdnl1.h"
#include <linux/pci.h>
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
extern const char *CardType[];
-const char *Sedlbauer_revision = "$Revision: 1.9 $";
+const char *Sedlbauer_revision = "$Revision: 1.16 $";
const char *Sedlbauer_Types[] =
{"None", "speed card/win", "speed star", "speed fax+",
@@ -291,7 +318,7 @@ static void
sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
if (!cs) {
printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n");
@@ -307,16 +334,12 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
- if (val) {
+ 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) {
+ 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)
@@ -329,23 +352,19 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
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);
- }
+ 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.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
+ 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);
}
static void
sedlbauer_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char ista, val, icnt = 20;
+ u_char ista, val, icnt = 5;
if (!cs) {
printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n");
@@ -392,7 +411,7 @@ sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char val;
- int cnt = 20;
+ int cnt = 5;
if (!cs) {
printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n");
@@ -431,9 +450,11 @@ sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs)
void
release_io_sedlbauer(struct IsdnCardState *cs)
{
- int bytecnt = (cs->subtyp == SEDL_SPEED_FAX) ? 16 : 8;
+ int bytecnt = 8;
- if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
+ if (cs->subtyp == SEDL_SPEED_FAX) {
+ bytecnt = 16;
+ } else if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
bytecnt = 256;
}
if (cs->hw.sedl.cfg_reg)
@@ -454,10 +475,10 @@ reset_sedlbauer(struct IsdnCardState *cs)
save_flags(flags);
sti();
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout((10*HZ)/1000);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout((10*HZ)/1000);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0);
@@ -469,10 +490,10 @@ reset_sedlbauer(struct IsdnCardState *cs)
save_flags(flags);
sti();
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout((10*HZ)/1000);
byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
}
@@ -486,19 +507,19 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
reset_sedlbauer(cs);
return(0);
case CARD_RELEASE:
- release_io_sedlbauer(cs);
- return(0);
- case CARD_SETIRQ:
if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
- return(request_irq(cs->irq, &sedlbauer_interrupt_isar,
- I4L_IRQ_FLAG, "HiSax", cs));
- } else if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
- return(request_irq(cs->irq, &sedlbauer_interrupt_ipac,
- I4L_IRQ_FLAG, "HiSax", cs));
- } else {
- return(request_irq(cs->irq, &sedlbauer_interrupt,
- I4L_IRQ_FLAG, "HiSax", cs));
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
+ ISAR_IRQBIT, 0);
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.isac,
+ ISAC_MASK, 0xFF);
+ reset_sedlbauer(cs);
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
+ ISAR_IRQBIT, 0);
+ writereg(cs->hw.sedl.adr, cs->hw.sedl.isac,
+ ISAC_MASK, 0xFF);
}
+ release_io_sedlbauer(cs);
+ return(0);
case CARD_INIT:
if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
clear_pending_isac_ints(cs);
@@ -516,24 +537,19 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
case CARD_TEST:
return(0);
- case CARD_LOAD_FIRM:
- if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
- if (isar_load_firmware(cs, arg))
- return(1);
- else
- ll_run(cs);
- }
- return(0);
}
return(0);
}
-
#ifdef SEDLBAUER_PCI
+#ifdef COMPAT_HAS_NEW_PCI
+static struct pci_dev *dev_sedl __initdata = NULL;
+#else
static int pci_index __initdata = 0;
#endif
+#endif
-int __init
+int __init
setup_sedlbauer(struct IsdnCard *card)
{
int bytecnt, ver, val;
@@ -569,6 +585,25 @@ setup_sedlbauer(struct IsdnCard *card)
/* Probe for Sedlbauer speed pci */
#if SEDLBAUER_PCI
#if CONFIG_PCI
+#ifdef COMPAT_HAS_NEW_PCI
+ if (!pci_present()) {
+ printk(KERN_ERR "Sedlbauer: no PCI bus present\n");
+ return(0);
+ }
+ if ((dev_sedl = pci_find_device(PCI_VENDOR_SEDLBAUER,
+ PCI_SPEEDPCI_ID, dev_sedl))) {
+ cs->irq = dev_sedl->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.sedl.cfg_reg = get_pcibase(dev_sedl, 0) &
+ PCI_BASE_ADDRESS_IO_MASK;
+ } else {
+ printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+ return(0);
+ }
+#else
for (; pci_index < 255; pci_index++) {
unsigned char pci_bus, pci_device_fn;
unsigned int ioaddr;
@@ -589,14 +624,6 @@ setup_sedlbauer(struct IsdnCard *card)
printk(KERN_WARNING "Sedlbauer: No IO-Adr for PCI card found\n");
return(0);
}
- cs->hw.sedl.bus = SEDL_BUS_PCI;
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = SEDL_SPEED_PCI;
- bytecnt = 256;
- byteout(cs->hw.sedl.cfg_reg, 0xff);
- byteout(cs->hw.sedl.cfg_reg, 0x00);
- byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
- byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
break;
}
if (pci_index == 255) {
@@ -604,6 +631,16 @@ setup_sedlbauer(struct IsdnCard *card)
return(0);
}
pci_index++;
+#endif /* COMPAT_HAS_NEW_PCI */
+ cs->irq_flags |= SA_SHIRQ;
+ cs->hw.sedl.bus = SEDL_BUS_PCI;
+ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+ cs->subtyp = SEDL_SPEED_PCI;
+ bytecnt = 256;
+ byteout(cs->hw.sedl.cfg_reg, 0xff);
+ byteout(cs->hw.sedl.cfg_reg, 0x00);
+ byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+ byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
#else
printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
return (0);
@@ -683,6 +720,7 @@ setup_sedlbauer(struct IsdnCard *card)
cs->writeisac = &WriteISAC_IPAC;
cs->readisacfifo = &ReadISACfifo_IPAC;
cs->writeisacfifo = &WriteISACfifo_IPAC;
+ cs->irq_func = &sedlbauer_interrupt_ipac;
val = readreg(cs->hw.sedl.adr,cs->hw.sedl.isac, IPAC_ID);
printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val);
@@ -702,7 +740,8 @@ setup_sedlbauer(struct IsdnCard *card)
cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar;
cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar;
test_and_set_bit(HW_ISAR, &cs->HW_Flags);
-
+ cs->irq_func = &sedlbauer_interrupt_isar;
+ cs->auxcmd = &isar_auxcmd;
ISACVersion(cs, "Sedlbauer:");
cs->BC_Read_Reg = &ReadISAR;
@@ -729,6 +768,7 @@ setup_sedlbauer(struct IsdnCard *card)
cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON;
cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF;
}
+ cs->irq_func = &sedlbauer_interrupt;
ISACVersion(cs, "Sedlbauer:");
if (HscxVersion(cs, "Sedlbauer:")) {
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
index ec2240b19..29fae02f7 100644
--- a/drivers/isdn/hisax/sportster.c
+++ b/drivers/isdn/hisax/sportster.c
@@ -1,4 +1,4 @@
-/* $Id: sportster.c,v 1.7 1998/11/15 23:55:22 keil Exp $
+/* $Id: sportster.c,v 1.9 1999/07/12 21:05:29 keil Exp $
* sportster.c low level stuff for USR Sportster internal TA
*
@@ -7,6 +7,13 @@
* Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
*
* $Log: sportster.c,v $
+ * Revision 1.9 1999/07/12 21:05:29 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.8 1999/07/01 08:12:10 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.7 1998/11/15 23:55:22 keil
* changes from 2.0
*
@@ -36,7 +43,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *sportster_revision = "$Revision: 1.7 $";
+const char *sportster_revision = "$Revision: 1.9 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -171,11 +178,11 @@ reset_sportster(struct IsdnCardState *cs)
save_flags(flags);
sti();
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout((10*HZ)/1000);
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;
- schedule_timeout(1);
+ schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
@@ -189,9 +196,6 @@ Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
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:
inithscxisac(cs, 1);
cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
@@ -204,7 +208,7 @@ Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __init
get_io_range(struct IsdnCardState *cs)
{
int i, j, adr;
@@ -230,7 +234,7 @@ get_io_range(struct IsdnCardState *cs)
}
}
-int __init
+int __init
setup_sportster(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
@@ -282,6 +286,7 @@ setup_sportster(struct IsdnCard *card)
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Sportster_card_msg;
+ cs->irq_func = &sportster_interrupt;
ISACVersion(cs, "Sportster:");
if (HscxVersion(cs, "Sportster:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
index c9d94fe4d..f21284bec 100644
--- a/drivers/isdn/hisax/tei.c
+++ b/drivers/isdn/hisax/tei.c
@@ -1,4 +1,4 @@
-/* $Id: tei.c,v 2.11 1998/11/15 23:55:24 keil Exp $
+/* $Id: tei.c,v 2.13 1999/07/21 14:46:28 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -11,6 +11,12 @@
* Fritz Elfert
*
* $Log: tei.c,v $
+ * Revision 2.13 1999/07/21 14:46:28 keil
+ * changes from EICON certification
+ *
+ * Revision 2.12 1999/07/01 08:12:11 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.11 1998/11/15 23:55:24 keil
* changes from 2.0
*
@@ -72,7 +78,7 @@
#include "isdnl2.h"
#include <linux/random.h>
-const char *tei_revision = "$Revision: 2.11 $";
+const char *tei_revision = "$Revision: 2.13 $";
#define ID_REQUEST 1
#define ID_ASSIGNED 2
@@ -163,6 +169,7 @@ put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei)
printk(KERN_WARNING "HiSax: No skb for TEI manager\n");
return;
}
+ SET_SKB_FREE(skb);
bp = skb_put(skb, 3);
bp[0] = (TEI_SAPI << 2);
bp[1] = (GROUP_TEI << 1) | 0x1;
@@ -226,6 +233,25 @@ tei_id_assign(struct FsmInst *fi, int event, void *arg)
}
static void
+tei_id_test_dup(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *ost, *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int tei, ri;
+
+ ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
+ tei = skb->data[4] >> 1;
+ if (st->ma.debug)
+ st->ma.tei_m.printdebug(&st->ma.tei_m,
+ "foreign identity assign ri %d tei %d", ri, tei);
+ if ((ost = findtei(st, tei))) { /* same tei is in use */
+ st->ma.tei_m.printdebug(&st->ma.tei_m,
+ "possible duplicate assignment tei %d", tei);
+ FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL);
+ }
+}
+
+static void
tei_id_denied(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
@@ -345,7 +371,7 @@ tei_l1l2(struct PStack *st, int pr, void *arg)
int mt;
if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
return;
}
@@ -353,8 +379,8 @@ tei_l1l2(struct PStack *st, int pr, void *arg)
if (skb->len < 3) {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"short mgr frame %ld/3", skb->len);
- } else if (((skb->data[0] >> 2) != TEI_SAPI) ||
- ((skb->data[1] >> 1) != GROUP_TEI)) {
+ } else if ((skb->data[0] != ((TEI_SAPI << 2) | 2)) ||
+ (skb->data[1] != ((GROUP_TEI << 1) | 1))) {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"wrong mgr sapi/tei %x/%x",
skb->data[0], skb->data[1]);
@@ -391,7 +417,7 @@ tei_l1l2(struct PStack *st, int pr, void *arg)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"tei handler wrong pr %x\n", pr);
}
- dev_kfree_skb(skb);
+ idev_kfree_skb(skb, FREE_READ);
}
static void
@@ -468,6 +494,7 @@ release_tei(struct IsdnCardState *cs)
static struct FsmNode TeiFnList[] HISAX_INITDATA =
{
{ST_TEI_NOP, EV_IDREQ, tei_id_request},
+ {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
{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},
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
index b37aded89..430ea2768 100644
--- a/drivers/isdn/hisax/teleint.c
+++ b/drivers/isdn/hisax/teleint.c
@@ -1,4 +1,4 @@
-/* $Id: teleint.c,v 1.7 1998/11/15 23:55:26 keil Exp $
+/* $Id: teleint.c,v 1.9 1999/07/12 21:05:30 keil Exp $
* teleint.c low level stuff for TeleInt isdn cards
*
@@ -6,6 +6,13 @@
*
*
* $Log: teleint.c,v $
+ * Revision 1.9 1999/07/12 21:05:30 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 1.8 1999/07/01 08:12:12 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 1.7 1998/11/15 23:55:26 keil
* changes from 2.0
*
@@ -38,7 +45,7 @@
extern const char *CardType[];
-const char *TeleInt_revision = "$Revision: 1.7 $";
+const char *TeleInt_revision = "$Revision: 1.9 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -191,7 +198,7 @@ static void
TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
if (!cs) {
printk(KERN_WARNING "TeleInt: Spurious interrupt!\n");
@@ -199,20 +206,16 @@ TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
Start_ISAC:
- if (val) {
+ 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);
- }
+ 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
@@ -252,11 +255,11 @@ reset_TeleInt(struct IsdnCardState *cs)
save_flags(flags);
sti();
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(3);
+ schedule_timeout((30*HZ)/1000);
cs->hw.hfc.cirm &= ~HFC_RESET;
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
@@ -270,9 +273,6 @@ TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
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);
@@ -289,7 +289,7 @@ TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __init
setup_TeleInt(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
@@ -365,6 +365,7 @@ setup_TeleInt(struct IsdnCard *card)
cs->BC_Read_Reg = &ReadHFC;
cs->BC_Write_Reg = &WriteHFC;
cs->cardmsg = &TeleInt_card_msg;
+ cs->irq_func = &TeleInt_interrupt;
ISACVersion(cs, "TeleInt:");
return (1);
}
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
index c562de877..4046c4357 100644
--- a/drivers/isdn/hisax/teles0.c
+++ b/drivers/isdn/hisax/teles0.c
@@ -1,4 +1,4 @@
-/* $Id: teles0.c,v 2.8 1998/04/15 16:44:28 keil Exp $
+/* $Id: teles0.c,v 2.9 1999/07/12 21:05:31 keil Exp $
* teles0.c low level stuff for Teles Memory IO isdn cards
* based on the teles driver from Jan den Ouden
@@ -10,6 +10,10 @@
* Beat Doebeli
*
* $Log: teles0.c,v $
+ * Revision 2.9 1999/07/12 21:05:31 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
* Revision 2.8 1998/04/15 16:44:28 keil
* new init code
*
@@ -54,7 +58,7 @@
extern const char *CardType[];
-const char *teles0_revision = "$Revision: 2.8 $";
+const char *teles0_revision = "$Revision: 2.9 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -177,7 +181,7 @@ static void
teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
int count = 0;
if (!cs) {
@@ -186,39 +190,31 @@ teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
Start_HSCX:
- if (val) {
+ if (val)
hscx_int_main(cs, val);
- stat |= 1;
- }
val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
Start_ISAC:
- if (val) {
+ if (val)
isac_interrupt(cs, val);
- stat |= 2;
- }
count++;
val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
- if (val && count < 20) {
+ if (val && count < 5) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
- if (val && count < 20) {
+ if (val && count < 5) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
- if (stat & 1) {
- 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(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
- writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
- }
+ writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
+ writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
+ writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
+ writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
+ writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
+ writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
}
void
@@ -290,9 +286,6 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
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:
inithscxisac(cs, 3);
return(0);
@@ -302,7 +295,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __init
setup_teles0(struct IsdnCard *card)
{
u_char val;
@@ -382,6 +375,7 @@ setup_teles0(struct IsdnCard *card)
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Teles_card_msg;
+ cs->irq_func = &teles0_interrupt;
ISACVersion(cs, "Teles0:");
if (HscxVersion(cs, "Teles0:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
index addc0dbf1..3210a6af6 100644
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -1,4 +1,4 @@
-/* $Id: teles3.c,v 2.10 1999/02/15 14:37:15 cpetig Exp $
+/* $Id: teles3.c,v 2.13 1999/08/30 12:01:28 keil Exp $
* teles3.c low level stuff for Teles 16.3 & PNP isdn cards
*
@@ -11,6 +11,16 @@
* Beat Doebeli
*
* $Log: teles3.c,v $
+ * Revision 2.13 1999/08/30 12:01:28 keil
+ * HW version v1.3 support
+ *
+ * Revision 2.12 1999/07/12 21:05:32 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 2.11 1999/07/01 08:12:14 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.10 1999/02/15 14:37:15 cpetig
* oops, missed something in last commit
*
@@ -78,7 +88,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *teles3_revision = "$Revision: 2.10 $";
+const char *teles3_revision = "$Revision: 2.13 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -160,9 +170,9 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
static void
teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
-#define MAXCOUNT 20
+#define MAXCOUNT 5
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
int count = 0;
if (!cs) {
@@ -171,16 +181,12 @@ teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
Start_HSCX:
- if (val) {
+ if (val)
hscx_int_main(cs, val);
- stat |= 1;
- }
val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
Start_ISAC:
- if (val) {
+ if (val)
isac_interrupt(cs, val);
- stat |= 2;
- }
count++;
val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
if (val && count < MAXCOUNT) {
@@ -196,16 +202,12 @@ teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
if (count >= MAXCOUNT)
printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
- if (stat & 1) {
- 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(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
- writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0);
- }
+ writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
+ writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
+ writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
+ writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0);
+ writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
+ writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
}
inline static void
@@ -222,15 +224,16 @@ release_ioregs(struct IsdnCardState *cs, int mask)
void
release_io_teles3(struct IsdnCardState *cs)
{
- if (cs->typ == ISDN_CTYPE_TELESPCMCIA)
+ if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
release_region(cs->hw.teles3.hscx[0], 97);
- else {
- if (cs->hw.teles3.cfg_reg)
+ } else {
+ 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);
}
}
@@ -309,9 +312,6 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
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:
inithscxisac(cs, 3);
return(0);
@@ -321,7 +321,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __init
setup_teles3(struct IsdnCard *card)
{
u_char val;
@@ -405,12 +405,13 @@ setup_teles3(struct IsdnCard *card)
CardType[cs->typ],
cs->hw.teles3.isac + 32,
cs->hw.teles3.isac + 64);
- if (cs->hw.teles3.cfg_reg)
+ 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(cs->hw.teles3.isac + 32, 32, "HiSax isac");
@@ -420,12 +421,13 @@ setup_teles3(struct IsdnCard *card)
CardType[cs->typ],
cs->hw.teles3.hscx[0] + 32,
cs->hw.teles3.hscx[0] + 64);
- if (cs->hw.teles3.cfg_reg)
+ 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
@@ -436,12 +438,13 @@ setup_teles3(struct IsdnCard *card)
CardType[cs->typ],
cs->hw.teles3.hscx[1] + 32,
cs->hw.teles3.hscx[1] + 64);
- if (cs->hw.teles3.cfg_reg)
+ 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
@@ -464,9 +467,10 @@ setup_teles3(struct IsdnCard *card)
* 0x1f=with AB
* 0x1c 16.3 ???
* 0x39 16.3 1.1
+ * 0x38 16.3 1.3
* 0x46 16.3 with AB + Video (Teles-Vision)
*/
- if (val != 0x46 && val != 0x39 && val != 0x1c && val != 0x1e && val != 0x1f) {
+ if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) {
printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
cs->hw.teles3.cfg_reg + 2, val);
release_io_teles3(cs);
@@ -494,6 +498,7 @@ setup_teles3(struct IsdnCard *card)
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Teles_card_msg;
+ cs->irq_func = &teles3_interrupt;
ISACVersion(cs, "Teles3:");
if (HscxVersion(cs, "Teles3:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index 88592aa8d..9ffe99918 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -1,4 +1,4 @@
-/* $Id: telespci.c,v 2.5 1998/11/15 23:55:28 keil Exp $
+/* $Id: telespci.c,v 2.9 1999/08/11 21:01:34 keil Exp $
* telespci.c low level stuff for Teles PCI isdn cards
*
@@ -7,6 +7,19 @@
*
*
* $Log: telespci.c,v $
+ * Revision 2.9 1999/08/11 21:01:34 keil
+ * new PCI codefix
+ *
+ * Revision 2.8 1999/08/10 16:02:10 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 2.7 1999/07/12 21:05:34 keil
+ * fix race in IRQ handling
+ * added watchdog for lost IRQs
+ *
+ * Revision 2.6 1999/07/01 08:12:15 keil
+ * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
+ *
* Revision 2.5 1998/11/15 23:55:28 keil
* changes from 2.0
*
@@ -24,16 +37,17 @@
*/
#define __NO_VERSION__
#include <linux/config.h>
-#include <linux/string.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
#include <linux/pci.h>
+#ifndef COMPAT_HAS_NEW_PCI
+#include <linux/bios32.h>
+#endif
extern const char *CardType[];
-
-const char *telespci_revision = "$Revision: 2.5 $";
+const char *telespci_revision = "$Revision: 2.9 $";
#define ZORAN_PO_RQ_PEN 0x02000000
#define ZORAN_PO_WR 0x00800000
@@ -243,35 +257,27 @@ telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
#define MAXCOUNT 20
struct IsdnCardState *cs = dev_id;
- u_char val, stat = 0;
+ u_char val;
if (!cs) {
printk(KERN_WARNING "TelesPCI: Spurious interrupt!\n");
return;
}
val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
- if (val) {
+ if (val)
hscx_int_main(cs, val);
- stat |= 1;
- }
val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
- if (val) {
+ if (val)
isac_interrupt(cs, val);
- stat |= 2;
- }
/* Clear interrupt register for Zoran PCI controller */
writel(0x70000000, cs->hw.teles0.membase + 0x3C);
- if (stat & 1) {
- 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(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
- writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
- }
+ writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
+ writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
+ writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
+ writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
+ writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
+ writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
}
void
@@ -289,9 +295,6 @@ TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
case CARD_RELEASE:
release_io_telespci(cs);
return(0);
- case CARD_SETIRQ:
- return(request_irq(cs->irq, &telespci_interrupt,
- I4L_IRQ_FLAG | SA_SHIRQ, "HiSax", cs));
case CARD_INIT:
inithscxisac(cs, 3);
return(0);
@@ -301,20 +304,29 @@ TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
+#ifdef COMPAT_HAS_NEW_PCI
static struct pci_dev *dev_tel __initdata = NULL;
+#else
+static int pci_index __initdata = 0;
+#endif
-__initfunc(int
-setup_telespci(struct IsdnCard *card))
+int __init
+setup_telespci(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
+#ifndef COMPAT_HAS_NEW_PCI
+ u_char pci_bus, pci_device_fn, pci_irq;
+ u_int pci_memaddr;
+ u_char found = 0;
+#endif
strcpy(tmp, telespci_revision);
printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_TELESPCI)
return (0);
-
#if CONFIG_PCI
+#ifdef COMPAT_HAS_NEW_PCI
if (!pci_present()) {
printk(KERN_ERR "TelesPCI: no PCI bus present\n");
return(0);
@@ -325,15 +337,41 @@ setup_telespci(struct IsdnCard *card))
printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
return(0);
}
- cs->hw.teles0.membase = (u_int) ioremap(dev_tel->base_address[0],
+ cs->hw.teles0.membase = (u_int) ioremap(get_pcibase(dev_tel, 0),
PAGE_SIZE);
printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
- dev_tel->base_address[0], dev_tel->irq);
+ get_pcibase(dev_tel, 0), dev_tel->irq);
} else {
printk(KERN_WARNING "TelesPCI: No PCI card found\n");
return(0);
}
#else
+ for (; pci_index < 0xff; pci_index++) {
+ if (pcibios_find_device (0x11DE, 0x6120,
+ pci_index, &pci_bus, &pci_device_fn)
+ == PCIBIOS_SUCCESSFUL) {
+ found = 1;
+ } else {
+ break;
+ }
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_memaddr);
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq);
+
+ printk(KERN_INFO "Found: Zoran, base-address: 0x%x,"
+ " irq: 0x%x\n", pci_memaddr, pci_irq);
+ break;
+ }
+ if (!found) {
+ printk(KERN_WARNING "TelesPCI: No PCI card found\n");
+ return(0);
+ }
+ pci_index++;
+ cs->irq = pci_irq;
+ cs->hw.teles0.membase = (u_int) vremap(pci_memaddr, PAGE_SIZE);
+#endif /* COMPAT_HAS_NEW_PCI */
+#else
printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
return (0);
@@ -361,6 +399,8 @@ setup_telespci(struct IsdnCard *card))
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &TelesPCI_card_msg;
+ cs->irq_func = &telespci_interrupt;
+ cs->irq_flags |= SA_SHIRQ;
ISACVersion(cs, "TelesPCI:");
if (HscxVersion(cs, "TelesPCI:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/icn/.cvsignore b/drivers/isdn/icn/.cvsignore
deleted file mode 100644
index 857dd22e9..000000000
--- a/drivers/isdn/icn/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.depend
-.*.flags
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index d08730e17..26ac3502d 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.56 1999/04/12 13:15:07 fritz Exp $
+/* $Id: icn.c,v 1.59 1999/08/28 22:10:55 keil Exp $
* ISDN low-level module for the ICN active ISDN-Card.
*
@@ -19,6 +19,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: icn.c,v $
+ * Revision 1.59 1999/08/28 22:10:55 keil
+ * __setup function should be static
+ *
+ * Revision 1.58 1999/08/25 16:44:17 keil
+ * Support for new __setup function
+ *
+ * Revision 1.57 1999/07/06 16:15:30 detabc
+ * remove unused messages
+ *
* Revision 1.56 1999/04/12 13:15:07 fritz
* Fixed a cast.
*
@@ -39,10 +48,6 @@
* Revision 1.51 1998/03/07 22:29:55 fritz
* Adapted Detlef's chenges for 2.1.
*
- * Revision 1.50 1998/03/07 17:41:54 detabc
- * add d-channel connect and disconnect support statcallback
- * from icn low-level to link->level
- *
* Revision 1.49 1998/02/13 11:14:15 keil
* change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
*
@@ -233,7 +238,7 @@
#undef MAP_DEBUG
static char
-*revision = "$Revision: 1.56 $";
+*revision = "$Revision: 1.59 $";
static int icn_addcard(int, char *, char *);
@@ -1847,13 +1852,25 @@ icn_addcard(int port, char *id1, char *id2)
#ifdef MODULE
#define icn_init init_module
#else
+#ifdef COMPAT_HAS_NEW_SETUP
+#include <linux/init.h>
+static int __init
+icn_setup(char *line)
+{
+ char *p, *str;
+ int ints[3];
+ static char sid[20];
+ static char sid2[20];
+
+ str = get_options(line, 2, ints);
+#else
void
icn_setup(char *str, int *ints)
{
char *p;
static char sid[20];
static char sid2[20];
-
+#endif
if (ints[0])
portbase = ints[1];
if (ints[0] > 1)
@@ -1867,8 +1884,14 @@ icn_setup(char *str, int *ints)
icn_id2 = sid2;
}
}
+#ifdef COMPAT_HAS_NEW_SETUP
+ return(1);
+}
+__setup("icn=", icn_setup);
+#else
}
#endif
+#endif /* MODULES */
int
icn_init(void)
diff --git a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c
index 67307a0ec..3599d2ada 100644
--- a/drivers/isdn/isdn_audio.c
+++ b/drivers/isdn/isdn_audio.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_audio.c,v 1.13 1999/04/12 12:33:09 fritz Exp $
+/* $Id: isdn_audio.c,v 1.17 1999/08/17 11:10:52 paul Exp $
* Linux ISDN subsystem, audio conversion and compression (linklevel).
*
@@ -21,6 +21,30 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_audio.c,v $
+ * Revision 1.17 1999/08/17 11:10:52 paul
+ * don't try to use x86 assembler on non-x86!
+ *
+ * Revision 1.16 1999/08/06 12:47:35 calle
+ * Using __GNUC__ == 2 && __GNUC_MINOR__ < 95 how to define
+ * ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT
+ *
+ * Revision 1.15 1999/08/06 12:02:52 calle
+ * egcs 2.95 complain about invalid asm statement:
+ * "fixed or forbidden register 2 (cx) was spilled for class CREG."
+ * Using ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT and not
+ * define it at the moment.
+ *
+ * Revision 1.14 1999/07/11 17:14:06 armin
+ * Added new layer 2 and 3 protocols for Fax and DSP functions.
+ * Moved "Add CPN to RING message" to new register S23,
+ * "Display message" is now correct on register S13 bit 7.
+ * New audio command AT+VDD implemented (deactivate DTMF decoder and
+ * activate possible existing hardware/DSP decoder).
+ * Moved some tty defines to .h file.
+ * Made whitespace possible in AT command line.
+ * Some AT-emulator output bugfixes.
+ * First Fax G3 implementations.
+ *
* Revision 1.13 1999/04/12 12:33:09 fritz
* Changes from 2.0 tree.
*
@@ -71,7 +95,7 @@
#include "isdn_audio.h"
#include "isdn_common.h"
-char *isdn_audio_revision = "$Revision: 1.13 $";
+char *isdn_audio_revision = "$Revision: 1.17 $";
/*
* Misc. lookup-tables.
@@ -268,7 +292,18 @@ static char dtmf_matrix[4][4] =
{'*', '0', '#', 'D'}
};
-#if ((CPU == 386) || (CPU == 486) || (CPU == 586))
+
+/*
+ * egcs 2.95 complain about invalid asm statement:
+ * "fixed or forbidden register 2 (cx) was spilled for class CREG."
+ */
+#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) && defined(__GNUC__)
+#if __GNUC__ == 2 && __GNUC_MINOR__ < 95
+#define ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT
+#endif
+#endif
+
+#ifdef ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT
static inline void
isdn_audio_tlookup(const void *table, void *buff, unsigned long n)
{
@@ -711,16 +746,51 @@ isdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt)
}
void
-isdn_audio_eval_silence(modem_info * info)
+isdn_audio_put_dle_code(modem_info * info, u_char code)
{
- silence_state *s = info->silence_state;
struct sk_buff *skb;
unsigned long flags;
int di;
int ch;
- char what;
char *p;
+ skb = dev_alloc_skb(2);
+ if (!skb) {
+ printk(KERN_WARNING
+ "isdn_audio: Could not alloc skb for ttyI%d\n",
+ info->line);
+ return;
+ }
+ p = (char *) skb_put(skb, 2);
+ p[0] = 0x10;
+ p[1] = code;
+ if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
+ printk(KERN_WARNING
+ "isdn_audio: insufficient skb_headroom, dropping\n");
+ kfree_skb(skb);
+ return;
+ }
+ ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
+ ISDN_AUDIO_SKB_LOCK(skb) = 0;
+ save_flags(flags);
+ cli();
+ di = info->isdn_driver;
+ ch = info->isdn_channel;
+ __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
+ dev->drv[di]->rcvcount[ch] += 2;
+ restore_flags(flags);
+ /* Schedule dequeuing */
+ if ((dev->modempoll) && (info->rcvsched))
+ isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+ wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
+}
+
+void
+isdn_audio_eval_silence(modem_info * info)
+{
+ silence_state *s = info->silence_state;
+ char what;
+
what = ' ';
if (s->idx > (info->emu.vpar[2] * 800)) {
@@ -734,28 +804,6 @@ isdn_audio_eval_silence(modem_info * info)
if ((what == 's') || (what == 'q')) {
printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
(what=='s') ? "silence":"quiet");
- skb = dev_alloc_skb(2);
- p = (char *) skb_put(skb, 2);
- p[0] = 0x10;
- p[1] = what;
- if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
- printk(KERN_WARNING
- "isdn_audio: insufficient skb_headroom, dropping\n");
- kfree_skb(skb);
- return;
- }
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
- save_flags(flags);
- cli();
- di = info->isdn_driver;
- ch = info->isdn_channel;
- __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
- dev->drv[di]->rcvcount[ch] += 2;
- restore_flags(flags);
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
+ isdn_audio_put_dle_code(info, what);
}
}
diff --git a/drivers/isdn/isdn_audio.h b/drivers/isdn/isdn_audio.h
index ee33ce020..54dcb253e 100644
--- a/drivers/isdn/isdn_audio.h
+++ b/drivers/isdn/isdn_audio.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_audio.h,v 1.7 1999/04/12 12:33:11 fritz Exp $
+/* $Id: isdn_audio.h,v 1.8 1999/07/11 17:14:07 armin Exp $
* Linux ISDN subsystem, audio conversion and compression (linklevel).
*
@@ -19,6 +19,17 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_audio.h,v $
+ * Revision 1.8 1999/07/11 17:14:07 armin
+ * Added new layer 2 and 3 protocols for Fax and DSP functions.
+ * Moved "Add CPN to RING message" to new register S23,
+ * "Display message" is now correct on register S13 bit 7.
+ * New audio command AT+VDD implemented (deactivate DTMF decoder and
+ * activate possible existing hardware/DSP decoder).
+ * Moved some tty defines to .h file.
+ * Made whitespace possible in AT command line.
+ * Some AT-emulator output bugfixes.
+ * First Fax G3 implementations.
+ *
* Revision 1.7 1999/04/12 12:33:11 fritz
* Changes from 2.0 tree.
*
@@ -74,3 +85,4 @@ dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int);
extern void isdn_audio_eval_silence(modem_info *);
silence_state *isdn_audio_silence_init(silence_state *);
+extern void isdn_audio_put_dle_code(modem_info *, u_char);
diff --git a/drivers/isdn/isdn_budget.c b/drivers/isdn/isdn_budget.c
deleted file mode 100644
index 985c97ba8..000000000
--- a/drivers/isdn/isdn_budget.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/* $Id: isdn_budget.c,v 1.3 1998/10/23 10:18:39 paul Exp $
- *
- * Linux ISDN subsystem, budget-accounting for network interfaces.
- *
- * Copyright 1997 by Christian Lademann <cal@zls.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_budget.c,v $
- * Revision 1.3 1998/10/23 10:18:39 paul
- * Implementation of "dialmode" (successor of "status")
- * You also need current isdnctrl for this!
- *
- * Revision 1.2 1998/03/07 23:17:30 fritz
- * Added RCS keywords
- * Bugfix: Did not compile without isdn_dumppkt beeing enabled.
- *
- */
-
-/*
-30.06.97:cal:angelegt
-04.11.97:cal:budget.period: int --> time_t
-*/
-
-#include <linux/config.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/isdn.h>
-#include "isdn_common.h"
-#include "isdn_net.h"
-
-#ifdef CONFIG_ISDN_BUDGET
-
-#define VERBOSE_PRINTK(v, l, p...) { \
- if(dev->net_verbose >= (v)) { \
- printk(l ## p); \
- } else { ; } \
-}
-
-
-int
-isdn_net_budget(int type, struct device *ndev) {
- isdn_net_local *lp = (isdn_net_local *)ndev->priv;
- int i, ret = 0;
-
- switch(type) {
- case ISDN_BUDGET_INIT:
- for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) {
- lp->budget [i] .amount = -1;
- lp->budget [i] .used = 0;
- lp->budget [i] .period = (time_t)0;
- lp->budget [i] .period_started = (time_t)0;
- lp->budget [i] .last_check = CURRENT_TIME;
- lp->budget [i] .notified = 0;
- }
-
- return(0);
- break;
-
- case ISDN_BUDGET_CHECK_DIAL:
- case ISDN_BUDGET_CHECK_CHARGE:
- case ISDN_BUDGET_CHECK_ONLINE:
- ret = 0;
-
- for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) {
- if(lp->budget [i] .amount < 0)
- continue;
-
- if(lp->budget [i] .period_started + lp->budget [i] .period < CURRENT_TIME) {
- lp->budget [i] .used = 0;
- lp->budget [i] .period_started = CURRENT_TIME;
- lp->budget [i] .notified = 0;
- }
-
- if(lp->budget [i] .used >= lp->budget [i] .amount)
- ret |= (1 << i);
- }
-
- switch(type) {
- case ISDN_BUDGET_CHECK_DIAL:
- if(! ret) {
- lp->budget [ISDN_BUDGET_DIAL] .used++;
- lp->budget [ISDN_BUDGET_DIAL] .last_check = CURRENT_TIME;
- }
- break;
-
- case ISDN_BUDGET_CHECK_CHARGE:
- lp->budget [ISDN_BUDGET_CHARGE] .used++;
- lp->budget [ISDN_BUDGET_CHARGE] .last_check = CURRENT_TIME;
- break;
-
- case ISDN_BUDGET_CHECK_ONLINE:
- if(lp->budget [ISDN_BUDGET_ONLINE] .last_check) {
- lp->budget [ISDN_BUDGET_ONLINE] .used += (CURRENT_TIME - lp->budget [ISDN_BUDGET_ONLINE] .last_check);
- }
-
- lp->budget [ISDN_BUDGET_ONLINE] .last_check = CURRENT_TIME;
- break;
- }
-
-/*
- if(ret)
- lp->flags |= ISDN_NET_DM_OFF;
-*/
- for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) {
- if(ret & (1 << i) && ! lp->budget [i] .notified) {
- switch(i) {
- case ISDN_BUDGET_DIAL:
- printk(KERN_WARNING "isdn_budget: dial budget used up.\n");
- break;
-
- case ISDN_BUDGET_CHARGE:
- printk(KERN_WARNING "isdn_budget: charge budget used up.\n");
- break;
-
- case ISDN_BUDGET_ONLINE:
- printk(KERN_WARNING "isdn_budget: online budget used up.\n");
- break;
-
- default:
- printk(KERN_WARNING "isdn_budget: budget #%d used up.\n", i);
- break;
- }
-
- lp->budget [i] .notified = 1;
- }
- }
-
- return(ret);
- break;
-
- case ISDN_BUDGET_START_ONLINE:
- lp->budget [ISDN_BUDGET_ONLINE] .last_check = CURRENT_TIME;
- return(0);
-
- break;
- }
-
- return(-1);
-}
-
-
-int
-isdn_budget_ioctl(isdn_ioctl_budget *iocmd) {
- isdn_net_dev *p = isdn_net_findif(iocmd->name);
-
- if(p) {
- switch(iocmd->command) {
- case ISDN_BUDGET_SET_BUDGET:
- if(! suser())
- return(-EPERM);
-
- if(iocmd->budget < 0 || iocmd->budget > ISDN_BUDGET_NUM_BUDGET)
- return(-EINVAL);
-
- if(iocmd->amount < 0)
- iocmd->amount = -1;
-
- p->local->budget [iocmd->budget] .amount = iocmd->amount;
- p->local->budget [iocmd->budget] .period = iocmd->period;
-
- if(iocmd->used <= 0)
- p->local->budget [iocmd->budget] .used = 0;
- else
- p->local->budget [iocmd->budget] .used = iocmd->used;
-
- if(iocmd->period_started == (time_t)0)
- p->local->budget [iocmd->budget] .period_started = CURRENT_TIME;
- else
- p->local->budget [iocmd->budget] .period_started = iocmd->period_started;
-
- return(0);
- break;
-
- case ISDN_BUDGET_GET_BUDGET:
- if(iocmd->budget < 0 || iocmd->budget > ISDN_BUDGET_NUM_BUDGET)
- return(-EINVAL);
-
- iocmd->amount = p->local->budget [iocmd->budget] .amount;
- iocmd->used = p->local->budget [iocmd->budget] .used;
- iocmd->period = p->local->budget [iocmd->budget] .period;
- iocmd->period_started = p->local->budget [iocmd->budget] .period_started;
-
- return(0);
- break;
-
- default:
- return(-EINVAL);
- break;
- }
- }
- return(-ENODEV);
-}
-#endif
diff --git a/drivers/isdn/isdn_cards.c b/drivers/isdn/isdn_cards.c
index 06fa3e7d7..bdbcd4191 100644
--- a/drivers/isdn/isdn_cards.c
+++ b/drivers/isdn/isdn_cards.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_cards.c,v 1.9 1999/04/12 12:33:11 fritz Exp $
+/* $Id: isdn_cards.c,v 1.10 1999/07/20 06:41:28 calle Exp $
* Linux ISDN subsystem, initialization for non-modularized drivers.
*
@@ -19,6 +19,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_cards.c,v $
+ * Revision 1.10 1999/07/20 06:41:28 calle
+ * Bugfix: After the redesign of the AVM B1 driver, the driver didn't even
+ * compile, if not selected as modules.
+ *
* Revision 1.9 1999/04/12 12:33:11 fritz
* Changes from 2.0 tree.
*
@@ -67,12 +71,9 @@ extern void eicon_init(void);
#endif
#ifdef CONFIG_ISDN_DRV_AVMB1
-extern void avmb1_init(void);
+extern void kcapi_init(void);
extern void capi_init(void);
extern void capidrv_init(void);
-#ifdef CONFIG_PCI
-extern int b1pci_init(void);
-#endif
#endif
void
@@ -88,10 +89,7 @@ isdn_cards_init(void)
pcbit_init();
#endif
#ifdef CONFIG_ISDN_DRV_AVMB1
- avmb1_init();
-#ifdef CONFIG_PCI
- b1pci_init();
-#endif
+ kcapi_init();
capi_init();
capidrv_init();
#endif
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index 779a327fa..cac4be6dc 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.75 1999/04/18 14:06:47 fritz Exp $
+/* $Id: isdn_common.c,v 1.86 1999/07/31 12:59:42 armin Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -21,6 +21,51 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.86 1999/07/31 12:59:42 armin
+ * Added tty fax capabilities.
+ *
+ * Revision 1.85 1999/07/29 16:58:35 armin
+ * Bugfix: DLE handling in isdn_readbchan()
+ *
+ * Revision 1.84 1999/07/25 16:21:10 keil
+ * fix number matching
+ *
+ * Revision 1.83 1999/07/13 21:02:05 werner
+ * Added limit possibilty of driver b_channel resources (ISDN_STAT_DISCH)
+ *
+ * Revision 1.82 1999/07/12 21:06:50 werner
+ * Fixed problem when loading more than one driver temporary
+ *
+ * Revision 1.81 1999/07/11 17:14:09 armin
+ * Added new layer 2 and 3 protocols for Fax and DSP functions.
+ * Moved "Add CPN to RING message" to new register S23,
+ * "Display message" is now correct on register S13 bit 7.
+ * New audio command AT+VDD implemented (deactivate DTMF decoder and
+ * activate possible existing hardware/DSP decoder).
+ * Moved some tty defines to .h file.
+ * Made whitespace possible in AT command line.
+ * Some AT-emulator output bugfixes.
+ * First Fax G3 implementations.
+ *
+ * Revision 1.80 1999/07/07 10:14:00 detabc
+ * remove unused messages
+ *
+ * Revision 1.79 1999/07/05 23:51:30 werner
+ * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl
+ * hisaxctrl id 10 <nr. of chans 0-2>
+ *
+ * Revision 1.78 1999/07/05 20:21:15 werner
+ * changes to use diversion sources for all kernel versions.
+ * removed static device, only proc filesystem used
+ *
+ * Revision 1.77 1999/07/01 08:29:50 keil
+ * compatibility to 2.3 kernel
+ *
+ * Revision 1.76 1999/06/29 16:16:44 calle
+ * Let ISDN_CMD_UNLOAD work with open isdn devices without crash again.
+ * Also right unlocking (ISDN_CMD_UNLOCK) is done now.
+ * isdnlog should check returncode of read(2) calls.
+ *
* Revision 1.75 1999/04/18 14:06:47 fritz
* Removed TIMRU stuff.
*
@@ -65,16 +110,6 @@
* brute force fix to avoid Ugh's in isdn_tty_write()
* cleaned up some dead code
*
- * Revision 1.65 1998/06/07 00:20:00 fritz
- * abc cleanup.
- *
- * Revision 1.64 1998/06/02 12:10:03 detabc
- * wegen einer einstweiliger verfuegung gegen DW ist zur zeit
- * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
- *
- * Revision 1.63 1998/05/03 17:40:38 detabc
- * Include abc-extension-support for >= 2.1.x Kernels in
- * isdn_net.c and isdn_common.c. alpha-test OK and running !
*
* Revision 1.62 1998/04/14 16:28:43 he
* Fixed user space access with interrupts off and remaining
@@ -335,6 +370,9 @@
#ifdef CONFIG_ISDN_AUDIO
#include "isdn_audio.h"
#endif
+#ifdef CONFIG_ISDN_DIVERSION
+#include <linux/isdn_divertif.h>
+#endif CONFIG_ISDN_DIVERSION
#include "isdn_v110.h"
#include "isdn_cards.h"
@@ -343,7 +381,7 @@
isdn_dev *dev = (isdn_dev *) 0;
-static char *isdn_revision = "$Revision: 1.75 $";
+static char *isdn_revision = "$Revision: 1.86 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
@@ -359,6 +397,11 @@ static char *isdn_audio_revision = ": none $";
#endif
extern char *isdn_v110_revision;
+#ifdef CONFIG_ISDN_DIVERSION
+isdn_divert_if *divert_if = NULL; /* interface to diversion module */
+#endif CONFIG_ISDN_DIVERSION
+
+
static int isdn_writebuf_stub(int, int, const u_char *, int, int);
void
@@ -449,6 +492,8 @@ isdn_wildmat(char *s, char *p)
register int reverse;
register int nostar = 1;
+ if (!(*s) && !(*p))
+ return(1);
for (; *p; s++, p++)
switch (*p) {
case '\\':
@@ -760,7 +805,7 @@ isdn_status_callback(isdn_ctrl * c)
return 0;
}
/* Try to find a network-interface which will accept incoming call */
- r = isdn_net_find_icall(di, c->arg, i, c->parm.setup);
+ r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, c->parm.setup));
switch (r) {
case 0:
/* No network-device replies.
@@ -768,7 +813,13 @@ isdn_status_callback(isdn_ctrl * c)
* These return 0 on no match, 1 on match and
* 3 on eventually match, if CID is longer.
*/
- retval = isdn_tty_find_icall(di, c->arg, c->parm.setup);
+ if (c->command == ISDN_STAT_ICALL)
+ if ((retval = isdn_tty_find_icall(di, c->arg, c->parm.setup))) return(retval);
+#ifdef CONFIG_ISDN_DIVERSION
+ if (divert_if)
+ if ((retval = divert_if->stat_callback(c)))
+ return(retval); /* processed */
+#endif CONFIG_ISDN_DIVERSION
if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
/* No tty responding */
cmd.driver = di;
@@ -831,6 +882,20 @@ isdn_status_callback(isdn_ctrl * c)
printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
dev->drvid[di], c->arg, c->parm.num);
isdn_tty_stat_callback(i, c);
+#ifdef CONFIG_ISDN_DIVERSION
+ if (divert_if)
+ divert_if->stat_callback(c);
+#endif CONFIG_ISDN_DIVERSION
+ break;
+ case ISDN_STAT_DISPLAY:
+#ifdef ISDN_DEBUG_STATCALLB
+ printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display);
+#endif
+ isdn_tty_stat_callback(i, c);
+#ifdef CONFIG_ISDN_DIVERSION
+ if (divert_if)
+ divert_if->stat_callback(c);
+#endif CONFIG_ISDN_DIVERSION
break;
case ISDN_STAT_DCONN:
if (i < 0)
@@ -869,6 +934,11 @@ isdn_status_callback(isdn_ctrl * c)
isdn_v110_stat_callback(i, c);
if (isdn_tty_stat_callback(i, c))
break;
+#ifdef CONFIG_ISDN_DIVERSION
+ if (divert_if)
+ divert_if->stat_callback(c);
+#endif CONFIG_ISDN_DIVERSION
+ break;
break;
case ISDN_STAT_BCONN:
if (i < 0)
@@ -924,7 +994,34 @@ isdn_status_callback(isdn_ctrl * c)
return -1;
isdn_info_update();
break;
+ case ISDN_STAT_DISCH:
+ save_flags(flags);
+ cli();
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ if ((dev->drvmap[i] == di) &&
+ (dev->chanmap[i] == c->arg)) {
+ if (c->parm.num[0])
+ dev->usage[i] &= ~ISDN_USAGE_DISABLED;
+ else
+ if (USG_NONE(dev->usage[i])) {
+ dev->usage[i] |= ISDN_USAGE_DISABLED;
+ }
+ else
+ retval = -1;
+ break;
+ }
+ restore_flags(flags);
+ isdn_info_update();
+ break;
case ISDN_STAT_UNLOAD:
+ while (dev->drv[di]->locks > 0) {
+ isdn_ctrl cmd;
+ cmd.driver = di;
+ cmd.arg = 0;
+ cmd.command = ISDN_CMD_UNLOCK;
+ isdn_command(&cmd);
+ dev->drv[di]->locks--;
+ }
save_flags(flags);
cli();
isdn_tty_stat_callback(i, c);
@@ -932,6 +1029,7 @@ isdn_status_callback(isdn_ctrl * c)
if (dev->drvmap[i] == di) {
dev->drvmap[i] = -1;
dev->chanmap[i] = -1;
+ dev->usage[i] &= ~ISDN_USAGE_DISABLED;
}
dev->drivers--;
dev->channels -= dev->drv[di]->channels;
@@ -941,7 +1039,7 @@ isdn_status_callback(isdn_ctrl * c)
isdn_free_queue(&dev->drv[di]->rpqueue[i]);
kfree(dev->drv[di]->rpqueue);
kfree(dev->drv[di]->rcv_waitq);
-#if LINUX_VERSION_CODE < 131841
+#ifndef COMPAT_HAS_NEW_WAITQ
kfree(dev->drv[di]->snd_waitq);
#endif
kfree(dev->drv[di]);
@@ -954,6 +1052,22 @@ isdn_status_callback(isdn_ctrl * c)
break;
case CAPI_PUT_MESSAGE:
return(isdn_capi_rec_hl_msg(&c->parm.cmsg));
+#ifdef CONFIG_ISDN_TTY_FAX
+ case ISDN_STAT_FAXIND:
+ isdn_tty_stat_callback(i, c);
+ break;
+#endif
+#ifdef CONFIG_ISDN_AUDIO
+ case ISDN_STAT_AUDIO:
+ isdn_tty_stat_callback(i, c);
+ break;
+#endif
+#ifdef CONFIG_ISDN_DIVERSION
+ case ISDN_STAT_PROT:
+ case ISDN_STAT_REDIR:
+ if (divert_if)
+ return(divert_if->stat_callback(c));
+#endif CONFIG_ISDN_DIVERSION
default:
return -1;
}
@@ -989,10 +1103,10 @@ isdn_getnum(char **p)
* of the mapping (di,ch)<->minor, happen during the sleep? --he
*/
int
-#if LINUX_VERSION_CODE < 131841
-isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct wait_queue **sleep)
-#else
+#ifdef COMPAT_HAS_NEW_WAITQ
isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep)
+#else
+isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct wait_queue **sleep)
#endif
{
int left;
@@ -1021,7 +1135,7 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
if (ISDN_AUDIO_SKB_LOCK(skb))
break;
ISDN_AUDIO_SKB_LOCK(skb) = 1;
- if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
+ if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
char *p = skb->data;
unsigned long DLEmask = (1 << channel);
@@ -1320,11 +1434,11 @@ isdn_poll(struct file *file, poll_table * wait)
return mask;
}
if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
- poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
if (drvidx < 0) {
- printk(KERN_ERR "isdn_common: isdn_poll 1 -> what the hell\n");
- return POLLERR;
+ /* driver deregistered while file open */
+ return POLLHUP;
}
+ poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
mask = POLLOUT | POLLWRNORM;
if (dev->drv[drvidx]->stavail) {
mask |= POLLIN | POLLRDNORM;
@@ -1938,6 +2052,8 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
((pre_dev != d) || (pre_chan != dev->chanmap[i])))
continue;
+ if (dev->usage[i] & ISDN_USAGE_DISABLED)
+ continue; /* usage not allowed */
if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
if (((dev->drv[d]->interface->features & features) == features) ||
(((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
@@ -2132,13 +2248,12 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
int j, k, m;
ulong flags;
-#if LINUX_VERSION_CODE >= 131841
+#ifdef COMPAT_HAS_NEW_WAITQ
init_waitqueue_head(&d->st_waitq);
#endif
if (d->flags & DRV_FLAG_RUNNING)
return -1;
- if (n < 1)
- return 0;
+ if (n < 1) return 0;
m = (adding) ? d->channels + n : n;
@@ -2185,13 +2300,13 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
if ((adding) && (d->rcv_waitq))
kfree(d->rcv_waitq);
-#if LINUX_VERSION_CODE < 131841
- if (!(d->rcv_waitq = (struct wait_queue **)
- kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) {
-#else
+#ifdef COMPAT_HAS_NEW_WAITQ
d->rcv_waitq = (wait_queue_head_t *)
kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL);
if (!d->rcv_waitq) {
+#else
+ if (!(d->rcv_waitq = (struct wait_queue **)
+ kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) {
#endif
printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
if (!adding) {
@@ -2201,7 +2316,13 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
}
return -1;
}
-#if LINUX_VERSION_CODE < 131841
+#ifdef COMPAT_HAS_NEW_WAITQ
+ d->snd_waitq = d->rcv_waitq + m;
+ for (j = 0; j < m; j++) {
+ init_waitqueue_head(&d->rcv_waitq[m]);
+ init_waitqueue_head(&d->snd_waitq[m]);
+ }
+#else
memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * m);
if ((adding) && (d->snd_waitq))
@@ -2218,12 +2339,6 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
return -1;
}
memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * m);
-#else
- d->snd_waitq = d->rcv_waitq + m;
- for (j = 0; j < m; j++) {
- init_waitqueue_head(&d->rcv_waitq[m]);
- init_waitqueue_head(&d->snd_waitq[m]);
- }
#endif
dev->channels += n;
@@ -2245,6 +2360,60 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
* Low-level-driver registration
*/
+
+#ifdef CONFIG_ISDN_DIVERSION
+extern isdn_divert_if *divert_if;
+
+static char *map_drvname(int di)
+{
+ if ((di < 0) || (di >= ISDN_MAX_DRIVERS))
+ return(NULL);
+ return(dev->drvid[di]); /* driver name */
+} /* map_drvname */
+
+static int map_namedrv(char *id)
+{ int i;
+
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ { if (!strcmp(dev->drvid[i],id))
+ return(i);
+ }
+ return(-1);
+} /* map_namedrv */
+
+int DIVERT_REG_NAME(isdn_divert_if *i_div)
+{
+ if (i_div->if_magic != DIVERT_IF_MAGIC)
+ return(DIVERT_VER_ERR);
+ switch (i_div->cmd)
+ {
+ case DIVERT_CMD_REL:
+ if (divert_if != i_div)
+ return(DIVERT_REL_ERR);
+ divert_if = NULL; /* free interface */
+ MOD_DEC_USE_COUNT;
+ return(DIVERT_NO_ERR);
+
+ case DIVERT_CMD_REG:
+ if (divert_if)
+ return(DIVERT_REG_ERR);
+ i_div->ll_cmd = isdn_command; /* set command function */
+ i_div->drv_to_name = map_drvname;
+ i_div->name_to_drv = map_namedrv;
+ MOD_INC_USE_COUNT;
+ divert_if = i_div; /* remember interface */
+ return(DIVERT_NO_ERR);
+
+ default:
+ return(DIVERT_CMD_ERR);
+ }
+} /* DIVERT_REG_NAME */
+
+EXPORT_SYMBOL(DIVERT_REG_NAME);
+
+#endif CONFIG_ISDN_DIVERSION
+
+
EXPORT_SYMBOL(register_isdn);
EXPORT_SYMBOL(register_isdn_module);
EXPORT_SYMBOL(unregister_isdn_module);
@@ -2352,18 +2521,18 @@ isdn_init(void)
memset((char *) dev, 0, sizeof(isdn_dev));
init_timer(&dev->timer);
dev->timer.function = isdn_timer_funct;
-#if LINUX_VERSION_CODE < 131841
- dev->sem = MUTEX;
-#else
+#ifdef COMPAT_HAS_NEW_WAITQ
init_MUTEX(&dev->sem);
init_waitqueue_head(&dev->info_waitq);
+#else
+ dev->sem = MUTEX;
#endif
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
dev->drvmap[i] = -1;
dev->chanmap[i] = -1;
dev->m_idx[i] = -1;
strcpy(dev->num[i], "???");
-#if LINUX_VERSION_CODE >= 131841
+#ifdef COMPAT_HAS_NEW_WAITQ
init_waitqueue_head(&dev->mdm.info[i].open_wait);
init_waitqueue_head(&dev->mdm.info[i].close_wait);
#endif
@@ -2452,6 +2621,9 @@ cleanup_module(void)
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
kfree(dev->mdm.info[i].xmit_buf - 4);
+#ifdef CONFIG_ISDN_TTY_FAX
+ kfree(dev->mdm.info[i].fax);
+#endif
}
if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
diff --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h
index 3ba4855b7..e6fb122f6 100644
--- a/drivers/isdn/isdn_common.h
+++ b/drivers/isdn/isdn_common.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.h,v 1.15 1999/04/18 14:06:50 fritz Exp $
+/* $Id: isdn_common.h,v 1.16 1999/07/01 08:29:54 keil Exp $
* header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
*
@@ -21,6 +21,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.h,v $
+ * Revision 1.16 1999/07/01 08:29:54 keil
+ * compatibility to 2.3 kernel
+ *
* Revision 1.15 1999/04/18 14:06:50 fritz
* Removed TIMRU stuff.
*
@@ -115,10 +118,10 @@ extern char *isdn_map_eaz2msn(char *msn, int di);
extern void isdn_timer_ctrl(int tf, int onoff);
extern void isdn_unexclusive_channel(int di, int ch);
extern int isdn_getnum(char **);
-#if LINUX_VERSION_CODE < 131841
-extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**);
-#else
+#ifdef COMPAT_HAS_NEW_WAITQ
extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
+#else
+extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**);
#endif
extern int isdn_get_free_channel(int, int, int, int, int);
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
diff --git a/drivers/isdn/isdn_concap.c b/drivers/isdn/isdn_concap.c
index 1ca6c34e3..ca05f8bf3 100644
--- a/drivers/isdn/isdn_concap.c
+++ b/drivers/isdn/isdn_concap.c
@@ -1,10 +1,16 @@
-/* $Id: isdn_concap.c,v 1.5 1998/10/30 18:44:48 he Exp $
+/* $Id: isdn_concap.c,v 1.6 1999/08/22 20:26:01 calle 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.6 1999/08/22 20:26:01 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
* Revision 1.5 1998/10/30 18:44:48 he
* pass return value from isdn_net_dial_req for dialmode change
*
@@ -53,7 +59,7 @@
int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
{
int tmp;
- struct device *ndev = concap -> net_dev;
+ struct net_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);
@@ -66,7 +72,7 @@ int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
int isdn_concap_dl_connect_req(struct concap_proto *concap)
{
- struct device *ndev = concap -> net_dev;
+ struct net_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);
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index 9e4426af0..9d54f0127 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.84 1999/04/18 14:06:55 fritz Exp $
+/* $Id: isdn_net.c,v 1.89 1999/08/22 20:26:03 calle Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -21,6 +21,25 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.89 1999/08/22 20:26:03 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.88 1999/07/07 10:13:31 detabc
+ * remove unused messages
+ *
+ * Revision 1.87 1999/07/06 07:53:53 calle
+ * calls to dev_alloc_skb waste 16 bytes of memory, if we calculate the
+ * right header space for the lowlevel driver. using alloc_skb instead.
+ *
+ * Revision 1.86 1999/06/09 10:12:05 paul
+ * thinko in previous patch
+ *
+ * Revision 1.85 1999/06/07 19:42:39 paul
+ * isdn_net_getpeer() fixed to return correct `outgoing' flag
+ *
* Revision 1.84 1999/04/18 14:06:55 fritz
* Removed TIMRU stuff.
*
@@ -68,7 +87,7 @@
* Added more locking stuff in tty_write.
*
* Revision 1.71 1998/06/18 22:43:08 fritz
- * Bugfix: Setting ndev->do_ioctl had beed accidetly removed at abc-cleanup.
+ * Bugfix: Setting ndev->do_ioctl had beed accidetly removed at cleanup.
*
* Revision 1.70 1998/06/17 19:50:49 he
* merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
@@ -80,40 +99,13 @@
* so autodial is suppressed for that device until it is switched on using
* 'isdnctrl status dev-name on'.
*
- * Revision 1.68 1998/06/07 00:20:05 fritz
- * abc cleanup.
*
- * Revision 1.67 1998/06/02 12:10:08 detabc
- * wegen einer einstweiliger verfuegung gegen DW ist zur zeit
- * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
*
* Revision 1.66 1998/05/26 22:39:24 he
* sync'ed with 2.1.102 where appropriate (CAPABILITY changes)
* concap typo
* cleared dev.tbusy in isdn_net BCONN status callback
*
- * Revision 1.65 1998/05/22 10:01:11 detabc
- * in case of a icmp-unreach condition the tcp-keepalive-entrys
- * will be dropped from the internal double-link-list (only abc-extension).
- * send icmp unreach only if the skb->protocol == ETH_P_IP
- * speedup abc-no-dchan redial
- *
- * Revision 1.64 1998/05/07 19:58:39 detabc
- * bugfix in abc_delayed_hangup
- * optimize keepalive-tests for abc_rawip
- *
- * Revision 1.63 1998/05/05 23:23:36 detabc
- * change ICMP_HOST_UNREACH to ICMP_NET_UNREACH (only abc-ext.)
- * set dev->tbusy to zero in isdn_net_unreachable() (only abc-ext.)
- * drop all new packets and send ICMP_NET_UNREACH for
- * min. dialwait to max. dialwait * 6 time. (only abc-ext.)
- * change random-deliver of packets (small first) from all emcapsulation
- * to only rawip with ABC-Router-Flag enabled.
- *
- * Revision 1.62 1998/05/03 17:40:42 detabc
- * Include abc-extension-support for >= 2.1.x Kernels in
- * isdn_net.c and isdn_common.c. alpha-test OK and running !
- *
* Revision 1.61 1998/04/16 19:19:42 keil
* Fix from vger (tx max qlength)
*
@@ -371,17 +363,17 @@
/* Prototypes */
int isdn_net_force_dial_lp(isdn_net_local *);
-static int isdn_net_start_xmit(struct sk_buff *, struct device *);
-static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
+static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
+static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *);
-char *isdn_net_revision = "$Revision: 1.84 $";
+char *isdn_net_revision = "$Revision: 1.89 $";
/*
* Code for raw-networking over ISDN
*/
static void
-isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason)
+isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
{
if(skb) {
@@ -403,7 +395,7 @@ isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason)
}
static void
-isdn_net_reset(struct device *dev)
+isdn_net_reset(struct net_device *dev)
{
#ifdef CONFIG_ISDN_X25
struct concap_device_ops * dops =
@@ -426,10 +418,10 @@ isdn_net_reset(struct device *dev)
/* Open/initialize the board. */
static int
-isdn_net_open(struct device *dev)
+isdn_net_open(struct net_device *dev)
{
int i;
- struct device *p;
+ struct net_device *p;
struct in_device *in_dev;
isdn_net_reset(dev);
@@ -616,7 +608,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
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;
+ struct net_device *mdev;
if (lp->master)
mdev = lp->master;
else
@@ -1060,7 +1052,7 @@ isdn_net_dial(void)
* Perform hangup for a net-interface.
*/
void
-isdn_net_hangup(struct device *d)
+isdn_net_hangup(struct net_device *d)
{
isdn_net_local *lp = (isdn_net_local *) d->priv;
isdn_ctrl cmd;
@@ -1191,7 +1183,7 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
* Side-effects: ndev->tbusy is cleared on success.
*/
int
-isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
+isdn_net_send_skb(struct net_device *ndev, isdn_net_local * lp,
struct sk_buff *skb)
{
int ret;
@@ -1224,7 +1216,7 @@ isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
*/
static int
-isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
+isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb)
{
int ret;
@@ -1280,7 +1272,7 @@ isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
}
static void
-isdn_net_adjust_hdr(struct sk_buff *skb, struct device *dev)
+isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
{
isdn_net_local *lp = (isdn_net_local *) dev->priv;
if (!skb)
@@ -1300,7 +1292,7 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct device *dev)
* and start dialing.
*/
static int
-isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
+isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
#ifdef CONFIG_ISDN_X25
@@ -1452,9 +1444,9 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
* Shutdown a net-interface.
*/
static int
-isdn_net_close(struct device *dev)
+isdn_net_close(struct net_device *dev)
{
- struct device *p;
+ struct net_device *p;
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot =
( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
@@ -1490,7 +1482,7 @@ isdn_net_close(struct device *dev)
* Get statistics
*/
static struct enet_statistics *
-isdn_net_get_stats(struct device *dev)
+isdn_net_get_stats(struct net_device *dev)
{
isdn_net_local *lp = (isdn_net_local *) dev->priv;
return &lp->stats;
@@ -1506,7 +1498,7 @@ isdn_net_get_stats(struct device *dev)
*/
static unsigned short
-isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
+isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
@@ -1553,7 +1545,7 @@ 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));
+ struct sk_buff *skb = alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp), GFP_ATOMIC);
unsigned long t = (jiffies / HZ * 1000000);
int len;
cisco_hdr *ch;
@@ -1644,7 +1636,7 @@ isdn_net_slarp_out(void)
* Got a packet from ISDN-Channel.
*/
static void
-isdn_net_receive(struct device *ndev, struct sk_buff *skb)
+isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
{
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
isdn_net_local *olp = lp; /* original 'lp' */
@@ -1793,7 +1785,7 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb)
}
static int
-my_eth_header(struct sk_buff *skb, struct device *dev, unsigned short type,
+my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
void *daddr, void *saddr, unsigned len)
{
struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
@@ -1838,7 +1830,7 @@ my_eth_header(struct sk_buff *skb, struct device *dev, unsigned short type,
*/
static int
-isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
+isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
void *daddr, void *saddr, unsigned plen)
{
isdn_net_local *lp = dev->priv;
@@ -1894,7 +1886,7 @@ isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
static int
isdn_net_rebuild_header(struct sk_buff *skb)
{
- struct device *dev = skb->dev;
+ struct net_device *dev = skb->dev;
isdn_net_local *lp = dev->priv;
int ret = 0;
@@ -1926,7 +1918,7 @@ isdn_net_rebuild_header(struct sk_buff *skb)
* Interface-setup. (called just after registering a new interface)
*/
static int
-isdn_net_init(struct device *ndev)
+isdn_net_init(struct net_device *ndev)
{
ushort max_hlhdr_len = 0;
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
@@ -2437,7 +2429,7 @@ isdn_net_force_dial(char *name)
* Allocate a new network-interface and initialize its data structures.
*/
char *
-isdn_net_new(char *name, struct device *master)
+isdn_net_new(char *name, struct net_device *master)
{
isdn_net_dev *netdev;
@@ -2466,8 +2458,8 @@ isdn_net_new(char *name, struct device *master)
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;
+ struct net_device *p = (((isdn_net_local *) master->priv)->slave);
+ struct net_device *q = master;
netdev->local->master = master;
/* Put device at end of slave-chain */
@@ -2928,7 +2920,7 @@ isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer)
/* for pre-bound channels, we need this extra check */
if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN;
strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN);
- phone->outgoing=USG_OUTGOING(idx);
+ phone->outgoing=USG_OUTGOING(dev->usage[idx]);
if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT;
return 0;
}
@@ -3004,7 +2996,7 @@ int
isdn_net_force_hangup(char *name)
{
isdn_net_dev *p = isdn_net_findif(name);
- struct device *q;
+ struct net_device *q;
if (p) {
if (p->local->isdn_device < 0)
diff --git a/drivers/isdn/isdn_net.h b/drivers/isdn/isdn_net.h
index 79d4ff615..bd48c592c 100644
--- a/drivers/isdn/isdn_net.h
+++ b/drivers/isdn/isdn_net.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.h,v 1.9 1999/04/12 12:33:27 fritz Exp $
+/* $Id: isdn_net.h,v 1.10 1999/08/22 20:26:06 calle Exp $
* header for Linux ISDN subsystem, network related functions (linklevel).
*
@@ -21,6 +21,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.h,v $
+ * Revision 1.10 1999/08/22 20:26:06 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
* Revision 1.9 1999/04/12 12:33:27 fritz
* Changes from 2.0 tree.
*
@@ -100,7 +106,7 @@ typedef struct cisco_slarp {
#define CISCO_SLARP_REQUEST 1
#define CISCO_SLARP_KEEPALIVE 2
-extern char *isdn_net_new(char *, struct device *);
+extern char *isdn_net_new(char *, struct net_device *);
extern char *isdn_net_newslave(char *);
extern int isdn_net_rm(char *);
extern int isdn_net_rmall(void);
@@ -112,13 +118,13 @@ extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *);
extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *);
extern int isdn_net_delphone(isdn_net_ioctl_phone *);
extern int isdn_net_find_icall(int, int, int, setup_parm);
-extern void isdn_net_hangup(struct device *);
+extern void isdn_net_hangup(struct net_device *);
extern void isdn_net_dial(void);
extern void isdn_net_autohup(void);
extern int isdn_net_force_hangup(char *);
extern int isdn_net_force_dial(char *);
extern isdn_net_dev *isdn_net_findif(char *);
-extern int isdn_net_send_skb(struct device *, isdn_net_local *,
+extern int isdn_net_send_skb(struct net_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 7bce66d44..78c71c7fe 100644
--- a/drivers/isdn/isdn_ppp.c
+++ b/drivers/isdn/isdn_ppp.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.47 1999/04/18 14:06:59 fritz Exp $
+/* $Id: isdn_ppp.c,v 1.52 1999/08/22 20:26:07 calle Exp $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -19,6 +19,26 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.c,v $
+ * Revision 1.52 1999/08/22 20:26:07 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.51 1999/08/18 16:19:17 hipp
+ * applied MPPP-resize-headroom patch
+ *
+ * Revision 1.50 1999/08/16 07:11:41 hipp
+ * Additional VJ decomp-buffer-size increased from 40 to 128
+ *
+ * Revision 1.49 1999/07/06 07:47:11 calle
+ * bugfix: dev_alloc_skb only reserve 16 bytes. We need to look at the
+ * hdrlen the driver want. So I changed dev_alloc_skb calls
+ * to alloc_skb and skb_reserve.
+ *
+ * Revision 1.48 1999/07/01 08:29:56 keil
+ * compatibility to 2.3 kernel
+ *
* Revision 1.47 1999/04/18 14:06:59 fritz
* Removed TIMRU stuff.
*
@@ -261,7 +281,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.47 $";
+char *isdn_ppp_revision = "$Revision: 1.52 $";
static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
static struct isdn_ppp_compressor *ipc_head = NULL;
@@ -430,7 +450,7 @@ isdn_ppp_wakeup_daemon(isdn_net_local * lp)
ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
-#if LINUX_VERSION_CODE < 131841
+#ifndef COMPAT_HAS_NEW_WAITQ
if (ippp_table[lp->ppp_slot]->wq)
#endif
wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
@@ -450,10 +470,10 @@ isdn_ppp_closewait(int slot)
return 0;
is = ippp_table[slot];
-#if LINUX_VERSION_CODE < 131841
- if (is->state && is->wq)
-#else
+#ifdef COMPAT_HAS_NEW_WAITQ
if (is->state)
+#else
+ if (is->state && is->wq)
#endif
wake_up_interruptible(&is->wq);
@@ -519,10 +539,10 @@ isdn_ppp_open(int min, struct file *file)
is->mru = 1524; /* MRU, default 1524 */
is->maxcid = 16; /* VJ: maxcid */
is->tk = current;
-#if LINUX_VERSION_CODE < 131841
- is->wq = NULL; /* read() wait queue */
-#else
+#ifdef COMPAT_HAS_NEW_WAITQ
init_waitqueue_head(&is->wq);
+#else
+ is->wq = NULL; /* read() wait queue */
#endif
is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
is->last = is->rq;
@@ -891,7 +911,7 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
is->last = bl->next;
restore_flags(flags);
-#if LINUX_VERSION_CODE < 131841
+#ifndef COMPAT_HAS_NEW_WAITQ
if (is->wq)
#endif
wake_up_interruptible(&is->wq);
@@ -983,13 +1003,21 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
lp->dialstate == 0 &&
(lp->flags & ISDN_NET_CONNECTED)) {
+ unsigned short hl;
int cnt;
struct sk_buff *skb;
- skb = dev_alloc_skb(count);
+ /*
+ * we need to reserve enought space in front of
+ * sk_buff. old call to dev_alloc_skb only reserved
+ * 16 bytes, now we are looking what the driver want
+ */
+ hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
+ skb = alloc_skb(hl+count, GFP_ATOMIC);
if (!skb) {
printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
return count;
}
+ skb_reserve(skb, hl);
if (copy_from_user(skb_put(skb, count), buf, count))
return -EFAULT;
if (is->debug & 0x40) {
@@ -1271,7 +1299,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
static void
isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
{
- struct device *dev = &net_dev->dev;
+ struct net_device *dev = &net_dev->dev;
struct ippp_struct *is = ippp_table[lp->ppp_slot];
if (is->debug & 0x10) {
@@ -1336,7 +1364,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
{
struct sk_buff *skb_old = skb;
int pkt_len;
- skb = dev_alloc_skb(skb_old->len + 40);
+ skb = dev_alloc_skb(skb_old->len + 128);
if (!skb) {
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
@@ -1345,7 +1373,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
return;
}
skb->dev = dev;
- skb_put(skb, skb_old->len + 40);
+ skb_put(skb, skb_old->len + 128);
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,
@@ -1399,9 +1427,17 @@ 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);
+ struct sk_buff *nskb = skb_realloc_headroom(skb, len);
+
+ if (!nskb) {
+ printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len);
dev_kfree_skb(skb);
- return NULL;
+ *skb_p = nskb;
+ return skb_push(nskb, len);
}
return skb_push(skb,len);
}
@@ -1416,9 +1452,9 @@ static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
*/
int
-isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
+isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
{
- struct device *mdev = ((isdn_net_local *) (dev->priv))->master; /* get master (for redundancy) */
+ struct net_device *mdev = ((isdn_net_local *) (netdev->priv))->master; /* get master (for redundancy) */
isdn_net_local *lp,*mlp;
isdn_net_dev *nd;
unsigned int proto = PPP_IP; /* 0x21 */
@@ -1427,8 +1463,8 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
if (mdev)
mlp = (isdn_net_local *) (mdev->priv);
else {
- mdev = dev;
- mlp = (isdn_net_local *) (dev->priv);
+ mdev = netdev;
+ mlp = (isdn_net_local *) (netdev->priv);
}
nd = mlp->netdev; /* get master lp */
ipts = ippp_table[mlp->ppp_slot];
@@ -1441,7 +1477,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
ipts->old_pa_dstaddr = mdev->pa_dstaddr;
#endif
if (ipts->debug & 0x1)
- printk(KERN_INFO "%s: IP frame delayed.\n", dev->name);
+ printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
return 1;
}
@@ -1506,12 +1542,19 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
#ifdef CONFIG_ISDN_PPP_VJ
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);
+ unsigned short hl;
+ /*
+ * we need to reserve enought space in front of
+ * sk_buff. old call to dev_alloc_skb only reserved
+ * 16 bytes, now we are looking what the driver want.
+ */
+ hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
+ new_skb = alloc_skb(hl+skb->len, GFP_ATOMIC);
if (new_skb) {
u_char *buf;
int pktlen;
+ skb_reserve(new_skb, hl);
new_skb->dev = skb->dev;
skb_put(new_skb, skb->len);
buf = skb->data;
@@ -1611,9 +1654,9 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot);
}
- if (isdn_net_send_skb(dev, lp, skb)) {
+ if (isdn_net_send_skb(netdev, lp, skb)) {
if (lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */
- printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", dev->name);
+ printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", netdev->name);
dev_kfree_skb(skb);
} else
lp->sav_skb = skb;
@@ -1985,7 +2028,7 @@ isdn_ppp_timer_timeout(void)
*/
static int
-isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct device *dev)
+isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
{
struct ppp_stats *res,
t;
@@ -2025,7 +2068,7 @@ isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct device *dev)
}
int
-isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
int error=0;
char *r;
@@ -2088,7 +2131,7 @@ isdn_ppp_dial_slave(char *name)
#ifdef CONFIG_ISDN_MPP
isdn_net_dev *ndev;
isdn_net_local *lp;
- struct device *sdev;
+ struct net_device *sdev;
if (!(ndev = isdn_net_findif(name)))
return 1;
@@ -2119,7 +2162,7 @@ isdn_ppp_hangup_slave(char *name)
#ifdef CONFIG_ISDN_MPP
isdn_net_dev *ndev;
isdn_net_local *lp;
- struct device *sdev;
+ struct net_device *sdev;
if (!(ndev = isdn_net_findif(name)))
return 1;
diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h
index 2c60240a5..1a1dcfcfe 100644
--- a/drivers/isdn/isdn_ppp.h
+++ b/drivers/isdn/isdn_ppp.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.h,v 1.13 1998/03/22 18:50:50 hipp Exp $
+/* $Id: isdn_ppp.h,v 1.14 1999/08/22 20:26:10 calle Exp $
* header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -19,6 +19,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.h,v $
+ * Revision 1.14 1999/08/22 20:26:10 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
* Revision 1.13 1998/03/22 18:50:50 hipp
* Added BSD Compression for syncPPP .. UNTESTED at the moment
*
@@ -78,9 +84,9 @@ extern int isdn_ppp_init(void);
extern void isdn_ppp_cleanup(void);
extern int isdn_ppp_free(isdn_net_local *);
extern int isdn_ppp_bind(isdn_net_local *);
-extern int isdn_ppp_xmit(struct sk_buff *, struct device *);
+extern int isdn_ppp_xmit(struct sk_buff *, struct net_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);
+extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
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 *);
diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c
index bfa895424..e502f90da 100644
--- a/drivers/isdn/isdn_tty.c
+++ b/drivers/isdn/isdn_tty.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.63 1999/04/12 12:33:39 fritz Exp $
+/* $Id: isdn_tty.c,v 1.73 1999/08/28 21:56:27 keil Exp $
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
@@ -20,6 +20,46 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.c,v $
+ * Revision 1.73 1999/08/28 21:56:27 keil
+ * misplaced #endif caused ttyI crash in 2.3.X
+ *
+ * Revision 1.72 1999/07/31 12:59:45 armin
+ * Added tty fax capabilities.
+ *
+ * Revision 1.71 1999/07/27 10:34:34 armin
+ * Fixed last change. Did not compile with AUDIO support off.
+ *
+ * Revision 1.70 1999/07/25 16:17:58 keil
+ * Fix Suspend/Resume
+ *
+ * Revision 1.69 1999/07/25 12:56:15 armin
+ * isdn_tty_at_cout() now queues the message if online and
+ * data is in queue or flip buffer is full.
+ * needed for fax connections.
+ *
+ * Revision 1.68 1999/07/11 17:51:51 armin
+ * Bugfix, "-" was missing for AT&L settings.
+ *
+ * Revision 1.67 1999/07/11 17:14:12 armin
+ * Added new layer 2 and 3 protocols for Fax and DSP functions.
+ * Moved "Add CPN to RING message" to new register S23,
+ * "Display message" is now correct on register S13 bit 7.
+ * New audio command AT+VDD implemented (deactivate DTMF decoder and
+ * activate possible existing hardware/DSP decoder).
+ * Moved some tty defines to .h file.
+ * Made whitespace possible in AT command line.
+ * Some AT-emulator output bugfixes.
+ * First Fax G3 implementations.
+ *
+ * Revision 1.66 1999/07/07 10:13:46 detabc
+ * remove unused messages
+ *
+ * Revision 1.65 1999/07/04 21:01:59 werner
+ * Added support for keypad and display (ported from 2.0)
+ *
+ * Revision 1.64 1999/07/01 08:30:00 keil
+ * compatibility to 2.3 kernel
+ *
* Revision 1.63 1999/04/12 12:33:39 fritz
* Changes from 2.0 tree.
*
@@ -61,24 +101,12 @@
* brute force fix to avoid Ugh's in isdn_tty_write()
* cleaned up some dead code
*
- * Revision 1.54 1998/06/07 00:20:13 fritz
- * abc cleanup.
*
- * Revision 1.53 1998/06/02 12:10:16 detabc
- * wegen einer einstweiliger verfuegung gegen DW ist zur zeit
- * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
*
* Revision 1.52 1998/03/19 13:18:21 keil
* Start of a CAPI like interface for supplementary Service
* first service: SUSPEND
*
- * Revision 1.51 1998/03/08 14:26:11 detabc
- * change kfree_skb to dev_kfree_skb
- * remove SET_SKB_FREE
- *
- * Revision 1.50 1998/03/08 13:14:28 detabc
- * abc-extension support for kernels > 2.1.x
- * first try (sorry experimental)
*
* Revision 1.49 1998/03/08 00:01:59 fritz
* Bugfix: Lowlevel module usage and channel usage were not
@@ -303,7 +331,6 @@ static int isdn_tty_edit_at(const char *, int, modem_info *, int);
static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int);
static void isdn_tty_modem_reset_regs(modem_info *, int);
static void isdn_tty_cmd_ATA(modem_info *);
-static void isdn_tty_at_cout(char *, modem_info *);
static void isdn_tty_flush_buffer(struct tty_struct *);
static void isdn_tty_modem_result(int, modem_info *);
#ifdef CONFIG_ISDN_AUDIO
@@ -321,64 +348,8 @@ static int bit2si[8] =
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.63 $";
-
-#define DLE 0x10
-#define ETX 0x03
-#define DC4 0x14
+char *isdn_tty_revision = "$Revision: 1.73 $";
-/*
- * 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_WAITC 7
-
-#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_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_RESRXT 13
-#define BIT_RESRXT 128
-
-#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
@@ -514,7 +485,7 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
#ifdef CONFIG_ISDN_AUDIO
ifmt = 1;
- if (info->vonline)
+ if ((info->vonline) && (!info->emu.vpar[4]))
isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
if ((info->vonline & 1) && (info->emu.vpar[1]))
isdn_audio_calc_silence(info, skb->data, skb->len, ifmt);
@@ -580,6 +551,15 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
ISDN_AUDIO_SKB_DLECOUNT(skb) =
isdn_tty_countDLE(skb->data, skb->len);
}
+#ifdef CONFIG_ISDN_TTY_FAX
+ else {
+ if (info->faxonline & 2) {
+ isdn_tty_fax_bitorder(info, skb);
+ ISDN_AUDIO_SKB_DLECOUNT(skb) =
+ isdn_tty_countDLE(skb->data, skb->len);
+ }
+ }
+#endif
#endif
/* Try to deliver directly via tty-flip-buf if queue is empty */
save_flags(flags);
@@ -909,6 +889,35 @@ isdn_tty_modem_ncarrier(modem_info * info)
}
}
+/*
+ * return the usage calculated by si and layer 2 protocol
+ */
+int
+isdn_calc_usage(int si, int l2)
+{
+ int usg = ISDN_USAGE_MODEM;
+
+#ifdef CONFIG_ISDN_AUDIO
+ if (si == 1) {
+ switch(l2) {
+ case ISDN_PROTO_L2_MODEM:
+ usg = ISDN_USAGE_MODEM;
+ break;
+#ifdef CONFIG_ISDN_TTY_FAX
+ case ISDN_PROTO_L2_FAX:
+ usg = ISDN_USAGE_FAX;
+ break;
+#endif
+ case ISDN_PROTO_L2_TRANS:
+ default:
+ usg = ISDN_USAGE_VOICE;
+ break;
+ }
+ }
+#endif
+ return(usg);
+}
+
/* isdn_tty_dial() performs dialing of a tty an the necessary
* setup of the lower levels before that.
*/
@@ -928,8 +937,14 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
si = bit2si[j];
break;
}
+ usg = isdn_calc_usage(si, l2);
#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
+ if ((si == 1) &&
+ (l2 != ISDN_PROTO_L2_MODEM)
+#ifdef CONFIG_ISDN_TTY_FAX
+ && (l2 != ISDN_PROTO_L2_FAX)
+#endif
+ ) {
l2 = ISDN_PROTO_L2_TRANS;
usg = ISDN_USAGE_VOICE;
}
@@ -967,6 +982,12 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL3;
cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (l2 == ISDN_PROTO_L2_FAX) {
+ cmd.parm.fax = info->fax;
+ info->fax->direction = ISDN_TTY_FAX_CONN_OUT;
+ }
+#endif
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
@@ -989,7 +1010,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
* ISDN-line (hangup). The usage-status is cleared
* and some cleanup is done also.
*/
-static void
+void
isdn_tty_modem_hup(modem_info * info, int local)
{
isdn_ctrl cmd;
@@ -1010,6 +1031,12 @@ isdn_tty_modem_hup(modem_info * info, int local)
}
#ifdef CONFIG_ISDN_AUDIO
info->vonline = 0;
+#ifdef CONFIG_ISDN_TTY_FAX
+ info->faxonline = 0;
+ info->fax->phase = ISDN_FAX_PHASE_IDLE;
+#endif
+ info->emu.vpar[4] = 0;
+ info->emu.vpar[5] = 8;
if (info->dtmf_state) {
kfree(info->dtmf_state);
info->dtmf_state = NULL;
@@ -1041,9 +1068,8 @@ isdn_tty_modem_hup(modem_info * info, int local)
}
isdn_all_eaz(info->isdn_driver, info->isdn_channel);
info->emu.mdmreg[REG_RINGCNT] = 0;
- usage = ((info->emu.mdmreg[REG_SI1I] != 1) ||
- (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ?
- ISDN_USAGE_MODEM : ISDN_USAGE_VOICE;
+ usage = isdn_calc_usage(info->emu.mdmreg[REG_SI1I],
+ info->emu.mdmreg[REG_L2PROT]);
isdn_free_channel(info->isdn_driver, info->isdn_channel,
usage);
}
@@ -1130,8 +1156,14 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
si = bit2si[j];
break;
}
+ usg = isdn_calc_usage(si, l2);
#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
+ if ((si == 1) &&
+ (l2 != ISDN_PROTO_L2_MODEM)
+#ifdef CONFIG_ISDN_TTY_FAX
+ && (l2 != ISDN_PROTO_L2_FAX)
+#endif
+ ) {
l2 = ISDN_PROTO_L2_TRANS;
usg = ISDN_USAGE_VOICE;
}
@@ -1184,11 +1216,11 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
cmd.parm.cmsg.para[5] = l;
strncpy(&cmd.parm.cmsg.para[6], id, l);
cmd.command =CAPI_PUT_MESSAGE;
-/* info->dialing = 1;
- strcpy(dev->num[i], n);
+ info->dialing = 1;
+// strcpy(dev->num[i], n);
isdn_info_update();
-*/
isdn_command(&cmd);
+ isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
}
}
@@ -1218,8 +1250,14 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
si = bit2si[j];
break;
}
+ usg = isdn_calc_usage(si, l2);
#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
+ if ((si == 1) &&
+ (l2 != ISDN_PROTO_L2_MODEM)
+#ifdef CONFIG_ISDN_TTY_FAX
+ && (l2 != ISDN_PROTO_L2_FAX)
+#endif
+ ) {
l2 = ISDN_PROTO_L2_TRANS;
usg = ISDN_USAGE_VOICE;
}
@@ -1863,11 +1901,11 @@ isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
static int
isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
{
-#if LINUX_VERSION_CODE < 131841
+#ifdef COMPAT_HAS_NEW_WAITQ
+ DECLARE_WAITQUEUE(wait, NULL);
+#else
struct wait_queue wait =
{current, NULL};
-#else
- DECLARE_WAITQUEUE(wait, NULL);
#endif
int do_clocal = 0;
unsigned long flags;
@@ -1946,7 +1984,7 @@ isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *
restore_flags(flags);
info->blocked_open++;
while (1) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(info->flags & ISDN_ASYNC_INITIALIZED)) {
#ifdef MODEM_DO_RESTART
@@ -2191,6 +2229,7 @@ isdn_tty_reset_profile(atemu * m)
m->profile[18] = 4;
m->profile[19] = 0;
m->profile[20] = 0;
+ m->profile[23] = 0;
m->pmsn[0] = '\0';
m->plmsn[0] = '\0';
}
@@ -2203,6 +2242,42 @@ isdn_tty_modem_reset_vpar(atemu * m)
m->vpar[1] = 0; /* Silence detection level (0 = none ) */
m->vpar[2] = 70; /* Silence interval (7 sec. ) */
m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */
+ m->vpar[4] = 0; /* DTMF detection level (0 = softcode ) */
+ m->vpar[5] = 8; /* DTMF interval (8 * 5 ms. ) */
+}
+#endif
+
+#ifdef CONFIG_ISDN_TTY_FAX
+static void
+isdn_tty_modem_reset_faxpar(modem_info * info)
+{
+ T30_s *f = info->fax;
+
+ f->code = 0;
+ f->phase = ISDN_FAX_PHASE_IDLE;
+ f->direction = 0;
+ f->resolution = 1; /* fine */
+ f->rate = 5; /* 14400 bit/s */
+ f->width = 0;
+ f->length = 0;
+ f->compression = 0;
+ f->ecm = 0;
+ f->binary = 0;
+ f->scantime = 0;
+ memset(&f->id[0], 32, FAXIDLEN - 1);
+ f->id[FAXIDLEN - 1] = 0;
+ f->badlin = 0;
+ f->badmul = 0;
+ f->bor = 0;
+ f->nbc = 0;
+ f->cq = 0;
+ f->cr = 0;
+ f->ctcrty = 0;
+ f->minsp = 0;
+ f->phcto = 30;
+ f->rel = 0;
+ memset(&f->pollid[0], 32, FAXIDLEN - 1);
+ f->pollid[FAXIDLEN - 1] = 0;
}
#endif
@@ -2219,6 +2294,9 @@ isdn_tty_modem_reset_regs(modem_info * info, int force)
#ifdef CONFIG_ISDN_AUDIO
isdn_tty_modem_reset_vpar(m);
#endif
+#ifdef CONFIG_ISDN_TTY_FAX
+ isdn_tty_modem_reset_faxpar(info);
+#endif
m->mdmcmdl = 0;
}
@@ -2291,10 +2369,16 @@ isdn_tty_modem_init(void)
}
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
info = &m->info[i];
-#if LINUX_VERSION_CODE < 131841
- info->write_sem = MUTEX;
-#else
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) {
+ printk(KERN_ERR "Could not allocate fax t30-buffer\n");
+ return -3;
+ }
+#endif
+#ifdef COMPAT_HAS_NEW_WAITQ
init_MUTEX(&info->write_sem);
+#else
+ info->write_sem = MUTEX;
#endif
sprintf(info->last_cause, "0000");
sprintf(info->last_num, "none");
@@ -2312,12 +2396,12 @@ isdn_tty_modem_init(void)
info->blocked_open = 0;
info->callout_termios = m->cua_modem.init_termios;
info->normal_termios = m->tty_modem.init_termios;
-#if LINUX_VERSION_CODE < 131841
- info->open_wait = 0;
- info->close_wait = 0;
-#else
+#ifdef COMPAT_HAS_NEW_WAITQ
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
+#else
+ info->open_wait = 0;
+ info->close_wait = 0;
#endif
info->isdn_driver = -1;
info->isdn_channel = -1;
@@ -2371,8 +2455,15 @@ isdn_tty_match_icall(char *cid, atemu *emu, int di)
break;
}
return ret;
- } else
- return isdn_wildmat(cid, isdn_map_eaz2msn(emu->msn, di));
+ } else {
+ int tmp;
+ tmp = isdn_wildmat(cid, isdn_map_eaz2msn(emu->msn, di));
+#ifdef ISDN_DEBUG_MODEM_ICALL
+ printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n",
+ isdn_map_eaz2msn(emu->msn, di), tmp);
+#endif
+ return tmp;
+ }
}
/*
@@ -2424,7 +2515,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
(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");
+ printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
info->flags, info->isdn_driver, info->isdn_channel,
dev->usage[idx]);
@@ -2446,8 +2537,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
info->drv_index = idx;
dev->m_idx[idx] = info->line;
dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[idx] |= ((si1 != 1) || (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ?
- ISDN_USAGE_MODEM : ISDN_USAGE_VOICE;
+ dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]);
strcpy(dev->num[idx], nr);
strcpy(info->emu.cpn, eaz);
info->emu.mdmreg[REG_SI1I] = si2bit[si1];
@@ -2514,6 +2604,19 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
/* Signal cause to tty-device */
strncpy(info->last_cause, c->parm.num, 5);
return 1;
+ case ISDN_STAT_DISPLAY:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_DISPLAY ttyI%d\n", info->line);
+#endif
+ /* Signal display to tty-device */
+ if ((info->emu.mdmreg[REG_DISPLAY] & BIT_DISPLAY) &&
+ !(info->emu.mdmreg[REG_RESPNUM] & BIT_RESPNUM)) {
+ isdn_tty_at_cout("\r\n", info);
+ isdn_tty_at_cout("DISPLAY: ", info);
+ isdn_tty_at_cout(c->parm.display, info);
+ isdn_tty_at_cout("\r\n", info);
+ }
+ return 1;
case ISDN_STAT_DCONN:
#ifdef ISDN_TTY_STAT_DEBUG
printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
@@ -2612,6 +2715,27 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
}
}
return 1;
+#ifdef CONFIG_ISDN_TTY_FAX
+ case ISDN_STAT_FAXIND:
+ if (TTY_IS_ACTIVE(info)) {
+ isdn_tty_fax_command(info);
+ }
+ break;
+#endif
+#ifdef CONFIG_ISDN_AUDIO
+ case ISDN_STAT_AUDIO:
+ if (TTY_IS_ACTIVE(info)) {
+ switch(c->parm.num[0]) {
+ case ISDN_AUDIO_DTMF:
+ if (info->vonline) {
+ isdn_audio_put_dle_code(info,
+ c->parm.num[1]);
+ }
+ break;
+ }
+ }
+ break;
+#endif
}
}
return 0;
@@ -2621,13 +2745,13 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
Modem-Emulator-Routines
*********************************************************************/
-#define cmdchar(c) ((c>' ')&&(c<=0x7f))
+#define cmdchar(c) ((c>=' ')&&(c<=0x7f))
/*
* Put a message from the AT-emulator into receive-buffer of tty,
* convert CR, LF, and BS to values in modem-registers 3, 4 and 5.
*/
-static void
+void
isdn_tty_at_cout(char *msg, modem_info * info)
{
struct tty_struct *tty;
@@ -2635,6 +2759,8 @@ isdn_tty_at_cout(char *msg, modem_info * info)
char *p;
char c;
ulong flags;
+ struct sk_buff *skb = 0;
+ char *sp = 0;
if (!msg) {
printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
@@ -2643,6 +2769,34 @@ isdn_tty_at_cout(char *msg, modem_info * info)
save_flags(flags);
cli();
tty = info->tty;
+ if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
+ restore_flags(flags);
+ return;
+ }
+
+ /* use queue instead of direct flip, if online and */
+ /* data is in queue or flip buffer is full */
+ if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) ||
+ (!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel])))) {
+ skb = alloc_skb(strlen(msg)
+#ifdef CONFIG_ISDN_AUDIO
+ + sizeof(isdn_audio_skb)
+#endif
+ , GFP_ATOMIC);
+ if (!skb) {
+ restore_flags(flags);
+ return;
+ }
+#ifdef CONFIG_ISDN_AUDIO
+ skb_reserve(skb, sizeof(isdn_audio_skb));
+#endif
+ sp = skb_put(skb, strlen(msg));
+#ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
+ ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+ }
+
for (p = msg; *p; p++) {
switch (*p) {
case '\r':
@@ -2657,16 +2811,26 @@ isdn_tty_at_cout(char *msg, modem_info * info)
default:
c = *p;
}
- if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
- restore_flags(flags);
- return;
+ if (skb) {
+ *sp++ = c;
+ } else {
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ break;
+ tty_insert_flip_char(tty, c, 0);
}
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- break;
- tty_insert_flip_char(tty, c, 0);
}
- restore_flags(flags);
- queue_task(&tty->flip.tqueue, &tq_timer);
+ if (skb) {
+ __skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb);
+ dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len;
+ restore_flags(flags);
+ /* Schedule dequeuing */
+ if ((dev->modempoll) && (info->rcvsched))
+ isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+
+ } else {
+ restore_flags(flags);
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ }
}
/*
@@ -2847,7 +3011,7 @@ isdn_tty_modem_result(int code, modem_info * info)
break;
case 2:
/* Append CPN, if enabled */
- if ((m->mdmreg[REG_RESRXT] & BIT_RESRXT)) {
+ if ((m->mdmreg[REG_CPN] & BIT_CPN)) {
sprintf(s, "/%s", m->cpn);
isdn_tty_at_cout(s, info);
}
@@ -2954,8 +3118,9 @@ isdn_tty_getdial(char *p, char *q,int cnt)
int limit=39; /* MUST match the size in isdn_tty_parse to avoid
buffer overflow */
- while (strchr("0123456789,#.*WPTS-", *p) && *p && --cnt>0) {
- if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first))
+ while (strchr(" 0123456789,#.*WPTS-", *p) && *p && --cnt>0) {
+ if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) ||
+ (*p == '*') || (*p == '#'))
*q++ = *p;
p++;
if(!--limit)
@@ -3008,6 +3173,9 @@ isdn_tty_report(modem_info * info)
case ISDN_PROTO_L2_MODEM:
isdn_tty_at_cout("modem", info);
break;
+ case ISDN_PROTO_L2_FAX:
+ isdn_tty_at_cout("fax", info);
+ break;
default:
isdn_tty_at_cout("unknown", info);
break;
@@ -3107,8 +3275,8 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
/* &L -Set Numbers to listen on */
p[0]++;
i = 0;
- while ((strchr("0123456789,*[]?;", *p[0])) &&
- (i < ISDN_LMSNLEN))
+ while ((strchr("0123456789,-*[]?;", *p[0])) &&
+ (i < ISDN_LMSNLEN) && *p[0])
m->lmsn[i++] = *p[0]++;
m->lmsn[i] = '\0';
break;
@@ -3264,7 +3432,7 @@ isdn_tty_cmd_ATS(char **p, modem_info * info)
int bval;
mreg = isdn_getnum(p);
- if (mreg < 0 || mreg > ISDN_MODEM_ANZREG)
+ if (mreg < 0 || mreg >= ISDN_MODEM_ANZREG)
PARSE_ERROR1;
switch (*p[0]) {
case '=':
@@ -3338,7 +3506,7 @@ isdn_tty_cmd_ATA(modem_info * info)
/* If more than one bit set in reg18, autoselect Layer2 */
if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
if (m->mdmreg[REG_SI1I] == 1) {
- if (l2 != ISDN_PROTO_L2_MODEM)
+ if ((l2 != ISDN_PROTO_L2_MODEM) && (l2 != ISDN_PROTO_L2_FAX))
l2 = ISDN_PROTO_L2_TRANS;
} else
l2 = ISDN_PROTO_L2_X75I;
@@ -3352,6 +3520,12 @@ isdn_tty_cmd_ATA(modem_info * info)
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL3;
cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (l2 == ISDN_PROTO_L2_FAX) {
+ cmd.parm.fax = info->fax;
+ info->fax->direction = ISDN_TTY_FAX_CONN_IN;
+ }
+#endif
isdn_command(&cmd);
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
@@ -3372,7 +3546,6 @@ static int
isdn_tty_cmd_PLUSF(char **p, modem_info * info)
{
atemu *m = &info->emu;
- int par;
char rs[20];
if (!strncmp(p[0], "CLASS", 5)) {
@@ -3382,6 +3555,10 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
p[0]++;
sprintf(rs, "\r\n%d",
(m->mdmreg[REG_SI1] & 1) ? 8 : 0);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX)
+ sprintf(rs, "\r\n2");
+#endif
isdn_tty_at_cout(rs, info);
break;
case '=':
@@ -3389,23 +3566,37 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
switch (*p[0]) {
case '0':
p[0]++;
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
+ m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
m->mdmreg[REG_SI1] = 4;
info->xmit_size =
m->mdmreg[REG_PSIZE] * 16;
break;
+#ifdef CONFIG_ISDN_TTY_FAX
case '2':
- printk(KERN_DEBUG "isdn_tty: FCLASS=2\n");
p[0]++;
+ m->mdmreg[REG_SI1] = 1;
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
+ m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FAX;
+ info->xmit_size =
+ m->mdmreg[REG_PSIZE] * 16;
break;
+#endif
case '8':
p[0]++;
+ /* L2 will change on dialout with si=1 */
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
+ m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
m->mdmreg[REG_SI1] = 5;
info->xmit_size = VBUF;
break;
case '?':
p[0]++;
- isdn_tty_at_cout("\r\n0,2,8",
- info);
+#ifdef CONFIG_ISDN_TTY_FAX
+ isdn_tty_at_cout("\r\n0,2,8", info);
+#else
+ isdn_tty_at_cout("\r\n0,8", info);
+#endif
break;
default:
PARSE_ERROR1;
@@ -3416,115 +3607,11 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
}
return 0;
}
- if (!strncmp(p[0], "AA", 2)) {
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d",
- m->mdmreg[REG_RINGATA]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- 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]);
+#ifdef CONFIG_ISDN_TTY_FAX
+ return (isdn_tty_cmd_PLUSF_FAX(p, info));
+#else
PARSE_ERROR1;
+#endif
}
/*
@@ -3534,8 +3621,9 @@ static int
isdn_tty_cmd_PLUSV(char **p, modem_info * info)
{
atemu *m = &info->emu;
+ isdn_ctrl cmd;
static char *vcmd[] =
- {"NH", "IP", "LS", "RX", "SD", "SM", "TX", NULL};
+ {"NH", "IP", "LS", "RX", "SD", "SM", "TX", "DD", NULL};
int i;
int par1;
int par2;
@@ -3711,9 +3799,9 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info)
info);
isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
info);
- isdn_tty_at_cout("5;ALAW;8;0;(8000)",
+ isdn_tty_at_cout("5;ALAW;8;0;(8000)\r\n",
info);
- isdn_tty_at_cout("6;ULAW;8;0;(8000)",
+ isdn_tty_at_cout("6;ULAW;8;0;(8000)\r\n",
info);
break;
default:
@@ -3752,6 +3840,52 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info)
isdn_tty_modem_result(1, info);
return 0;
break;
+ case 7:
+ /* AT+VDD - DTMF detection */
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n<%d>,<%d>",
+ m->vpar[4],
+ m->vpar[5]);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if ((*p[0]>='0') && (*p[0]<='9')) {
+ if (info->online != 1)
+ PARSE_ERROR1;
+ par1 = isdn_getnum(p);
+ if ((par1 < 0) || (par1 > 15))
+ PARSE_ERROR1;
+ if (*p[0] != ',')
+ PARSE_ERROR1;
+ p[0]++;
+ par2 = isdn_getnum(p);
+ if ((par2 < 0) || (par2 > 255))
+ PARSE_ERROR1;
+ m->vpar[4] = par1;
+ m->vpar[5] = par2;
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_AUDIO;
+ cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8);
+ cmd.parm.num[0] = par1;
+ cmd.parm.num[1] = par2;
+ isdn_command(&cmd);
+ break;
+ } else
+ if (*p[0] == '?') {
+ p[0]++;
+ isdn_tty_at_cout("\r\n<0-15>,<0-255>",
+ info);
+ break;
+ } else
+ PARSE_ERROR1;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
default:
PARSE_ERROR1;
}
@@ -3774,6 +3908,9 @@ isdn_tty_parse_at(modem_info * info)
#endif
for (p = &m->mdmcmd[2]; *p;) {
switch (*p) {
+ case ' ':
+ p++;
+ break;
case 'A':
/* A - Accept incoming call */
p++;
@@ -3919,8 +4056,10 @@ isdn_tty_parse_at(modem_info * info)
isdn_tty_suspend(ds, info, m);
break;
case 'R': /* RESUME */
+ p++;
isdn_tty_get_msnstr(ds, &p);
isdn_tty_resume(ds, info, m);
+ break;
case 'M': /* MESSAGE */
p++;
isdn_tty_send_msg(info, m, p);
@@ -3981,7 +4120,7 @@ isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
eb[1] = 0;
isdn_tty_at_cout(eb, info);
}
- if (m->mdmcmdl >= 2)
+ if ((m->mdmcmdl >= 2) && (!(strncmp(m->mdmcmd, "AT", 2))))
isdn_tty_parse_at(info);
m->mdmcmdl = 0;
continue;
@@ -4007,15 +4146,16 @@ isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
switch (m->mdmcmdl) {
case 0:
if (c == 'A')
- m->mdmcmd[m->mdmcmdl++] = c;
+ m->mdmcmd[m->mdmcmdl] = c;
break;
case 1:
if (c == 'T')
- m->mdmcmd[m->mdmcmdl++] = c;
+ m->mdmcmd[m->mdmcmdl] = c;
break;
default:
- m->mdmcmd[m->mdmcmdl++] = c;
+ m->mdmcmd[m->mdmcmdl] = c;
}
+ m->mdmcmd[++m->mdmcmdl] = 0;
}
}
}
diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h
index 663648e58..87acd7be2 100644
--- a/drivers/isdn/isdn_tty.h
+++ b/drivers/isdn/isdn_tty.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.h,v 1.13 1999/04/12 12:33:46 fritz Exp $
+/* $Id: isdn_tty.h,v 1.16 1999/08/22 20:26:10 calle Exp $
* header for Linux ISDN subsystem, tty related functions (linklevel).
*
@@ -20,6 +20,26 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.h,v $
+ * Revision 1.16 1999/08/22 20:26:10 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.15 1999/07/31 12:59:48 armin
+ * Added tty fax capabilities.
+ *
+ * Revision 1.14 1999/07/11 17:14:15 armin
+ * Added new layer 2 and 3 protocols for Fax and DSP functions.
+ * Moved "Add CPN to RING message" to new register S23,
+ * "Display message" is now correct on register S13 bit 7.
+ * New audio command AT+VDD implemented (deactivate DTMF decoder and
+ * activate possible existing hardware/DSP decoder).
+ * Moved some tty defines to .h file.
+ * Made whitespace possible in AT command line.
+ * Some AT-emulator output bugfixes.
+ * First Fax G3 implementations.
+ *
* Revision 1.13 1999/04/12 12:33:46 fritz
* Changes from 2.0 tree.
*
@@ -72,6 +92,69 @@
*
*/
+#include <linux/config.h>
+
+#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_WAITC 7
+
+#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_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_DISPLAY 13
+#define BIT_DISPLAY 128
+
+#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
+
+#define REG_CPN 23
+#define BIT_CPN 1
+
extern void isdn_tty_modem_escape(void);
extern void isdn_tty_modem_ring(void);
extern void isdn_tty_carrier_timeout(void);
@@ -83,3 +166,10 @@ extern void isdn_tty_cleanup_xmit(modem_info *);
extern int isdn_tty_stat_callback(int, isdn_ctrl *);
extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
extern int isdn_tty_capi_facility(capi_msg *cm);
+extern void isdn_tty_at_cout(char *, modem_info *);
+extern void isdn_tty_modem_hup(modem_info *, int);
+#ifdef CONFIG_ISDN_TTY_FAX
+extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
+extern int isdn_tty_fax_command(modem_info *);
+extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
+#endif
diff --git a/drivers/isdn/isdn_ttyfax.c b/drivers/isdn/isdn_ttyfax.c
new file mode 100644
index 000000000..7665aa812
--- /dev/null
+++ b/drivers/isdn/isdn_ttyfax.c
@@ -0,0 +1,1206 @@
+/* $Id: isdn_ttyfax.c,v 1.3 1999/08/22 20:26:12 calle Exp $
+ * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
+ *
+ * Copyright 1999 by Armin Schindler (mac@melware.de)
+ * Copyright 1999 by Ralf Spachmann (mel@melware.de)
+ * Copyright 1999 by Cytronics & Melware
+ *
+ * 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_ttyfax.c,v $
+ * Revision 1.3 1999/08/22 20:26:12 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.2 1999/08/05 10:36:10 armin
+ * Bugfix: kernel oops on getting revision.
+ *
+ * Revision 1.1 1999/07/31 12:59:50 armin
+ * Added tty fax capabilities.
+ *
+ *
+ */
+
+#undef ISDN_TTY_FAX_STAT_DEBUG
+#undef ISDN_TTY_FAX_CMD_DEBUG
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/isdn.h>
+#include "isdn_common.h"
+#include "isdn_tty.h"
+#include "isdn_ttyfax.h"
+
+
+static char *isdn_tty_fax_revision = "$Revision: 1.3 $";
+
+#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
+
+static char *
+isdn_getrev(const char *revision)
+{
+ char *rev;
+ char *p;
+
+ if ((p = strchr(revision, ':'))) {
+ rev = p + 2;
+ p = strchr(rev, '$');
+ *--p = 0;
+ } else
+ rev = "???";
+ return rev;
+}
+
+
+/*
+ * Fax Class 2 Modem results
+ *
+ */
+static void isdn_tty_fax_modem_result(int code, modem_info * info)
+{
+ atemu *m = &info->emu;
+ T30_s *f = info->fax;
+ char rs[50];
+ char rss[50];
+ char *rp;
+ int i;
+ static char *msg[] =
+ {"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:",
+ "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:",
+ "+FCFR", "+FPTS:", "+FET:" };
+
+
+ isdn_tty_at_cout("\r\n", info);
+ isdn_tty_at_cout(msg[code], info);
+
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax send %s on ttyI%d\n",
+ msg[code], info->line);
+#endif
+ switch (code) {
+ case 0: /* OK */
+ break;
+ case 1: /* ERROR */
+ break;
+ case 2: /* +FCON */
+ /* Append CPN, if enabled */
+ if ((m->mdmreg[REG_CPN] & BIT_CPN) &&
+ (!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) {
+ sprintf(rs, "/%s", m->cpn);
+ isdn_tty_at_cout(rs, info);
+ }
+ info->online = 1;
+ f->fet = 0;
+ if (f->phase == ISDN_FAX_PHASE_A)
+ f->phase = ISDN_FAX_PHASE_B;
+ break;
+ case 3: /* +FCSI */
+ case 8: /* +FTSI */
+ sprintf(rs, "\"%s\"", f->r_id);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case 4: /* +FDIS */
+ rs[0] = 0;
+ rp = &f->r_resolution;
+ for(i = 0; i < 8; i++) {
+ sprintf(rss, "%c%s", rp[i] + 48,
+ (i < 7) ? "," : "");
+ strcat(rs, rss);
+ }
+ isdn_tty_at_cout(rs, info);
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n",
+ rs, info->line);
+#endif
+ break;
+ case 5: /* +FHNG */
+ sprintf(rs, "%d", f->code);
+ isdn_tty_at_cout(rs, info);
+ info->faxonline = 0;
+ break;
+ case 6: /* +FDCS */
+ rs[0] = 0;
+ rp = &f->r_resolution;
+ for(i = 0; i < 8; i++) {
+ sprintf(rss, "%c%s", rp[i] + 48,
+ (i < 7) ? "," : "");
+ strcat(rs, rss);
+ }
+ isdn_tty_at_cout(rs, info);
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n",
+ rs, info->line);
+#endif
+ break;
+ case 7: /* CONNECT */
+ info->faxonline |= 2;
+ break;
+ case 9: /* FCFR */
+ break;
+ case 10: /* FPTS */
+ isdn_tty_at_cout("1", info);
+ break;
+ case 11: /* FET */
+ sprintf(rs, "%d", f->fet);
+ isdn_tty_at_cout(rs, info);
+ break;
+ }
+
+ isdn_tty_at_cout("\r\n", info);
+
+ switch (code) {
+ case 7: /* CONNECT */
+ info->online = 2;
+ if (info->faxonline & 1) {
+ sprintf(rs, "%c", XON);
+ isdn_tty_at_cout(rs, info);
+ }
+ break;
+ }
+}
+
+int
+isdn_tty_fax_command(modem_info * info)
+{
+ T30_s *f = info->fax;
+ char rs[10];
+
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n",
+ f->r_code, info->line);
+#endif
+ switch(f->r_code) {
+ case ISDN_TTY_FAX_FCON:
+ info->faxonline = 1;
+ isdn_tty_fax_modem_result(2, info); /* +FCON */
+ return(0);
+ case ISDN_TTY_FAX_FCON_I:
+ info->faxonline = 16;
+ isdn_tty_fax_modem_result(2, info); /* +FCON */
+ return(0);
+ case ISDN_TTY_FAX_RID:
+ if (info->faxonline & 1)
+ isdn_tty_fax_modem_result(3, info); /* +FCSI */
+ if (info->faxonline & 16)
+ isdn_tty_fax_modem_result(8, info); /* +FTSI */
+ return(0);
+ case ISDN_TTY_FAX_DIS:
+ isdn_tty_fax_modem_result(4, info); /* +FDIS */
+ return(0);
+ case ISDN_TTY_FAX_HNG:
+ if (f->phase == ISDN_FAX_PHASE_C) {
+ if (f->direction == ISDN_TTY_FAX_CONN_IN) {
+ sprintf(rs, "%c%c", DLE, ETX);
+ isdn_tty_at_cout(rs, info);
+ } else {
+ sprintf(rs, "%c", 0x18);
+ isdn_tty_at_cout(rs, info);
+ }
+ info->faxonline &= ~2; /* leave data mode */
+ info->online = 1;
+ }
+ f->phase = ISDN_FAX_PHASE_E;
+ isdn_tty_fax_modem_result(5, info); /* +FHNG */
+ isdn_tty_fax_modem_result(0, info); /* OK */
+ return(0);
+ case ISDN_TTY_FAX_DCS:
+ isdn_tty_fax_modem_result(6, info); /* +FDCS */
+ isdn_tty_fax_modem_result(7, info); /* CONNECT */
+ f->phase = ISDN_FAX_PHASE_C;
+ return(0);
+ case ISDN_TTY_FAX_TRAIN_OK:
+ isdn_tty_fax_modem_result(6, info); /* +FDCS */
+ isdn_tty_fax_modem_result(0, info); /* OK */
+ return(0);
+ case ISDN_TTY_FAX_SENT:
+ isdn_tty_fax_modem_result(0, info); /* OK */
+ return(0);
+ case ISDN_TTY_FAX_CFR:
+ isdn_tty_fax_modem_result(9, info); /* +FCFR */
+ return(0);
+ case ISDN_TTY_FAX_ET:
+ sprintf(rs, "%c%c", DLE, ETX);
+ isdn_tty_at_cout(rs, info);
+ isdn_tty_fax_modem_result(10, info); /* +FPTS */
+ isdn_tty_fax_modem_result(11, info); /* +FET */
+ isdn_tty_fax_modem_result(0, info); /* OK */
+ info->faxonline &= ~2; /* leave data mode */
+ info->online = 1;
+ f->phase = ISDN_FAX_PHASE_D;
+ return(0);
+ case ISDN_TTY_FAX_PTS:
+ isdn_tty_fax_modem_result(10, info); /* +FPTS */
+ if (f->direction == ISDN_TTY_FAX_CONN_OUT) {
+ if (f->fet == 1)
+ f->phase = ISDN_FAX_PHASE_B;
+ if (f->fet == 0)
+ isdn_tty_fax_modem_result(0, info); /* OK */
+ }
+ return(0);
+ case ISDN_TTY_FAX_EOP:
+ info->faxonline &= ~2; /* leave data mode */
+ info->online = 1;
+ f->phase = ISDN_FAX_PHASE_D;
+ return(0);
+
+ }
+ return(-1);
+}
+
+
+void
+isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
+{
+ __u8 LeftMask;
+ __u8 RightMask;
+ __u8 fBit;
+ __u8 Data;
+ int i;
+
+ if (!info->fax->bor) {
+ for(i = 0; i < skb->len; i++) {
+ Data = skb->data[i];
+ for (
+ LeftMask = 0x80, RightMask = 0x01;
+ LeftMask > RightMask;
+ LeftMask >>= 1, RightMask <<= 1
+ ) {
+ fBit = (Data & LeftMask);
+ if (Data & RightMask)
+ Data |= LeftMask;
+ else
+ Data &= ~LeftMask;
+ if (fBit)
+ Data |= RightMask;
+ else
+ Data &= ~RightMask;
+
+ }
+ skb->data[i] = Data;
+ }
+ }
+}
+
+/*
+ * Parse AT+F.. FAX class 2 commands
+ */
+
+int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
+{
+ atemu *m = &info->emu;
+ T30_s *f = info->fax;
+ isdn_ctrl cmd;
+ int par;
+ char rs[50];
+ char rss[50];
+ int maxdccval[]={1,5,2,2,3,2,0,7};
+
+ /* FAA still unchanged */
+ if (!strncmp(p[0], "AA", 2)) { /* TODO */
+ p[0] += 2;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d", 0);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */
+ if (!strncmp(p[0], "BADLIN", 6)) {
+ p[0] += 6;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",f->badlin);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0-255");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ f->badlin = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* BADMUL=value - dummy 0=disable errorchk disabled (treshold multiplier) */
+ if (!strncmp(p[0], "BADMUL", 6)){
+ p[0] +=6;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d", f->badmul);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0-255");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ f->badmul = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* BOR=n - Phase C bit order, 0=direct, 1=reverse */
+ if (!strncmp(p[0], "BOR", 3)){
+ p[0] +=3;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d", f->bor);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0,1");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 1))
+ PARSE_ERROR1;
+ f->bor = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* NBC=n - No Best Capabilities */
+ if (!strncmp(p[0], "NBC", 3)){
+ p[0] +=3;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d", f->nbc);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0,1");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 1))
+ PARSE_ERROR1;
+ f->nbc = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* BUF? - Readonly buffersize readout */
+ if (!strncmp(p[0], "BUF?", 4)) {
+ p[0] += 4;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE]));
+#endif
+ p[0]++;
+ sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE]));
+ isdn_tty_at_cout(rs, info);
+ return 0;
+ }
+
+ /* CIG=string - local fax station id string for polling rx */
+ if (!strncmp(p[0], "CIG", 3)) {
+ int i, r;
+ p[0] += 3;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n\"%s\"", f->pollid);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n\"STRING\"");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ if (*p[0] =='"')
+ p[0]++;
+ for(i=0; (*p[0]) && i < (FAXIDLEN-1) && (*p[0] != '"'); i++)
+ {
+ f->pollid[i] = *p[0]++;
+ }
+ if (*p[0] =='"')
+ p[0]++;
+ for(r=i; r < FAXIDLEN; r++)
+ {
+ f->pollid[r] = 32;
+ }
+ f->pollid[FAXIDLEN-1] = 0;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */
+ if (!strncmp(p[0], "CQ", 2)) {
+ p[0] += 2;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d", f->cq);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0,1,2");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 2))
+ PARSE_ERROR1;
+ f->cq = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */
+ if (!strncmp(p[0], "CR", 2)) {
+ p[0] += 2;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0,1"); /* display online help */
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 1))
+ PARSE_ERROR1;
+ f->cr = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* CTCRTY=value - ECM retry count */
+ if (!strncmp(p[0], "CTCRTY", 6)){
+ p[0] +=6;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",f->ctcrty);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0-255");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ f->ctcrty = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */
+ if (!strncmp(p[0], "DCC", 3)) {
+ char *rp = &f->resolution;
+ int i;
+
+ p[0] += 3;
+ switch(*p[0]) {
+ case '?':
+ p[0]++;
+ strcpy(rs, "\r\n");
+ for(i = 0; i < 8; i++) {
+ sprintf(rss, "%c%s", rp[i] + 48,
+ (i < 7) ? "," : "");
+ strcat(rs, rss);
+ }
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?') {
+ isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)",info);
+ p[0]++;
+ } else {
+ for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<8); i++) {
+ if (*p[0] != ',') {
+ if ((*p[0] - 48) > maxdccval[i]) {
+ PARSE_ERROR1;
+ }
+ rp[i] = *p[0] - 48;
+ p[0]++;
+ if (*p[0] == ',')
+ p[0]++;
+ } else p[0]++;
+ }
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n",
+ rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */
+ if (!strncmp(p[0], "DIS", 3)) {
+ char *rp = &f->resolution;
+ int i;
+
+ p[0] += 3;
+ switch(*p[0]) {
+ case '?':
+ p[0]++;
+ strcpy(rs, "\r\n");
+ for(i = 0; i < 8; i++) {
+ sprintf(rss, "%c%s", rp[i] + 48,
+ (i < 7) ? "," : "");
+ strcat(rs, rss);
+ }
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?') {
+ isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)",info);
+ p[0]++;
+ } else {
+ for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<8); i++) {
+ if (*p[0] != ',') {
+ if ((*p[0] - 48) > maxdccval[i]) {
+ PARSE_ERROR1;
+ }
+ rp[i] = *p[0] - 48;
+ p[0]++;
+ if (*p[0] == ',')
+ p[0]++;
+ } else p[0]++;
+ }
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n",
+ rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* DR - Receive Phase C data command, initiates document reception */
+ if (!strncmp(p[0], "DR", 2)) {
+ p[0] += 2;
+ if ((info->faxonline & 16) && /* incoming connection */
+ ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) {
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
+#endif
+ f->code = ISDN_TTY_FAX_DR;
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ cmd.command = ISDN_CMD_FAXCMD;
+ isdn_command(&cmd);
+ if (f->phase == ISDN_FAX_PHASE_B) {
+ f->phase = ISDN_FAX_PHASE_C;
+ } else if (f->phase == ISDN_FAX_PHASE_D) {
+ switch(f->fet) {
+ case 0: /* next page will be received */
+ f->phase = ISDN_FAX_PHASE_C;
+ isdn_tty_fax_modem_result(7, info); /* CONNECT */
+ break;
+ case 1: /* next doc will be received */
+ f->phase = ISDN_FAX_PHASE_B;
+ break;
+ case 2: /* fax session is terminating */
+ f->phase = ISDN_FAX_PHASE_E;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ }
+ } else {
+ PARSE_ERROR1;
+ }
+ return 1;
+ }
+
+ /* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */
+ if (!strncmp(p[0], "DT", 2)) {
+ int i, val[]={4,0,2,3};
+ char *rp = &f->resolution;
+
+ p[0] += 2;
+ if (!info->faxonline & 1) /* not outgoing connection */
+ PARSE_ERROR1;
+
+ for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<4); i++) {
+ if (*p[0] != ',') {
+ if ((*p[0] - 48) > maxdccval[val[i]]) {
+ PARSE_ERROR1;
+ }
+ rp[val[i]] = *p[0] - 48;
+ p[0]++;
+ if (*p[0] == ',')
+ p[0]++;
+ } else p[0]++;
+ }
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n",
+ rp[4], rp[0], rp[2], rp[3]);
+#endif
+ if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) {
+ f->code = ISDN_TTY_FAX_DT;
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ cmd.command = ISDN_CMD_FAXCMD;
+ isdn_command(&cmd);
+ if (f->phase == ISDN_FAX_PHASE_D) {
+ f->phase = ISDN_FAX_PHASE_C;
+ isdn_tty_fax_modem_result(7, info); /* CONNECT */
+ }
+ } else {
+ PARSE_ERROR1;
+ }
+ return 1;
+ }
+
+ /* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */
+ if (!strncmp(p[0], "ECM", 3)) {
+ p[0] += 3;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",f->ecm);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0,2");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par != 0) && (par != 2))
+ PARSE_ERROR1;
+ f->ecm = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* ET=n - End of page or document */
+ if (!strncmp(p[0], "ET=", 3)) {
+ p[0] += 3;
+ if (*p[0] == '?') {
+ p[0]++;
+ sprintf(rs, "\r\n0-2");
+ isdn_tty_at_cout(rs, info);
+ } else {
+ if ((f->phase != ISDN_FAX_PHASE_D) || (!info->faxonline & 1))
+ PARSE_ERROR1;
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 2))
+ PARSE_ERROR1;
+ f->fet = par;
+ f->code = ISDN_TTY_FAX_ET;
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ cmd.command = ISDN_CMD_FAXCMD;
+ isdn_command(&cmd);
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par);
+#endif
+ return 1;
+ }
+ return 0;
+ }
+
+ /* K - terminate */
+ if (!strncmp(p[0], "K", 1)) {
+ p[0] += 1;
+ if ((f->phase == ISDN_FAX_PHASE_IDLE) || (f->phase == ISDN_FAX_PHASE_E))
+ PARSE_ERROR1;
+ isdn_tty_modem_hup(info, 1);
+ return 1;
+ }
+
+ /* LID=string - local fax ID */
+ if (!strncmp(p[0], "LID", 3)) {
+ int i, r;
+ p[0] += 3;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n\"%s\"", f->id);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n\"STRING\"");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ if (*p[0] =='"')
+ p[0]++;
+ for(i=0; (*p[0]) && i < (FAXIDLEN-1) && (*p[0] != '"'); i++)
+ {
+ f->id[i] = *p[0]++;
+ }
+ if (*p[0] =='"')
+ p[0]++;
+ for(r=i; r < FAXIDLEN; r++)
+ {
+ f->id[r] = 32;
+ }
+ f->id[FAXIDLEN-1] = 0;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+#if 0
+ /* LO=n - Flow control opts */
+ if (!strncmp(p[0], "LO", 2)) { /* TODO */
+ p[0] += 2;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",f->lo);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0,1,2");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 2))
+ PARSE_ERROR1;
+ f->lo = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FLO=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+#endif
+#if 0
+ /* LPL=n - Doc for polling cmd */
+ if (!strncmp(p[0], "LPL", 3)) { /* TODO */
+ p[0] += 3;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",f->lpl);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0,1");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 1))
+ PARSE_ERROR1;
+ f->lpl = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FLPL=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+#endif
+
+ /* MDL? - DCE Model */
+ if (!strncmp(p[0], "MDL?", 4)) {
+ p[0] += 4;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: FMDL?\n");
+#endif
+ isdn_tty_at_cout("\r\nisdn4linux", info);
+ return 0;
+ }
+
+ /* MFR? - DCE Manufacturer */
+ if (!strncmp(p[0], "MFR?", 4)) {
+ p[0] += 4;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: FMFR?\n");
+#endif
+ isdn_tty_at_cout("\r\nisdn4linux", info);
+ return 0;
+ }
+
+ /* MINSP=n - Minimum Speed for Phase C */
+ if (!strncmp(p[0], "MINSP", 5)) {
+ p[0] += 5;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",f->minsp);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0-5");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 5))
+ PARSE_ERROR1;
+ f->minsp = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* PHCTO=value - DTE phase C timeout */
+ if (!strncmp(p[0], "PHCTO", 5)){
+ p[0] +=5;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",f->phcto);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0-255");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ f->phcto = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+#if 0
+ /* PTS=n - Page transfer status */
+ if (!strncmp(p[0], "PTS", 3)) { /* TODO */
+ p[0] += 3;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",f->pts);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0-5");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 5))
+ PARSE_ERROR1;
+ f->pts = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FPTS=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+#endif
+
+ /* REL=n - Phase C received EOL alignment */
+ if (!strncmp(p[0], "REL", 3)) {
+ p[0] += 3;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",f->rel);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0,1");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 1))
+ PARSE_ERROR1;
+ f->rel = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ /* REV? - DCE Revision */
+ if (!strncmp(p[0], "REV?", 4)) {
+ p[0] += 4;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: FREV?\n");
+#endif
+ strcpy(rss, isdn_tty_fax_revision);
+ sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
+ isdn_tty_at_cout(rs, info);
+ return 0;
+ }
+
+#if 0
+ /* SPL=n - Enable polling */
+ if (!strncmp(p[0], "SPL", 3)) { /* TODO */
+ p[0] += 3;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d", f->spl);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?')
+ {
+ p[0]++;
+ sprintf(rs, "\r\n0,1");
+ isdn_tty_at_cout(rs, info);
+ }
+ else
+ {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 1))
+ PARSE_ERROR1;
+ f->spl = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FSPL=%d\n", par);
+#endif
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+#endif
+
+ /* Phase C Transmit Data Block Size */
+ if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */
+ p[0] += 4;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
+#endif
+ switch (*p[0]) {
+ case '0':
+ p[0]++;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+
+ printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
+ PARSE_ERROR1;
+}
+
diff --git a/drivers/isdn/isdn_ttyfax.h b/drivers/isdn/isdn_ttyfax.h
new file mode 100644
index 000000000..1ad75d2df
--- /dev/null
+++ b/drivers/isdn/isdn_ttyfax.h
@@ -0,0 +1,33 @@
+/* $Id: isdn_ttyfax.h,v 1.1 1999/07/31 12:59:51 armin Exp $
+ * header for Linux ISDN subsystem, tty_fax related functions (linklevel).
+ *
+ * Copyright 1999 by Armin Schindler (mac@melware.de)
+ * Copyright 1999 by Ralf Spachmann (mel@melware.de)
+ * Copyright 1999 by Cytronics & Melware
+ *
+ * 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_ttyfax.h,v $
+ * Revision 1.1 1999/07/31 12:59:51 armin
+ * Added tty fax capabilities.
+ *
+ *
+ */
+
+
+#define XON 0x11
+#define XOFF 0x13
+#define DC2 0x12
+
diff --git a/drivers/isdn/isdn_x25iface.c b/drivers/isdn/isdn_x25iface.c
index d0594fe34..9a5074801 100644
--- a/drivers/isdn/isdn_x25iface.c
+++ b/drivers/isdn/isdn_x25iface.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_x25iface.c,v 1.6 1999/01/27 22:53:19 he Exp $
+/* $Id: isdn_x25iface.c,v 1.7 1999/08/22 20:26:13 calle 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
@@ -10,6 +10,12 @@
* goes to another -- device related -- concap_proto support source file.
*
* $Log: isdn_x25iface.c,v $
+ * Revision 1.7 1999/08/22 20:26:13 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
* Revision 1.6 1999/01/27 22:53:19 he
* minor updates (spellings, jiffies wrap around in isdn_tty)
*
@@ -57,7 +63,7 @@ typedef struct isdn_x25iface_proto_data {
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 net_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 * );
@@ -175,7 +181,7 @@ void isdn_x25iface_proto_del(struct concap_proto *cprot){
/* (re-)initialize the data structures for x25iface encapsulation
*/
int isdn_x25iface_proto_restart(struct concap_proto *cprot,
- struct device *ndev,
+ struct net_device *ndev,
struct concap_device_ops *dops)
{
ix25_pdata_t * pda = cprot -> proto_data ;
diff --git a/drivers/isdn/isdnloop/.cvsignore b/drivers/isdn/isdnloop/.cvsignore
deleted file mode 100644
index 857dd22e9..000000000
--- a/drivers/isdn/isdnloop/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.depend
-.*.flags
diff --git a/drivers/isdn/pcbit/.cvsignore b/drivers/isdn/pcbit/.cvsignore
deleted file mode 100644
index 857dd22e9..000000000
--- a/drivers/isdn/pcbit/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.depend
-.*.flags
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index a3186ac11..77f0ed45f 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -86,7 +86,7 @@ int pcbit_init_dev(int board, int mem_base, int irq)
dev_pcbit[board] = dev;
memset(dev, 0, sizeof(struct pcbit_dev));
-#if LINUX_VERSION_CODE >= 131841
+#ifdef COMPAT_HAS_NEW_WAITQ
init_waitqueue_head(&dev->set_running_wq);
#endif
diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c
index 33aee3360..799552019 100644
--- a/drivers/isdn/pcbit/module.c
+++ b/drivers/isdn/pcbit/module.c
@@ -102,10 +102,21 @@ void cleanup_module(void)
}
#else
-void pcbit_setup(char *str, int *ints)
+#ifdef COMPAT_HAS_NEW_SETUP
+#define MAX_PARA (MAX_PCBIT_CARDS * 2)
+#include <linux/init.h>
+static int __init pcbit_setup(char *line)
{
int i, j, argc;
+ char *str;
+ int ints[MAX_PARA+1];
+ str = get_options(line, MAX_PARA, ints);
+#else
+void pcbit_setup(char *str, int *ints)
+{
+ int i, j, argc;
+#endif
argc = ints[0];
i = 0;
j = 1;
@@ -124,8 +135,14 @@ void pcbit_setup(char *str, int *ints)
i++;
}
+#ifdef COMPAT_HAS_NEW_SETUP
+ return(1);
+}
+__setup("pcbit=", pcbit_setup);
+#else
}
#endif
+#endif
diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h
index 0dbdb5fd1..45c68871d 100644
--- a/drivers/isdn/pcbit/pcbit.h
+++ b/drivers/isdn/pcbit/pcbit.h
@@ -68,10 +68,10 @@ struct pcbit_dev {
struct frame_buf *write_queue;
/* Protocol start */
-#if LINUX_VERSION_CODE < 131841
- struct wait_queue *set_running_wq;
-#else
+#ifdef COMPAT_HAS_NEW_WAITQ
wait_queue_head_t set_running_wq;
+#else
+ struct wait_queue *set_running_wq;
#endif
struct timer_list set_running_timer;
diff --git a/drivers/isdn/sc/.cvsignore b/drivers/isdn/sc/.cvsignore
deleted file mode 100644
index 857dd22e9..000000000
--- a/drivers/isdn/sc/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.depend
-.*.flags
diff --git a/drivers/isdn/teles/.cvsignore b/drivers/isdn/teles/.cvsignore
deleted file mode 100644
index 857dd22e9..000000000
--- a/drivers/isdn/teles/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.depend
-.*.flags