summaryrefslogtreecommitdiffstats
path: root/drivers/isdn
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
commit482368b1a8e45430672c58c9a42e7d2004367126 (patch)
treece2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /drivers/isdn
parente4d0251c6f56ab2e191afb70f80f382793e23f74 (diff)
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'drivers/isdn')
-rw-r--r--drivers/isdn/Config.in127
-rw-r--r--drivers/isdn/Makefile6
-rw-r--r--drivers/isdn/avmb1/Makefile11
-rw-r--r--drivers/isdn/avmb1/avmcard.h31
-rw-r--r--drivers/isdn/avmb1/b1.c16
-rw-r--r--drivers/isdn/avmb1/b1dma.c984
-rw-r--r--drivers/isdn/avmb1/b1isa.c41
-rw-r--r--drivers/isdn/avmb1/b1pci.c295
-rw-r--r--drivers/isdn/avmb1/b1pcmcia.c36
-rw-r--r--drivers/isdn/avmb1/c4.c1326
-rw-r--r--drivers/isdn/avmb1/capi.c58
-rw-r--r--drivers/isdn/avmb1/capidrv.c47
-rw-r--r--drivers/isdn/avmb1/kcapi.c120
-rw-r--r--drivers/isdn/avmb1/t1isa.c28
-rw-r--r--drivers/isdn/avmb1/t1pci.c964
-rw-r--r--drivers/isdn/divert/divert_procfs.c474
-rw-r--r--drivers/isdn/eicon/eicon.h32
-rw-r--r--drivers/isdn/eicon/eicon_dsp.h12
-rw-r--r--drivers/isdn/eicon/eicon_idi.c224
-rw-r--r--drivers/isdn/eicon/eicon_idi.h21
-rw-r--r--drivers/isdn/eicon/eicon_io.c23
-rw-r--r--drivers/isdn/eicon/eicon_isa.c111
-rw-r--r--drivers/isdn/eicon/eicon_isa.h18
-rw-r--r--drivers/isdn/eicon/eicon_mod.c87
-rw-r--r--drivers/isdn/eicon/eicon_pci.c16
-rw-r--r--drivers/isdn/eicon/eicon_pci.h12
-rw-r--r--drivers/isdn/hisax/Makefile4
-rw-r--r--drivers/isdn/hisax/arcofi.c17
-rw-r--r--drivers/isdn/hisax/arcofi.h7
-rw-r--r--drivers/isdn/hisax/asuscom.c12
-rw-r--r--drivers/isdn/hisax/avm_pci.c37
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c16
-rw-r--r--drivers/isdn/hisax/bkm_a8.c12
-rw-r--r--drivers/isdn/hisax/callc.c584
-rw-r--r--drivers/isdn/hisax/config.c38
-rw-r--r--drivers/isdn/hisax/diva.c20
-rw-r--r--drivers/isdn/hisax/elsa.c14
-rw-r--r--drivers/isdn/hisax/fsm.c7
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c7
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.h7
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c186
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.h7
-rw-r--r--drivers/isdn/hisax/hfc_pci.c65
-rw-r--r--drivers/isdn/hisax/hfc_sx.c1583
-rw-r--r--drivers/isdn/hisax/hfc_sx.h216
-rw-r--r--drivers/isdn/hisax/hfcscard.c14
-rw-r--r--drivers/isdn/hisax/hisax.h63
-rw-r--r--drivers/isdn/hisax/hscx.h7
-rw-r--r--drivers/isdn/hisax/ipac.h7
-rw-r--r--drivers/isdn/hisax/isac.h7
-rw-r--r--drivers/isdn/hisax/isar.c700
-rw-r--r--drivers/isdn/hisax/isar.h36
-rw-r--r--drivers/isdn/hisax/isdnl1.c27
-rw-r--r--drivers/isdn/hisax/isurf.c12
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c8
-rw-r--r--drivers/isdn/hisax/l3dss1.c79
-rw-r--r--drivers/isdn/hisax/l3dss1.h7
-rw-r--r--drivers/isdn/hisax/netjet.c12
-rw-r--r--drivers/isdn/hisax/rawhdlc.c4
-rw-r--r--drivers/isdn/hisax/saphir.c12
-rw-r--r--drivers/isdn/hisax/sedlbauer.c31
-rw-r--r--drivers/isdn/hisax/sportster.c17
-rw-r--r--drivers/isdn/hisax/teleint.c12
-rw-r--r--drivers/isdn/hisax/teles0.c9
-rw-r--r--drivers/isdn/hisax/teles3.c22
-rw-r--r--drivers/isdn/hisax/telespci.c9
-rw-r--r--drivers/isdn/hysdn/.cvsignore2
-rw-r--r--drivers/isdn/hysdn/Makefile24
-rw-r--r--drivers/isdn/hysdn/boardergo.c467
-rw-r--r--drivers/isdn/hysdn/boardergo.h117
-rw-r--r--drivers/isdn/hysdn/hysdn_boot.c420
-rw-r--r--drivers/isdn/hysdn/hysdn_defs.h229
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c243
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c378
-rw-r--r--drivers/isdn/hysdn/hysdn_pof.h95
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c485
-rw-r--r--drivers/isdn/hysdn/hysdn_procfs.c502
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c481
-rw-r--r--drivers/isdn/hysdn/hysdn_sched.c202
-rw-r--r--drivers/isdn/hysdn/ince1pc.h132
-rw-r--r--drivers/isdn/isdn_common.c229
-rw-r--r--drivers/isdn/isdn_common.h7
-rw-r--r--drivers/isdn/isdn_net.c320
-rw-r--r--drivers/isdn/isdn_ppp.c35
-rw-r--r--drivers/isdn/isdn_tty.c108
-rw-r--r--drivers/isdn/isdn_tty.h14
-rw-r--r--drivers/isdn/isdn_ttyfax.c1118
87 files changed, 11836 insertions, 2826 deletions
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index 2081f12fe..a73c26766 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -12,68 +12,99 @@ 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' CONFIG_ISDN_X25
fi
-dep_tristate ' ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
-dep_tristate ' isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
-dep_tristate ' PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-dep_tristate ' HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
+
+mainmenu_option next_comment
+comment 'ISDN feature submodules'
+ dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
+ bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION
+endmenu
+
+comment 'low-level hardware drivers'
+
+mainmenu_option next_comment
+comment 'Passive ISDN cards'
+dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
- bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+ comment ' D-channel protocol features'
+ bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
if [ "$CONFIG_HISAX_EURO" != "n" ]; then
- bool ' Support for german chargeinfo' CONFIG_DE_AOC
- bool ' Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
- bool ' Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
+ bool ' Support for german chargeinfo' CONFIG_DE_AOC
+ bool ' Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
+ bool ' Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
+ bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD
fi
- bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
- bool ' HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
- bool ' HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
- bool ' HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI
- bool ' HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX
- bool ' HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
- bool ' HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
- bool ' HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
- bool ' HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
- bool ' HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
- bool ' HiSax Support for 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 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
- bool ' HiSax Support for Winbond W6692 based cards' CONFIG_HISAX_W6692
+ bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+ comment ' HiSax supported cards'
+ bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0
+ bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+ bool ' Teles PCI' CONFIG_HISAX_TELESPCI
+ bool ' Teles S0Box' CONFIG_HISAX_S0BOX
+ bool ' AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+ bool ' AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
+ bool ' AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
+ bool ' Elsa cards' CONFIG_HISAX_ELSA
+ bool ' ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+ bool ' Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
+ bool ' ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
+ bool ' TELEINT cards' CONFIG_HISAX_TELEINT
+ bool ' HFC-S based cards' CONFIG_HISAX_HFCS
+ bool ' Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
+ bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+ bool ' MIC card' CONFIG_HISAX_MIC
+ bool ' NETjet card' CONFIG_HISAX_NETJET
+ bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY
+ bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF
+ bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+ bool ' Telekom A4T card' CONFIG_HISAX_BKM_A4T
+ bool ' Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
+ bool ' Gazel cards' CONFIG_HISAX_GAZEL
+ bool ' HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
+ bool ' Winbond W6692 based cards' CONFIG_HISAX_W6692
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-# bool ' HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+ bool ' HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
+# bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
- bool ' HiSax Support for Am7930' CONFIG_HISAX_AMD7930
+ bool ' Am7930' CONFIG_HISAX_AMD7930
fi
fi
fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Active ISDN cards'
+dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
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 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+ dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
fi
-dep_tristate ' Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
+dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
- bool ' Eicon S, SX, SCOM, Quadro, S2M support' CONFIG_ISDN_DRV_EICON_ISA
+ 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
+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/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
- bool ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
- bool ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
- bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+ bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
+ bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
+ if [ "$CONFIG_ISDN_DRV_AVMB1_B1PCI" != "n" ]; then
+ if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+ bool ' AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ fi
+ fi
+ bool ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
+ bool ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+ bool ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
+ if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+ bool ' AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4
+ fi
+ bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+fi
+if [ "$CONFIG_PROC_FS" != "n" ]; then
+if [ "$CONFIG_MODULES" != "n" ]; then
+ bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN
+fi
fi
+endmenu
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
index 04be19f9c..c94551716 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 divert
+ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon divert hysdn
L_OBJS :=
LX_OBJS :=
@@ -137,5 +137,9 @@ else
endif
endif
+ifeq ($(CONFIG_HYSDN),y)
+ MOD_SUB_DIRS += hysdn
+endif
+
include $(TOPDIR)/Rules.make
diff --git a/drivers/isdn/avmb1/Makefile b/drivers/isdn/avmb1/Makefile
index 111c39466..bfeb81939 100644
--- a/drivers/isdn/avmb1/Makefile
+++ b/drivers/isdn/avmb1/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile,v 1.7 1999/09/15 08:16:03 calle Exp $
+# $Id: Makefile,v 1.8 2000/01/25 14:33:38 calle Exp $
#
# Makefile for the CAPI and AVM-B1 device drivers.
#
@@ -11,6 +11,11 @@
# parent makes..
#
# $Log: Makefile,v $
+# Revision 1.8 2000/01/25 14:33:38 calle
+# - Added Support AVM B1 PCI V4.0 (tested with prototype)
+# - splitted up t1pci.c into b1dma.c for common function with b1pciv4
+# - support for revision register
+#
# Revision 1.7 1999/09/15 08:16:03 calle
# Implementation of 64Bit extention complete.
#
@@ -99,7 +104,7 @@ ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
ifdef CONFIG_ISDN_DRV_AVMB1_C4
O_OBJS += c4.o
endif
- OX_OBJS += capiutil.o capidrv.o b1.o
+ OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
else
ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
O_TARGET += kernelcapi.o
@@ -123,7 +128,7 @@ else
ifdef CONFIG_ISDN_DRV_AVMB1_C4
M_OBJS += c4.o
endif
- MX_OBJS += capiutil.o capidrv.o b1.o
+ MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
endif
endif
diff --git a/drivers/isdn/avmb1/avmcard.h b/drivers/isdn/avmb1/avmcard.h
index f4b5df689..56fa0fba6 100644
--- a/drivers/isdn/avmb1/avmcard.h
+++ b/drivers/isdn/avmb1/avmcard.h
@@ -1,9 +1,14 @@
/*
- * $Id: avmcard.h,v 1.6 1999/11/05 16:38:01 calle Exp $
+ * $Id: avmcard.h,v 1.7 2000/01/25 14:33:38 calle Exp $
*
* Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: avmcard.h,v $
+ * Revision 1.7 2000/01/25 14:33:38 calle
+ * - Added Support AVM B1 PCI V4.0 (tested with prototype)
+ * - splitted up t1pci.c into b1dma.c for common function with b1pciv4
+ * - support for revision register
+ *
* Revision 1.6 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -92,6 +97,8 @@ typedef struct avmcard {
unsigned irq;
unsigned long membase;
enum avmcardtype cardtype;
+ unsigned char revision;
+ unsigned char class;
int cardnr; /* for t1isa */
char msgbuf[128]; /* capimsg msg part */
@@ -228,8 +235,9 @@ extern int b1_irq_table[16];
#define B1_WRITE 0x01
#define B1_INSTAT 0x02
#define B1_OUTSTAT 0x03
-#define B1_RESET 0x10
#define B1_ANALYSE 0x04
+#define B1_REVISION 0x05
+#define B1_RESET 0x10
#define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l)
@@ -561,10 +569,13 @@ static inline void b1_setinterrupt(unsigned int base, unsigned irq,
}
}
+/* b1.c */
int b1_detect(unsigned int base, enum avmcardtype cardtype);
+void b1_getrevision(avmcard *card);
int b1_load_t4file(avmcard *card, capiloaddatapart * t4file);
int b1_load_config(avmcard *card, capiloaddatapart * config);
int b1_loaded(avmcard *card);
+
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,
@@ -577,5 +588,21 @@ 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);
+/* b1dma.c */
+int b1pciv4_detect(avmcard *card);
+int t1pci_detect(avmcard *card);
+void b1dma_reset(avmcard *card);
+void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
+
+int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
+void b1dma_reset_ctr(struct capi_ctr *ctrl);
+void b1dma_remove_ctr(struct capi_ctr *ctrl);
+void b1dma_register_appl(struct capi_ctr *ctrl,
+ __u16 appl,
+ capi_register_params *rp);
+void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl);
+void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
+int b1dmactl_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
index 900b31c8c..65c4368cd 100644
--- a/drivers/isdn/avmb1/b1.c
+++ b/drivers/isdn/avmb1/b1.c
@@ -1,11 +1,16 @@
/*
- * $Id: b1.c,v 1.12 1999/11/05 16:38:01 calle Exp $
+ * $Id: b1.c,v 1.13 2000/01/25 14:33:38 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.13 2000/01/25 14:33:38 calle
+ * - Added Support AVM B1 PCI V4.0 (tested with prototype)
+ * - splitted up t1pci.c into b1dma.c for common function with b1pciv4
+ * - support for revision register
+ *
* Revision 1.12 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -86,7 +91,7 @@
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.12 $";
+static char *revision = "$Revision: 1.13 $";
/* ------------------------------------------------------------- */
@@ -158,6 +163,12 @@ int b1_detect(unsigned int base, enum avmcardtype cardtype)
return 0;
}
+void b1_getrevision(avmcard *card)
+{
+ card->class = inb(card->port + B1_ANALYSE);
+ card->revision = inb(card->port + B1_REVISION);
+}
+
int b1_load_t4file(avmcard *card, capiloaddatapart * t4file)
{
unsigned char buf[256];
@@ -688,6 +699,7 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
EXPORT_SYMBOL(b1_irq_table);
EXPORT_SYMBOL(b1_detect);
+EXPORT_SYMBOL(b1_getrevision);
EXPORT_SYMBOL(b1_load_t4file);
EXPORT_SYMBOL(b1_load_config);
EXPORT_SYMBOL(b1_loaded);
diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c
new file mode 100644
index 000000000..8bf595282
--- /dev/null
+++ b/drivers/isdn/avmb1/b1dma.c
@@ -0,0 +1,984 @@
+/*
+ * $Id: b1dma.c,v 1.2 2000/01/25 14:44:47 calle Exp $
+ *
+ * Common module for AVM B1 cards that support dma with AMCC
+ *
+ * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1dma.c,v $
+ * Revision 1.2 2000/01/25 14:44:47 calle
+ * typo in b1pciv4_detect().
+ *
+ * Revision 1.1 2000/01/25 14:36:43 calle
+ * common function for T1 PCI and B1 PCI V4.
+ *
+ *
+ */
+
+#include <linux/config.h>
+#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 <asm/uaccess.h>
+#include "capilli.h"
+#include "avmcard.h"
+#include "capicmd.h"
+#include "capiutil.h"
+
+static char *revision = "$Revision: 1.2 $";
+
+/* ------------------------------------------------------------- */
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+int suppress_pollack = 0;
+MODULE_PARM(suppress_pollack, "0-1i");
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_dispatch_tx(avmcard *card);
+
+/* ------------------------------------------------------------- */
+
+/* S5933 */
+
+#define AMCC_RXPTR 0x24
+#define AMCC_RXLEN 0x28
+#define AMCC_TXPTR 0x2c
+#define AMCC_TXLEN 0x30
+
+#define AMCC_INTCSR 0x38
+# define EN_READ_TC_INT 0x00008000L
+# define EN_WRITE_TC_INT 0x00004000L
+# define EN_TX_TC_INT EN_READ_TC_INT
+# define EN_RX_TC_INT EN_WRITE_TC_INT
+# define AVM_FLAG 0x30000000L
+
+# define ANY_S5933_INT 0x00800000L
+# define READ_TC_INT 0x00080000L
+# define WRITE_TC_INT 0x00040000L
+# define TX_TC_INT READ_TC_INT
+# define RX_TC_INT WRITE_TC_INT
+# define MASTER_ABORT_INT 0x00100000L
+# define TARGET_ABORT_INT 0x00200000L
+# define BUS_MASTER_INT 0x00200000L
+# define ALL_INT 0x000C0000L
+
+#define AMCC_MCSR 0x3c
+# define A2P_HI_PRIORITY 0x00000100L
+# define EN_A2P_TRANSFERS 0x00000400L
+# define P2A_HI_PRIORITY 0x00001000L
+# define EN_P2A_TRANSFERS 0x00004000L
+# define RESET_A2P_FLAGS 0x04000000L
+# define RESET_P2A_FLAGS 0x02000000L
+
+/* ------------------------------------------------------------- */
+
+#define b1dmaoutmeml(addr, value) writel(value, addr)
+#define b1dmainmeml(addr) readl(addr)
+#define b1dmaoutmemw(addr, value) writew(value, addr)
+#define b1dmainmemw(addr) readw(addr)
+#define b1dmaoutmemb(addr, value) writeb(value, addr)
+#define b1dmainmemb(addr) readb(addr)
+
+/* ------------------------------------------------------------- */
+
+static inline int b1dma_tx_empty(unsigned int port)
+{
+ return inb(port + 0x03) & 0x1;
+}
+
+static inline int b1dma_rx_full(unsigned int port)
+{
+ return inb(port + 0x02) & 0x1;
+}
+
+static int b1dma_tolink(avmcard *card, void *buf, unsigned int len)
+{
+ unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
+ unsigned char *s = (unsigned char *)buf;
+ while (len--) {
+ while ( !b1dma_tx_empty(card->port)
+ && time_before(jiffies, stop));
+ if (!b1dma_tx_empty(card->port))
+ return -1;
+ t1outp(card->port, 0x01, *s++);
+ }
+ return 0;
+}
+
+static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len)
+{
+ unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
+ unsigned char *s = (unsigned char *)buf;
+ while (len--) {
+ while ( !b1dma_rx_full(card->port)
+ && time_before(jiffies, stop));
+ if (!b1dma_rx_full(card->port))
+ return -1;
+ *s++ = t1inp(card->port, 0x00);
+ }
+ return 0;
+}
+
+static int WriteReg(avmcard *card, __u32 reg, __u8 val)
+{
+ __u8 cmd = 0x00;
+ if ( b1dma_tolink(card, &cmd, 1) == 0
+ && b1dma_tolink(card, &reg, 4) == 0) {
+ __u32 tmp = val;
+ return b1dma_tolink(card, &tmp, 4);
+ }
+ return -1;
+}
+
+static __u8 ReadReg(avmcard *card, __u32 reg)
+{
+ __u8 cmd = 0x01;
+ if ( b1dma_tolink(card, &cmd, 1) == 0
+ && b1dma_tolink(card, &reg, 4) == 0) {
+ __u32 tmp;
+ if (b1dma_fromlink(card, &tmp, 4) == 0)
+ return (__u8)tmp;
+ }
+ return 0xff;
+}
+
+/* ------------------------------------------------------------- */
+
+static inline void _put_byte(void **pp, __u8 val)
+{
+ __u8 *s = *pp;
+ *s++ = val;
+ *pp = s;
+}
+
+static inline void _put_word(void **pp, __u32 val)
+{
+ __u8 *s = *pp;
+ *s++ = val & 0xff;
+ *s++ = (val >> 8) & 0xff;
+ *s++ = (val >> 16) & 0xff;
+ *s++ = (val >> 24) & 0xff;
+ *pp = s;
+}
+
+static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
+{
+ unsigned i = len;
+ _put_word(pp, i);
+ while (i-- > 0)
+ _put_byte(pp, *dp++);
+}
+
+static inline __u8 _get_byte(void **pp)
+{
+ __u8 *s = *pp;
+ __u8 val;
+ val = *s++;
+ *pp = s;
+ return val;
+}
+
+static inline __u32 _get_word(void **pp)
+{
+ __u8 *s = *pp;
+ __u32 val;
+ val = *s++;
+ val |= (*s++ << 8);
+ val |= (*s++ << 16);
+ val |= (*s++ << 24);
+ *pp = s;
+ return val;
+}
+
+static inline __u32 _get_slice(void **pp, unsigned char *dp)
+{
+ unsigned int len, i;
+
+ len = i = _get_word(pp);
+ while (i-- > 0) *dp++ = _get_byte(pp);
+ return len;
+}
+
+/* ------------------------------------------------------------- */
+
+void b1dma_reset(avmcard *card)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ card->csr = 0x0;
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+ b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0);
+ b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0);
+
+ t1outp(card->port, 0x10, 0x00);
+ t1outp(card->port, 0x07, 0x00);
+
+ restore_flags(flags);
+
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+ udelay(10 * 1000);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
+ udelay(10 * 1000);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+ if (card->cardtype == avm_t1pci)
+ udelay(42 * 1000);
+ else
+ udelay(10 * 1000);
+}
+
+/* ------------------------------------------------------------- */
+
+int b1dma_detect(avmcard *card)
+{
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+ udelay(10 * 1000);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
+ udelay(10 * 1000);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
+ udelay(42 * 1000);
+
+ b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0);
+ b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0);
+ card->csr = 0x0;
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+
+ if (b1dmainmeml(card->mbase+AMCC_MCSR) != 0x000000E6)
+ return 1;
+
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0xffffffff);
+ b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0xffffffff);
+ if ( b1dmainmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc
+ || b1dmainmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc)
+ return 2;
+
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0x0);
+ b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0x0);
+ if ( b1dmainmeml(card->mbase+AMCC_RXPTR) != 0x0
+ || b1dmainmeml(card->mbase+AMCC_TXPTR) != 0x0)
+ return 3;
+
+ t1outp(card->port, 0x10, 0x00);
+ t1outp(card->port, 0x07, 0x00);
+
+ t1outp(card->port, 0x02, 0x02);
+ t1outp(card->port, 0x03, 0x02);
+
+ if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02
+ || t1inp(card->port, 0x3) != 0x03)
+ return 4;
+
+ t1outp(card->port, 0x02, 0x00);
+ t1outp(card->port, 0x03, 0x00);
+
+ if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00
+ || t1inp(card->port, 0x3) != 0x01)
+ return 5;
+
+ return 0;
+}
+
+int t1pci_detect(avmcard *card)
+{
+ int ret;
+
+ if ((ret = b1dma_detect(card)) != 0)
+ return ret;
+
+ /* Transputer test */
+
+ if ( WriteReg(card, 0x80001000, 0x11) != 0
+ || WriteReg(card, 0x80101000, 0x22) != 0
+ || WriteReg(card, 0x80201000, 0x33) != 0
+ || WriteReg(card, 0x80301000, 0x44) != 0)
+ return 6;
+
+ if ( ReadReg(card, 0x80001000) != 0x11
+ || ReadReg(card, 0x80101000) != 0x22
+ || ReadReg(card, 0x80201000) != 0x33
+ || ReadReg(card, 0x80301000) != 0x44)
+ return 7;
+
+ if ( WriteReg(card, 0x80001000, 0x55) != 0
+ || WriteReg(card, 0x80101000, 0x66) != 0
+ || WriteReg(card, 0x80201000, 0x77) != 0
+ || WriteReg(card, 0x80301000, 0x88) != 0)
+ return 8;
+
+ if ( ReadReg(card, 0x80001000) != 0x55
+ || ReadReg(card, 0x80101000) != 0x66
+ || ReadReg(card, 0x80201000) != 0x77
+ || ReadReg(card, 0x80301000) != 0x88)
+ return 9;
+
+ return 0;
+}
+
+int b1pciv4_detect(avmcard *card)
+{
+ int ret, i;
+
+ if ((ret = b1dma_detect(card)) != 0)
+ return ret;
+
+ for (i=0; i < 5 ; i++) {
+ if (WriteReg(card, 0x80A00000, 0x21) != 0)
+ return 6;
+ if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01)
+ return 7;
+ }
+ for (i=0; i < 5 ; i++) {
+ if (WriteReg(card, 0x80A00000, 0x20) != 0)
+ return 8;
+ if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00)
+ return 9;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_dispatch_tx(avmcard *card)
+{
+ avmcard_dmainfo *dma = card->dma;
+ unsigned long flags;
+ struct sk_buff *skb;
+ __u8 cmd, subcmd;
+ __u16 len;
+ __u32 txlen;
+ int inint;
+ void *p;
+
+ save_flags(flags);
+ cli();
+
+ inint = card->interrupt;
+
+ if (card->csr & EN_TX_TC_INT) { /* tx busy */
+ restore_flags(flags);
+ return;
+ }
+
+ skb = skb_dequeue(&dma->send_queue);
+ if (!skb) {
+#ifdef CONFIG_B1DMA_DEBUG
+ printk(KERN_DEBUG "tx(%d): underrun\n", inint);
+#endif
+ restore_flags(flags);
+ return;
+ }
+
+ len = CAPIMSG_LEN(skb->data);
+
+ if (len) {
+ cmd = CAPIMSG_COMMAND(skb->data);
+ subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+ p = dma->sendbuf;
+
+ if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+ __u16 dlen = CAPIMSG_DATALEN(skb->data);
+ _put_byte(&p, SEND_DATA_B3_REQ);
+ _put_slice(&p, skb->data, len);
+ _put_slice(&p, skb->data + len, dlen);
+ } else {
+ _put_byte(&p, SEND_MESSAGE);
+ _put_slice(&p, skb->data, len);
+ }
+ txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+#ifdef CONFIG_B1DMA_DEBUG
+ printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
+ inint, txlen);
+#endif
+ } else {
+ txlen = skb->len-2;
+#ifdef CONFIG_B1DMA_POLLDEBUG
+ if (skb->data[2] == SEND_POLLACK)
+ printk(KERN_INFO "%s: send ack\n", card->name);
+#endif
+#ifdef CONFIG_B1DMA_DEBUG
+ printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n",
+ inint, skb->data[2], txlen);
+#endif
+ memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+ }
+ txlen = (txlen + 3) & ~3;
+
+ b1dmaoutmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf));
+ b1dmaoutmeml(card->mbase+AMCC_TXLEN, txlen);
+
+ card->csr |= EN_TX_TC_INT;
+
+ if (!inint)
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+
+ restore_flags(flags);
+ dev_kfree_skb(skb);
+}
+
+/* ------------------------------------------------------------- */
+
+static void queue_pollack(avmcard *card)
+{
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(3, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost poll ack\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_POLLACK);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ b1dma_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_handle_rx(avmcard *card)
+{
+ avmctrl_info *cinfo = &card->ctrlinfo[0];
+ avmcard_dmainfo *dma = card->dma;
+ struct capi_ctr *ctrl = cinfo->capi_ctrl;
+ struct sk_buff *skb;
+ void *p = dma->recvbuf+4;
+ __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+ __u8 b1cmd = _get_byte(&p);
+
+#ifdef CONFIG_B1DMA_DEBUG
+ printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
+#endif
+
+ switch (b1cmd) {
+ case RECEIVE_DATA_B3_IND:
+
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ DataB3Len = _get_slice(&p, card->databuf);
+
+ if (MsgLen < 30) { /* not CAPI 64Bit */
+ memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
+ MsgLen = 30;
+ CAPIMSG_SETLEN(card->msgbuf, 30);
+ }
+ 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);
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_MESSAGE:
+
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, 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 = _get_word(&p);
+ NCCI = _get_word(&p);
+ WindowSize = _get_word(&p);
+
+ ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
+
+ break;
+
+ case RECEIVE_FREE_NCCI:
+
+ ApplId = _get_word(&p);
+ NCCI = _get_word(&p);
+
+ if (NCCI != 0xffffffff)
+ ctrl->free_ncci(ctrl, ApplId, NCCI);
+ else ctrl->appl_released(ctrl, ApplId);
+ break;
+
+ case RECEIVE_START:
+#ifdef CONFIG_B1DMA_POLLDEBUG
+ printk(KERN_INFO "%s: receive poll\n", card->name);
+#endif
+ if (!suppress_pollack)
+ queue_pollack(card);
+ ctrl->resume_output(ctrl);
+ break;
+
+ case RECEIVE_STOP:
+ ctrl->suspend_output(ctrl);
+ break;
+
+ case RECEIVE_INIT:
+
+ cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
+ b1_parse_version(cinfo);
+ printk(KERN_INFO "%s: %s-card (%s) now active\n",
+ card->name,
+ cinfo->version[VER_CARDTYPE],
+ cinfo->version[VER_DRIVER]);
+ ctrl->ready(ctrl);
+ break;
+
+ case RECEIVE_TASK_READY:
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
+ card->name, ApplId, card->msgbuf);
+ break;
+
+ case RECEIVE_DEBUGMSG:
+ MsgLen = _get_slice(&p, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
+ break;
+
+ default:
+ printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n",
+ card->name, b1cmd);
+ return;
+ }
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_handle_interrupt(avmcard *card)
+{
+ __u32 status = b1dmainmeml(card->mbase+AMCC_INTCSR);
+ __u32 newcsr;
+
+ if ((status & ANY_S5933_INT) == 0)
+ return;
+
+ newcsr = card->csr | (status & ALL_INT);
+ if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
+ if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, newcsr);
+
+ if ((status & RX_TC_INT) != 0) {
+ __u8 *recvbuf = card->dma->recvbuf;
+ __u32 rxlen;
+ if (card->dma->recvlen == 0) {
+ card->dma->recvlen = *((__u32 *)recvbuf);
+ rxlen = (card->dma->recvlen + 3) & ~3;
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR,
+ virt_to_phys(recvbuf+4));
+ b1dmaoutmeml(card->mbase+AMCC_RXLEN, rxlen);
+ } else {
+ b1dma_handle_rx(card);
+ card->dma->recvlen = 0;
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf));
+ b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
+ }
+ }
+
+ if ((status & TX_TC_INT) != 0) {
+ card->csr &= ~EN_TX_TC_INT;
+ b1dma_dispatch_tx(card);
+ } else if (card->csr & EN_TX_TC_INT) {
+ if (b1dmainmeml(card->mbase+AMCC_TXLEN) == 0) {
+ card->csr &= ~EN_TX_TC_INT;
+ b1dma_dispatch_tx(card);
+ }
+ }
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+}
+
+void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+ avmcard *card;
+
+ card = (avmcard *) devptr;
+
+ if (!card) {
+ printk(KERN_WARNING "b1dma: interrupt: wrong device\n");
+ return;
+ }
+ if (card->interrupt) {
+ printk(KERN_ERR "%s: reentering interrupt hander\n", card->name);
+ return;
+ }
+
+ card->interrupt = 1;
+
+ b1dma_handle_interrupt(card);
+
+ card->interrupt = 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static int b1dma_loaded(avmcard *card)
+{
+ unsigned long stop;
+ unsigned char ans;
+ unsigned long tout = 2;
+ unsigned int base = card->port;
+
+ for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+ if (b1_tx_empty(base))
+ break;
+ }
+ if (!b1_tx_empty(base)) {
+ printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n",
+ card->name);
+ return 0;
+ }
+ b1_put_byte(base, SEND_POLLACK);
+ for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+ if (b1_rx_full(base)) {
+ if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
+ return 1;
+ }
+ printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
+ return 0;
+ }
+ }
+ printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name);
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_send_init(avmcard *card)
+{
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(15, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_INIT);
+ _put_word(&p, AVM_NAPPS);
+ _put_word(&p, AVM_NCCI_PER_CHANNEL*30);
+ _put_word(&p, card->cardnr - 1);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ b1dma_dispatch_tx(card);
+}
+
+int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ unsigned long flags;
+ int retval;
+
+ b1dma_reset(card);
+
+ if ((retval = b1_load_t4file(card, &data->firmware))) {
+ b1dma_reset(card);
+ 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(card, &data->configuration))) {
+ b1dma_reset(card);
+ printk(KERN_ERR "%s: failed to load config!!\n",
+ card->name);
+ return retval;
+ }
+ }
+
+ if (!b1dma_loaded(card)) {
+ b1dma_reset(card);
+ printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
+ return -EIO;
+ }
+
+ save_flags(flags);
+ cli();
+
+ card->csr = AVM_FLAG;
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+ b1dmaoutmeml(card->mbase+AMCC_MCSR,
+ EN_A2P_TRANSFERS|EN_P2A_TRANSFERS
+ |A2P_HI_PRIORITY|P2A_HI_PRIORITY
+ |RESET_A2P_FLAGS|RESET_P2A_FLAGS);
+ t1outp(card->port, 0x07, 0x30);
+ t1outp(card->port, 0x10, 0xF0);
+
+ card->dma->recvlen = 0;
+ b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf));
+ b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
+ card->csr |= EN_RX_TC_INT;
+ b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
+ restore_flags(flags);
+
+ b1dma_send_init(card);
+
+ return 0;
+}
+
+void b1dma_reset_ctr(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+
+ b1dma_reset(card);
+
+ memset(cinfo->version, 0, sizeof(cinfo->version));
+ ctrl->reseted(ctrl);
+}
+
+
+/* ------------------------------------------------------------- */
+
+
+void b1dma_register_appl(struct capi_ctr *ctrl,
+ __u16 appl,
+ capi_register_params *rp)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ struct sk_buff *skb;
+ int want = rp->level3cnt;
+ int nconn;
+ void *p;
+
+ if (want > 0) nconn = want;
+ else nconn = ctrl->profile.nbchannel * -want;
+ if (nconn == 0) nconn = ctrl->profile.nbchannel;
+
+ skb = alloc_skb(23, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_REGISTER);
+ _put_word(&p, appl);
+ _put_word(&p, 1024 * (nconn+1));
+ _put_word(&p, nconn);
+ _put_word(&p, rp->datablkcnt);
+ _put_word(&p, rp->datablklen);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ b1dma_dispatch_tx(card);
+
+ ctrl->appl_registered(ctrl, appl);
+}
+
+/* ------------------------------------------------------------- */
+
+void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(7, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost release appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_RELEASE);
+ _put_word(&p, appl);
+
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+ skb_queue_tail(&card->dma->send_queue, skb);
+ b1dma_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ skb_queue_tail(&card->dma->send_queue, skb);
+ b1dma_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+int b1dmactl_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ unsigned long flags;
+ __u8 flag;
+ int len = 0;
+ char *s;
+ __u32 txaddr, txlen, rxaddr, rxlen, csr;
+
+ 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);
+ len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+ 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 ((s = cinfo->version[VER_DRIVER]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+ if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+ if ((s = cinfo->version[VER_SERIAL]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+
+ 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", cinfo->cardname);
+
+ save_flags(flags);
+ cli();
+
+ txaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x2c));
+ txaddr -= (__u32)card->dma->sendbuf;
+ txlen = b1dmainmeml(card->mbase+0x30);
+
+ rxaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x24));
+ rxaddr -= (__u32)card->dma->recvbuf;
+ rxlen = b1dmainmeml(card->mbase+0x28);
+
+ csr = b1dmainmeml(card->mbase+AMCC_INTCSR);
+
+ restore_flags(flags);
+
+ len += sprintf(page+len, "%-16s 0x%lx\n",
+ "csr (cached)", (unsigned long)card->csr);
+ len += sprintf(page+len, "%-16s 0x%lx\n",
+ "csr", (unsigned long)csr);
+ len += sprintf(page+len, "%-16s %lu\n",
+ "txoff", (unsigned long)txaddr);
+ len += sprintf(page+len, "%-16s %lu\n",
+ "txlen", (unsigned long)txlen);
+ len += sprintf(page+len, "%-16s %lu\n",
+ "rxoff", (unsigned long)rxaddr);
+ len += sprintf(page+len, "%-16s %lu\n",
+ "rxlen", (unsigned long)rxlen);
+
+ if (off+count >= len)
+ *eof = 1;
+ if (len < off)
+ return 0;
+ *start = page + off;
+ return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+EXPORT_SYMBOL(b1dma_reset);
+EXPORT_SYMBOL(t1pci_detect);
+EXPORT_SYMBOL(b1pciv4_detect);
+EXPORT_SYMBOL(b1dma_interrupt);
+
+EXPORT_SYMBOL(b1dma_load_firmware);
+EXPORT_SYMBOL(b1dma_reset_ctr);
+EXPORT_SYMBOL(b1dma_register_appl);
+EXPORT_SYMBOL(b1dma_release_appl);
+EXPORT_SYMBOL(b1dma_send_message);
+EXPORT_SYMBOL(b1dmactl_read_proc);
+
+#ifdef MODULE
+#define b1dma_init init_module
+void cleanup_module(void);
+#endif
+
+int b1dma_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 "b1dma: 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
index 01972b2d2..590e825b6 100644
--- a/drivers/isdn/avmb1/b1isa.c
+++ b/drivers/isdn/avmb1/b1isa.c
@@ -1,11 +1,19 @@
/*
- * $Id: b1isa.c,v 1.5 1999/11/05 16:38:01 calle Exp $
+ * $Id: b1isa.c,v 1.7 2000/02/02 18:36:03 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.7 2000/02/02 18:36:03 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.6 2000/01/25 14:37:39 calle
+ * new message after successfull detection including card revision and
+ * used resources.
+ *
* Revision 1.5 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -61,7 +69,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.5 $";
+static char *revision = "$Revision: 1.7 $";
/* ------------------------------------------------------------- */
@@ -69,10 +77,6 @@ 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;
@@ -96,6 +100,10 @@ static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
}
/* ------------------------------------------------------------- */
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
static void b1isa_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -122,10 +130,13 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
avmcard *card;
int retval;
+ MOD_INC_USE_COUNT;
+
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "b1isa: no memory.\n");
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
@@ -133,6 +144,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
if (!cinfo) {
printk(KERN_WARNING "b1isa: no memory.\n");
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
@@ -149,12 +161,14 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
if (b1_irq_table[card->irq & 0xf] == 0) {
printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EINVAL;
}
if ( card->port != 0x150 && card->port != 0x250
@@ -162,6 +176,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EINVAL;
}
b1_reset(card->port);
@@ -170,9 +185,11 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
b1_reset(card->port);
+ b1_getrevision(card);
request_region(p->port, AVMB1_PORTLEN, card->name);
@@ -182,6 +199,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
@@ -192,10 +210,14 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
- MOD_INC_USE_COUNT;
+ printk(KERN_INFO
+ "%s: AVM B1 ISA at i/o %#x, irq %d, revision %d\n",
+ driver->name, card->port, card->irq, card->revision);
+
return 0;
}
@@ -205,11 +227,12 @@ static char *b1isa_procinfo(struct capi_ctr *ctrl)
if (!cinfo)
return "";
- sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
- cinfo->card ? cinfo->card->irq : 0
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c
index f4e87b12f..f7affea0d 100644
--- a/drivers/isdn/avmb1/b1pci.c
+++ b/drivers/isdn/avmb1/b1pci.c
@@ -1,11 +1,20 @@
/*
- * $Id: b1pci.c,v 1.18 1999/11/05 16:38:01 calle Exp $
+ * $Id: b1pci.c,v 1.20 2000/02/02 18:36:03 calle Exp $
*
* Module for AVM B1 PCI-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1pci.c,v $
+ * Revision 1.20 2000/02/02 18:36:03 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.19 2000/01/25 14:33:38 calle
+ * - Added Support AVM B1 PCI V4.0 (tested with prototype)
+ * - splitted up t1pci.c into b1dma.c for common function with b1pciv4
+ * - support for revision register
+ *
* Revision 1.18 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -66,7 +75,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.18 $";
+static char *revision = "$Revision: 1.20 $";
/* ------------------------------------------------------------- */
@@ -138,11 +147,12 @@ static char *b1pci_procinfo(struct capi_ctr *ctrl)
if (!cinfo)
return "";
- sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
- cinfo->card ? cinfo->card->irq : 0
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
@@ -155,10 +165,13 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
avmctrl_info *cinfo;
int retval;
+ MOD_INC_USE_COUNT;
+
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
@@ -166,6 +179,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
@@ -182,6 +196,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
b1_reset(card->port);
@@ -190,9 +205,11 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
b1_reset(card->port);
+ b1_getrevision(card);
request_region(p->port, AVMB1_PORTLEN, card->name);
@@ -203,6 +220,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
@@ -214,10 +232,19 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
- MOD_INC_USE_COUNT;
+ if (card->revision >= 4) {
+ printk(KERN_INFO
+ "%s: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n",
+ driver->name, card->port, card->irq, card->revision);
+ } else {
+ printk(KERN_INFO
+ "%s: AVM B1 PCI at i/o %#x, irq %d, revision %d\n",
+ driver->name, card->port, card->irq, card->revision);
+ }
return 0;
}
@@ -241,6 +268,187 @@ static struct capi_driver b1pci_driver = {
0, /* no add_card function */
};
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface *div4;
+
+/* ------------------------------------------------------------- */
+
+static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+
+ b1dma_reset(card);
+
+ div4->detach_ctr(ctrl);
+ free_irq(card->irq, card);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ release_region(card->port, AVMB1_PORTLEN);
+ ctrl->driverdata = 0;
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
+}
+
+static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+ if (!cinfo)
+ return "";
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d",
+ cinfo->cardname[0] ? cinfo->cardname : "-",
+ cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+ cinfo->card ? cinfo->card->port : 0x0,
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->membase : 0,
+ cinfo->card ? cinfo->card->revision : 0
+ );
+ return cinfo->infobuf;
+}
+
+/* ------------------------------------------------------------- */
+
+static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p)
+{
+ unsigned long base, page_offset;
+ avmcard *card;
+ avmctrl_info *cinfo;
+ int retval;
+
+ card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+ if (!card) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ return -ENOMEM;
+ }
+ memset(card, 0, sizeof(avmcard));
+ card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+ if (!card->dma) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ kfree(card);
+ return -ENOMEM;
+ }
+ memset(card->dma, 0, sizeof(avmcard_dmainfo));
+ cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+ if (!cinfo) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ kfree(card->dma);
+ kfree(card);
+ return -ENOMEM;
+ }
+ memset(cinfo, 0, sizeof(avmctrl_info));
+ card->ctrlinfo = cinfo;
+ cinfo->card = card;
+ sprintf(card->name, "b1pciv4-%x", p->port);
+ card->port = p->port;
+ card->irq = p->irq;
+ card->membase = p->membase;
+ card->cardtype = avm_b1pci;
+
+ if (check_region(card->port, AVMB1_PORTLEN)) {
+ printk(KERN_WARNING
+ "%s: ports 0x%03x-0x%03x in use.\n",
+ driver->name, card->port, card->port + AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ base = card->membase & PAGE_MASK;
+ page_offset = card->membase - base;
+ card->mbase = ioremap_nocache(base, page_offset + 64);
+ if (card->mbase) {
+ card->mbase += page_offset;
+ } else {
+ printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
+ driver->name, card->membase);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ return -EIO;
+ }
+
+ b1dma_reset(card);
+
+ if ((retval = b1pciv4_detect(card)) != 0) {
+ printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+ driver->name, card->port, retval);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ return -EIO;
+ }
+ b1dma_reset(card);
+ b1_getrevision(card);
+
+ request_region(p->port, AVMB1_PORTLEN, card->name);
+
+ retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
+ if (retval) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+ driver->name, card->irq);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ return -EBUSY;
+ }
+
+ cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo);
+ if (!cinfo->capi_ctrl) {
+ printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ return -EBUSY;
+ }
+ card->cardnr = cinfo->capi_ctrl->cnr;
+
+ skb_queue_head_init(&card->dma->send_queue);
+
+ printk(KERN_INFO
+ "%s: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
+ driver->name, card->port, card->irq,
+ card->membase, card->revision);
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+
+static struct capi_driver b1pciv4_driver = {
+ "b1pciv4",
+ "0.0",
+ b1dma_load_firmware,
+ b1dma_reset_ctr,
+ b1pciv4_remove_ctr,
+ b1dma_register_appl,
+ b1dma_release_appl,
+ b1dma_send_message,
+
+ b1pciv4_procinfo,
+ b1dmactl_read_proc,
+ 0, /* use standard driver_read_proc */
+
+ 0, /* no add_card function */
+};
+
+#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
+
#ifdef MODULE
#define b1pci_init init_module
void cleanup_module(void);
@@ -248,9 +456,55 @@ void cleanup_module(void);
static int ncards = 0;
+static int add_card(struct pci_dev *dev)
+{
+ struct capi_driver *driver = &b1pci_driver;
+ struct capicardparams param;
+ int retval;
+
+ if (dev->resource[ 2].start & PCI_BASE_ADDRESS_IO_MASK) { /* B1 PCI V4 */
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ driver = &b1pciv4_driver;
+#endif
+ param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK;
+ param.port = dev->resource[ 2].start & PCI_BASE_ADDRESS_IO_MASK;
+ param.irq = dev->irq;
+ printk(KERN_INFO
+ "%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
+ driver->name, param.port, param.irq, param.membase);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ retval = b1pciv4_add_card(driver, &param);
+#else
+ retval = b1pci_add_card(driver, &param);
+#endif
+ if (retval != 0) {
+ printk(KERN_ERR
+ "%s: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n",
+ driver->name, param.port, param.irq, param.membase);
+ }
+ } else {
+ param.membase = 0;
+ param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK;
+ param.irq = dev->irq;
+ printk(KERN_INFO
+ "%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
+ "%s: no AVM-B1 at i/o %#x, irq %d detected\n",
+ driver->name, param.port, param.irq);
+ }
+ }
+ return retval;
+}
+
int b1pci_init(void)
{
struct capi_driver *driver = &b1pci_driver;
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ struct capi_driver *driverv4 = &b1pciv4_driver;
+#endif
struct pci_dev *dev = NULL;
char *p;
int retval;
@@ -271,26 +525,32 @@ int b1pci_init(void)
return -EIO;
}
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ printk(KERN_INFO "%s: revision %s\n", driverv4->name, driverv4->revision);
+
+ div4 = attach_capi_driver(driverv4);
+
+ if (!div4) {
+ detach_capi_driver(driver);
+ printk(KERN_ERR "%s: failed to attach capi_driver\n",
+ driverv4->name);
+ return -EIO;
+ }
+#endif
+
#ifdef CONFIG_PCI
if (!pci_present()) {
printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
detach_capi_driver(driver);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ detach_capi_driver(driverv4);
+#endif
return -EIO;
}
while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev))) {
- struct capicardparams param;
-
- param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK;
- param.irq = dev->irq;
- printk(KERN_INFO
- "%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);
+ retval = add_card(dev);
if (retval != 0) {
- printk(KERN_ERR
- "%s: no AVM-B1 at i/o %#x, irq %d detected\n",
- driver->name, param.port, param.irq);
#ifdef MODULE
cleanup_module();
#endif
@@ -315,5 +575,8 @@ int b1pci_init(void)
void cleanup_module(void)
{
detach_capi_driver(&b1pci_driver);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ detach_capi_driver(&b1pciv4_driver);
+#endif
}
#endif
diff --git a/drivers/isdn/avmb1/b1pcmcia.c b/drivers/isdn/avmb1/b1pcmcia.c
index 79e343164..6e39c43d2 100644
--- a/drivers/isdn/avmb1/b1pcmcia.c
+++ b/drivers/isdn/avmb1/b1pcmcia.c
@@ -1,11 +1,19 @@
/*
- * $Id: b1pcmcia.c,v 1.5 1999/11/05 16:38:01 calle Exp $
+ * $Id: b1pcmcia.c,v 1.7 2000/02/02 18:36:03 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.7 2000/02/02 18:36:03 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.6 2000/01/25 14:37:39 calle
+ * new message after successfull detection including card revision and
+ * used resources.
+ *
* Revision 1.5 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -62,7 +70,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.5 $";
+static char *revision = "$Revision: 1.7 $";
/* ------------------------------------------------------------- */
@@ -126,12 +134,16 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
{
avmctrl_info *cinfo;
avmcard *card;
+ char *cardname;
int retval;
+ MOD_INC_USE_COUNT;
+
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
@@ -139,6 +151,7 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
@@ -159,9 +172,11 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
driver->name, card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
b1_reset(card->port);
+ b1_getrevision(card);
retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card);
if (retval) {
@@ -169,6 +184,7 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
driver->name, card->irq);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
@@ -179,10 +195,19 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
free_irq(card->irq, card);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
+ switch (cardtype) {
+ case avm_m1: cardname = "M1"; break;
+ case avm_m2: cardname = "M2"; break;
+ default : cardname = "B1 PCMCIA"; break;
+ }
+
+ printk(KERN_INFO
+ "%s: AVM %s at i/o %#x, irq %d, revision %d\n",
+ driver->name, cardname, card->port, card->irq, card->revision);
- MOD_INC_USE_COUNT;
return cinfo->capi_ctrl->cnr;
}
@@ -194,11 +219,12 @@ static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
if (!cinfo)
return "";
- sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
- cinfo->card ? cinfo->card->irq : 0
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c
new file mode 100644
index 000000000..7483370cf
--- /dev/null
+++ b/drivers/isdn/avmb1/c4.c
@@ -0,0 +1,1326 @@
+/*
+ * $Id: c4.c,v 1.4 2000/02/02 18:36:03 calle Exp $
+ *
+ * Module for AVM C4 card.
+ *
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: c4.c,v $
+ * Revision 1.4 2000/02/02 18:36:03 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.3 2000/01/25 14:37:39 calle
+ * new message after successfull detection including card revision and
+ * used resources.
+ *
+ * Revision 1.2 2000/01/21 20:52:58 keil
+ * pci_find_subsys as local function for 2.2.X kernel
+ *
+ * Revision 1.1 2000/01/20 10:51:37 calle
+ * Added driver for C4.
+ *
+ *
+ */
+
+#include <linux/config.h>
+#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/pci.h>
+#include <linux/capi.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include "capicmd.h"
+#include "capiutil.h"
+#include "capilli.h"
+#include "avmcard.h"
+
+static char *revision = "$Revision: 1.4 $";
+
+#undef CONFIG_C4_DEBUG
+#undef CONFIG_C4_POLLDEBUG
+
+/* ------------------------------------------------------------- */
+
+#ifndef PCI_VENDOR_ID_DEC
+#define PCI_VENDOR_ID_DEC 0x1011
+#endif
+
+#ifndef PCI_DEVICE_ID_DEC_21285
+#define PCI_DEVICE_ID_DEC_21285 0x1065
+#endif
+
+#ifndef PCI_VENDOR_ID_AVM
+#define PCI_VENDOR_ID_AVM 0x1244
+#endif
+
+#ifndef PCI_DEVICE_ID_AVM_C4
+#define PCI_DEVICE_ID_AVM_C4 0x0800
+#endif
+
+/* ------------------------------------------------------------- */
+
+int suppress_pollack = 0;
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+MODULE_PARM(suppress_pollack, "0-1i");
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
+static void c4_dispatch_tx(avmcard *card);
+
+/* ------------------------------------------------------------- */
+
+#define DC21285_DRAM_A0MR 0x40000000
+#define DC21285_DRAM_A1MR 0x40004000
+#define DC21285_DRAM_A2MR 0x40008000
+#define DC21285_DRAM_A3MR 0x4000C000
+
+#define CAS_OFFSET 0x88
+
+#define DC21285_ARMCSR_BASE 0x42000000
+
+#define PCI_OUT_INT_STATUS 0x30
+#define PCI_OUT_INT_MASK 0x34
+#define MAILBOX_0 0x50
+#define MAILBOX_1 0x54
+#define MAILBOX_2 0x58
+#define MAILBOX_3 0x5C
+#define DOORBELL 0x60
+#define DOORBELL_SETUP 0x64
+
+#define CHAN_1_CONTROL 0x90
+#define CHAN_2_CONTROL 0xB0
+#define DRAM_TIMING 0x10C
+#define DRAM_ADDR_SIZE_0 0x110
+#define DRAM_ADDR_SIZE_1 0x114
+#define DRAM_ADDR_SIZE_2 0x118
+#define DRAM_ADDR_SIZE_3 0x11C
+#define SA_CONTROL 0x13C
+#define XBUS_CYCLE 0x148
+#define XBUS_STROBE 0x14C
+#define DBELL_PCI_MASK 0x150
+#define DBELL_SA_MASK 0x154
+
+#define SDRAM_SIZE 0x1000000
+
+/* ------------------------------------------------------------- */
+
+#define MBOX_PEEK_POKE MAILBOX_0
+
+#define DBELL_ADDR 0x01
+#define DBELL_DATA 0x02
+#define DBELL_RNWR 0x40
+#define DBELL_INIT 0x80
+
+/* ------------------------------------------------------------- */
+
+#define MBOX_UP_ADDR MAILBOX_0
+#define MBOX_UP_LEN MAILBOX_1
+#define MBOX_DOWN_ADDR MAILBOX_2
+#define MBOX_DOWN_LEN MAILBOX_3
+
+#define DBELL_UP_HOST 0x00000100
+#define DBELL_UP_ARM 0x00000200
+#define DBELL_DOWN_HOST 0x00000400
+#define DBELL_DOWN_ARM 0x00000800
+#define DBELL_RESET_HOST 0x40000000
+#define DBELL_RESET_ARM 0x80000000
+
+/* ------------------------------------------------------------- */
+
+#define DRAM_TIMING_DEF 0x001A01A5
+#define DRAM_AD_SZ_DEF0 0x00000045
+#define DRAM_AD_SZ_NULL 0x00000000
+
+#define SA_CTL_ALLRIGHT 0x64AA0271
+
+#define INIT_XBUS_CYCLE 0x100016DB
+#define INIT_XBUS_STROBE 0xF1F1F1F1
+
+/* ------------------------------------------------------------- */
+
+#define RESET_TIMEOUT (15*HZ) /* 15 sec */
+#define PEEK_POKE_TIMEOUT (HZ/10) /* 0.1 sec */
+
+/* ------------------------------------------------------------- */
+
+#define c4outmeml(addr, value) writel(value, addr)
+#define c4inmeml(addr) readl(addr)
+#define c4outmemw(addr, value) writew(value, addr)
+#define c4inmemw(addr) readw(addr)
+#define c4outmemb(addr, value) writeb(value, addr)
+#define c4inmemb(addr) readb(addr)
+
+/* ------------------------------------------------------------- */
+
+static inline int wait_for_doorbell(avmcard *card, unsigned long t)
+{
+ unsigned long stop;
+
+ stop = jiffies + t;
+ while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+ if (!time_before(jiffies, stop))
+ return -1;
+ }
+ return 0;
+}
+
+static int c4_poke(avmcard *card, unsigned long off, unsigned long value)
+{
+
+ if (wait_for_doorbell(card, HZ/10) < 0)
+ return -1;
+
+ c4outmeml(card->mbase+MBOX_PEEK_POKE, off);
+ c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+
+ if (wait_for_doorbell(card, HZ/10) < 0)
+ return -1;
+
+ c4outmeml(card->mbase+MBOX_PEEK_POKE, value);
+ c4outmeml(card->mbase+DOORBELL, DBELL_DATA | DBELL_ADDR);
+
+ return 0;
+}
+
+static int c4_peek(avmcard *card, unsigned long off, unsigned long *valuep)
+{
+ if (wait_for_doorbell(card, HZ/10) < 0)
+ return -1;
+
+ c4outmeml(card->mbase+MBOX_PEEK_POKE, off);
+ c4outmeml(card->mbase+DOORBELL, DBELL_RNWR | DBELL_ADDR);
+
+ if (wait_for_doorbell(card, HZ/10) < 0)
+ return -1;
+
+ *valuep = c4inmeml(card->mbase+MBOX_PEEK_POKE);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_load_t4file(avmcard *card, capiloaddatapart * t4file)
+{
+ __u32 val;
+ unsigned char *dp;
+ int left, retval;
+ __u32 loadoff = 0;
+
+ dp = t4file->data;
+ left = t4file->len;
+ while (left >= sizeof(__u32)) {
+ if (t4file->user) {
+ retval = copy_from_user(&val, dp, sizeof(val));
+ if (retval)
+ return -EFAULT;
+ } else {
+ memcpy(&val, dp, sizeof(val));
+ }
+ if (c4_poke(card, loadoff, val)) {
+ printk(KERN_ERR "%s: corrupted firmware file ?\n",
+ card->name);
+ return -EIO;
+ }
+ left -= sizeof(__u32);
+ dp += sizeof(__u32);
+ loadoff += sizeof(__u32);
+ }
+ if (left) {
+ val = 0;
+ if (t4file->user) {
+ retval = copy_from_user(&val, dp, left);
+ if (retval)
+ return -EFAULT;
+ } else {
+ memcpy(&val, dp, left);
+ }
+ if (c4_poke(card, loadoff, val)) {
+ printk(KERN_ERR "%s: corrupted firmware file ?\n",
+ card->name);
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static inline void _put_byte(void **pp, __u8 val)
+{
+ __u8 *s = *pp;
+ *s++ = val;
+ *pp = s;
+}
+
+static inline void _put_word(void **pp, __u32 val)
+{
+ __u8 *s = *pp;
+ *s++ = val & 0xff;
+ *s++ = (val >> 8) & 0xff;
+ *s++ = (val >> 16) & 0xff;
+ *s++ = (val >> 24) & 0xff;
+ *pp = s;
+}
+
+static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
+{
+ unsigned i = len;
+ _put_word(pp, i);
+ while (i-- > 0)
+ _put_byte(pp, *dp++);
+}
+
+static inline __u8 _get_byte(void **pp)
+{
+ __u8 *s = *pp;
+ __u8 val;
+ val = *s++;
+ *pp = s;
+ return val;
+}
+
+static inline __u32 _get_word(void **pp)
+{
+ __u8 *s = *pp;
+ __u32 val;
+ val = *s++;
+ val |= (*s++ << 8);
+ val |= (*s++ << 16);
+ val |= (*s++ << 24);
+ *pp = s;
+ return val;
+}
+
+static inline __u32 _get_slice(void **pp, unsigned char *dp)
+{
+ unsigned int len, i;
+
+ len = i = _get_word(pp);
+ while (i-- > 0) *dp++ = _get_byte(pp);
+ return len;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_reset(avmcard *card)
+{
+ unsigned long stop;
+
+ c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM);
+
+ stop = jiffies + HZ*10;
+ while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+ if (!time_before(jiffies, stop))
+ return;
+ c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+ }
+
+ c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
+ c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_detect(avmcard *card)
+{
+ unsigned long stop, dummy;
+
+ c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+ if (c4inmeml(card->mbase+PCI_OUT_INT_MASK) != 0x0c)
+ return 1;
+
+ c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM);
+
+ stop = jiffies + HZ*10;
+ while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+ if (!time_before(jiffies, stop))
+ return 2;
+ c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+ }
+
+ c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
+ c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
+
+ c4outmeml(card->mbase+MAILBOX_0, 0x55aa55aa);
+ if (c4inmeml(card->mbase+MAILBOX_0) != 0x55aa55aa) return 3;
+
+ c4outmeml(card->mbase+MAILBOX_0, 0xaa55aa55);
+ if (c4inmeml(card->mbase+MAILBOX_0) != 0xaa55aa55) return 4;
+
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_SA_MASK, 0)) return 5;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_PCI_MASK, 0)) return 6;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+SA_CONTROL, SA_CTL_ALLRIGHT))
+ return 7;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_CYCLE, INIT_XBUS_CYCLE))
+ return 8;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_STROBE, INIT_XBUS_STROBE))
+ return 8;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9;
+
+ udelay(1000);
+
+ if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10;
+ if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11;
+ if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12;
+ if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13;
+
+ if (c4_poke(card, DC21285_DRAM_A0MR+CAS_OFFSET, 0)) return 14;
+ if (c4_poke(card, DC21285_DRAM_A1MR+CAS_OFFSET, 0)) return 15;
+ if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16;
+ if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17;
+
+ udelay(1000);
+
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF))
+ return 18;
+
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_0,DRAM_AD_SZ_DEF0))
+ return 19;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_1,DRAM_AD_SZ_NULL))
+ return 20;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_2,DRAM_AD_SZ_NULL))
+ return 21;
+ if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_3,DRAM_AD_SZ_NULL))
+ return 22;
+
+ /* Transputer test */
+
+ if ( c4_poke(card, 0x000000, 0x11111111)
+ || c4_poke(card, 0x400000, 0x22222222)
+ || c4_poke(card, 0x800000, 0x33333333)
+ || c4_poke(card, 0xC00000, 0x44444444))
+ return 23;
+
+ if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111
+ || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222
+ || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333
+ || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444)
+ return 24;
+
+ if ( c4_poke(card, 0x000000, 0x55555555)
+ || c4_poke(card, 0x400000, 0x66666666)
+ || c4_poke(card, 0x800000, 0x77777777)
+ || c4_poke(card, 0xC00000, 0x88888888))
+ return 25;
+
+ if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555
+ || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666
+ || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777
+ || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888)
+ return 26;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_dispatch_tx(avmcard *card)
+{
+ avmcard_dmainfo *dma = card->dma;
+ unsigned long flags;
+ struct sk_buff *skb;
+ __u8 cmd, subcmd;
+ __u16 len;
+ __u32 txlen;
+ void *p;
+
+ save_flags(flags);
+ cli();
+
+ if (card->csr & DBELL_DOWN_ARM) { /* tx busy */
+ restore_flags(flags);
+ return;
+ }
+
+ skb = skb_dequeue(&dma->send_queue);
+ if (!skb) {
+#ifdef CONFIG_C4_DEBUG
+ printk(KERN_DEBUG "%s: tx underrun\n", card->name);
+#endif
+ restore_flags(flags);
+ return;
+ }
+
+ len = CAPIMSG_LEN(skb->data);
+
+ if (len) {
+ cmd = CAPIMSG_COMMAND(skb->data);
+ subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+ p = dma->sendbuf;
+
+ if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+ __u16 dlen = CAPIMSG_DATALEN(skb->data);
+ _put_byte(&p, SEND_DATA_B3_REQ);
+ _put_slice(&p, skb->data, len);
+ _put_slice(&p, skb->data + len, dlen);
+ } else {
+ _put_byte(&p, SEND_MESSAGE);
+ _put_slice(&p, skb->data, len);
+ }
+ txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+#ifdef CONFIG_C4_DEBUG
+ printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen);
+#endif
+ } else {
+ txlen = skb->len-2;
+#ifdef CONFIG_C4_POLLDEBUG
+ if (skb->data[2] == SEND_POLLACK)
+ printk(KERN_INFO "%s: ack to c4\n", card->name);
+#endif
+#ifdef CONFIG_C4_DEBUG
+ printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n",
+ card->name, skb->data[2], txlen);
+#endif
+ memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+ }
+ txlen = (txlen + 3) & ~3;
+
+ c4outmeml(card->mbase+MBOX_DOWN_ADDR, virt_to_phys(dma->sendbuf));
+ c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen);
+
+ card->csr |= DBELL_DOWN_ARM;
+
+ c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM);
+
+ restore_flags(flags);
+ dev_kfree_skb(skb);
+}
+
+/* ------------------------------------------------------------- */
+
+static void queue_pollack(avmcard *card)
+{
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(3, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost poll ack\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_POLLACK);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_handle_rx(avmcard *card)
+{
+ avmcard_dmainfo *dma = card->dma;
+ struct capi_ctr *ctrl;
+ avmctrl_info *cinfo;
+ struct sk_buff *skb;
+ void *p = dma->recvbuf;
+ __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+ __u8 b1cmd = _get_byte(&p);
+ __u32 cidx;
+
+
+#ifdef CONFIG_C4_DEBUG
+ printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name,
+ b1cmd, (unsigned long)dma->recvlen);
+#endif
+
+ switch (b1cmd) {
+ case RECEIVE_DATA_B3_IND:
+
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ DataB3Len = _get_slice(&p, card->databuf);
+ cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
+ if (cidx > 3) cidx = 0;
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+
+ if (MsgLen < 30) { /* not CAPI 64Bit */
+ memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
+ MsgLen = 30;
+ CAPIMSG_SETLEN(card->msgbuf, 30);
+ }
+ 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);
+ ctrl->handle_capimsg(ctrl, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_MESSAGE:
+
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
+ if (cidx > 3) cidx = 0;
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+
+ 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 = _get_word(&p);
+ NCCI = _get_word(&p);
+ WindowSize = _get_word(&p);
+ cidx = (NCCI&0x7f) - card->cardnr;
+ if (cidx > 3) cidx = 0;
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+
+ ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
+
+ break;
+
+ case RECEIVE_FREE_NCCI:
+
+ ApplId = _get_word(&p);
+ NCCI = _get_word(&p);
+
+ if (NCCI != 0xffffffff) {
+ cidx = (NCCI&0x7f) - card->cardnr;
+ if (cidx > 3) cidx = 0;
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+ ctrl->free_ncci(ctrl, ApplId, NCCI);
+ } else {
+ for (cidx=0; cidx < 4; cidx++) {
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+ ctrl->appl_released(ctrl, ApplId);
+ }
+ }
+ break;
+
+ case RECEIVE_START:
+#ifdef CONFIG_C4_POLLDEBUG
+ printk(KERN_INFO "%s: poll from c4\n", card->name);
+#endif
+ if (!suppress_pollack)
+ queue_pollack(card);
+ for (cidx=0; cidx < 4; cidx++) {
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+ ctrl->resume_output(ctrl);
+ }
+ break;
+
+ case RECEIVE_STOP:
+ for (cidx=0; cidx < 4; cidx++) {
+ ctrl = card->ctrlinfo[cidx].capi_ctrl;
+ ctrl->suspend_output(ctrl);
+ }
+ break;
+
+ case RECEIVE_INIT:
+
+ cidx = card->nlogcontr++;
+ cinfo = &card->ctrlinfo[cidx];
+ ctrl = cinfo->capi_ctrl;
+ cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
+ b1_parse_version(cinfo);
+ printk(KERN_INFO "%s: %s-card (%s) now active\n",
+ card->name,
+ cinfo->version[VER_CARDTYPE],
+ cinfo->version[VER_DRIVER]);
+ ctrl->ready(cinfo->capi_ctrl);
+ break;
+
+ case RECEIVE_TASK_READY:
+ ApplId = (unsigned) _get_word(&p);
+ MsgLen = _get_slice(&p, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
+ card->name, ApplId, card->msgbuf);
+ break;
+
+ case RECEIVE_DEBUGMSG:
+ MsgLen = _get_slice(&p, card->msgbuf);
+ card->msgbuf[MsgLen--] = 0;
+ while ( MsgLen >= 0
+ && ( card->msgbuf[MsgLen] == '\n'
+ || card->msgbuf[MsgLen] == '\r'))
+ card->msgbuf[MsgLen--] = 0;
+ printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
+ break;
+
+ default:
+ printk(KERN_ERR "%s: c4_interrupt: 0x%x ???\n",
+ card->name, b1cmd);
+ return;
+ }
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_handle_interrupt(avmcard *card)
+{
+ __u32 status = c4inmeml(card->mbase+DOORBELL);
+
+ if (status & DBELL_RESET_HOST) {
+ int i;
+ c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+ printk(KERN_ERR "%s: unexpected reset\n", card->name);
+ for (i=0; i < 4; i++) {
+ avmctrl_info *cinfo = &card->ctrlinfo[i];
+ memset(cinfo->version, 0, sizeof(cinfo->version));
+ if (cinfo->capi_ctrl)
+ cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
+ }
+ return;
+ }
+
+ status &= (DBELL_UP_HOST | DBELL_DOWN_HOST);
+ if (!status)
+ return;
+ c4outmeml(card->mbase+DOORBELL, status);
+
+ if ((status & DBELL_UP_HOST) != 0) {
+ card->dma->recvlen = c4inmeml(card->mbase+MBOX_UP_LEN);
+ c4outmeml(card->mbase+MBOX_UP_LEN, 0);
+ c4_handle_rx(card);
+ card->dma->recvlen = 0;
+ c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf));
+ c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
+ }
+
+ if ((status & DBELL_DOWN_HOST) != 0) {
+ card->csr &= ~DBELL_DOWN_ARM;
+ c4_dispatch_tx(card);
+ } else if (card->csr & DBELL_DOWN_HOST) {
+ if (c4inmeml(card->mbase+MBOX_DOWN_LEN) == 0) {
+ card->csr &= ~DBELL_DOWN_ARM;
+ c4_dispatch_tx(card);
+ }
+ }
+}
+
+static void c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+ avmcard *card;
+
+ card = (avmcard *) devptr;
+
+ if (!card) {
+ printk(KERN_WARNING "%s: interrupt: wrong device\n", card->name);
+ return;
+ }
+ if (card->interrupt) {
+ printk(KERN_ERR "%s: reentering interrupt hander\n",
+ card->name);
+ return;
+ }
+
+ card->interrupt = 1;
+
+ c4_handle_interrupt(card);
+
+ card->interrupt = 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_send_init(avmcard *card)
+{
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(15, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_INIT);
+ _put_word(&p, AVM_NAPPS);
+ _put_word(&p, AVM_NCCI_PER_CHANNEL*30);
+ _put_word(&p, card->cardnr - 1);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+}
+
+static int c4_send_config(avmcard *card, capiloaddatapart * config)
+{
+ struct sk_buff *skb;
+ __u8 val[sizeof(__u32)];
+ void *p;
+ unsigned char *dp;
+ int left, retval;
+
+ skb = alloc_skb(12 + ((config->len+3)/4)*5, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, can't send config.\n",
+ card->name);
+ return -ENOMEM;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_CONFIG);
+ _put_word(&p, 1);
+ _put_byte(&p, SEND_CONFIG);
+ _put_word(&p, config->len); /* 12 */
+
+ dp = config->data;
+ left = config->len;
+ while (left >= sizeof(__u32)) {
+ if (config->user) {
+ retval = copy_from_user(val, dp, sizeof(val));
+ if (retval) {
+ dev_kfree_skb(skb);
+ return -EFAULT;
+ }
+ } else {
+ memcpy(val, dp, sizeof(val));
+ }
+ _put_byte(&p, SEND_CONFIG);
+ _put_byte(&p, val[0]);
+ _put_byte(&p, val[1]);
+ _put_byte(&p, val[2]);
+ _put_byte(&p, val[3]);
+ left -= sizeof(val);
+ dp += sizeof(val);
+ }
+ if (left) {
+ memset(val, 0, sizeof(val));
+ if (config->user) {
+ retval = copy_from_user(&val, dp, left);
+ if (retval) {
+ dev_kfree_skb(skb);
+ return -EFAULT;
+ }
+ } else {
+ memcpy(&val, dp, left);
+ }
+ _put_byte(&p, SEND_CONFIG);
+ _put_byte(&p, val[0]);
+ _put_byte(&p, val[1]);
+ _put_byte(&p, val[2]);
+ _put_byte(&p, val[3]);
+ }
+
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+
+ return 0;
+}
+
+static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ unsigned long flags;
+ int retval;
+
+ if ((retval = c4_load_t4file(card, &data->firmware))) {
+ printk(KERN_ERR "%s: failed to load t4file!!\n",
+ card->name);
+ c4_reset(card);
+ return retval;
+ }
+
+ save_flags(flags);
+ cli();
+
+ card->csr = 0;
+ c4outmeml(card->mbase+MBOX_UP_LEN, 0);
+ c4outmeml(card->mbase+MBOX_DOWN_LEN, 0);
+ c4outmeml(card->mbase+DOORBELL, DBELL_INIT);
+ udelay(1000);
+ c4outmeml(card->mbase+DOORBELL,
+ DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST);
+
+ c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08);
+
+ card->dma->recvlen = 0;
+ c4outmeml(card->mbase+MBOX_UP_ADDR, virt_to_phys(card->dma->recvbuf));
+ c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf));
+ c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
+ restore_flags(flags);
+
+ if (data->configuration.len > 0 && data->configuration.data)
+ c4_send_config(card, &data->configuration);
+
+ c4_send_init(card);
+
+ return 0;
+}
+
+
+void c4_reset_ctr(struct capi_ctr *ctrl)
+{
+ avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
+ avmctrl_info *cinfo;
+ int i;
+
+ c4_reset(card);
+
+ for (i=0; i < 4; i++) {
+ cinfo = &card->ctrlinfo[i];
+ memset(cinfo->version, 0, sizeof(cinfo->version));
+ if (cinfo->capi_ctrl)
+ cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
+ }
+}
+
+static void c4_remove_ctr(struct capi_ctr *ctrl)
+{
+ avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
+ avmctrl_info *cinfo;
+ int i;
+
+ c4_reset(card);
+
+ for (i=0; i <= 4; i++) {
+ cinfo = &card->ctrlinfo[i];
+ if (cinfo->capi_ctrl)
+ di->detach_ctr(cinfo->capi_ctrl);
+ }
+
+ free_irq(card->irq, card);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ release_region(card->port, AVMB1_PORTLEN);
+ ctrl->driverdata = 0;
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+
+ MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------- */
+
+
+void c4_register_appl(struct capi_ctr *ctrl,
+ __u16 appl,
+ capi_register_params *rp)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ struct sk_buff *skb;
+ int want = rp->level3cnt;
+ int nconn;
+ void *p;
+
+ if (ctrl->cnr == card->cardnr) {
+
+ if (want > 0) nconn = want;
+ else nconn = ctrl->profile.nbchannel * 4 * -want;
+ if (nconn == 0) nconn = ctrl->profile.nbchannel * 4;
+
+ skb = alloc_skb(23, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_REGISTER);
+ _put_word(&p, appl);
+ _put_word(&p, 1024 * (nconn+1));
+ _put_word(&p, nconn);
+ _put_word(&p, rp->datablkcnt);
+ _put_word(&p, rp->datablklen);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+ }
+
+ ctrl->appl_registered(ctrl, appl);
+}
+
+/* ------------------------------------------------------------- */
+
+void c4_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ struct sk_buff *skb;
+ void *p;
+
+ if (ctrl->cnr == card->cardnr) {
+ skb = alloc_skb(7, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, lost release appl.\n",
+ card->name);
+ return;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
+ _put_byte(&p, SEND_RELEASE);
+ _put_word(&p, appl);
+
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+ }
+}
+
+/* ------------------------------------------------------------- */
+
+
+static void c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static char *c4_procinfo(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+ if (!cinfo)
+ return "";
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
+ cinfo->cardname[0] ? cinfo->cardname : "-",
+ cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+ cinfo->card ? cinfo->card->port : 0x0,
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->membase : 0
+ );
+ return cinfo->infobuf;
+}
+
+static int c4_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+ avmcard *card = cinfo->card;
+ __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);
+ len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+ 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 ((s = cinfo->version[VER_DRIVER]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+ if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+ if ((s = cinfo->version[VER_SERIAL]) != 0)
+ len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+
+ 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", cinfo->cardname);
+
+ if (off+count >= len)
+ *eof = 1;
+ if (len < off)
+ return 0;
+ *start = page + off;
+ return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_add_card(struct capi_driver *driver, struct capicardparams *p)
+{
+ unsigned long base, page_offset;
+ avmctrl_info *cinfo;
+ avmcard *card;
+ int retval;
+ int i;
+
+ MOD_INC_USE_COUNT;
+
+ card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+ if (!card) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+ memset(card, 0, sizeof(avmcard));
+ card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+ if (!card->dma) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+ memset(card->dma, 0, sizeof(avmcard_dmainfo));
+ cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
+ if (!cinfo) {
+ printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+ memset(cinfo, 0, sizeof(avmctrl_info)*4);
+ card->ctrlinfo = cinfo;
+ for (i=0; i < 4; i++) {
+ cinfo = &card->ctrlinfo[i];
+ cinfo->card = card;
+ }
+ sprintf(card->name, "c4-%x", p->port);
+ card->port = p->port;
+ card->irq = p->irq;
+ card->membase = p->membase;
+ card->cardtype = avm_c4;
+
+ if (check_region(card->port, AVMB1_PORTLEN)) {
+ printk(KERN_WARNING
+ "%s: ports 0x%03x-0x%03x in use.\n",
+ driver->name, card->port, card->port + AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+
+ base = card->membase & PAGE_MASK;
+ page_offset = card->membase - base;
+ card->mbase = ioremap_nocache(base, page_offset + 128);
+ if (card->mbase) {
+ card->mbase += page_offset;
+ } else {
+ printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
+ driver->name, card->membase);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
+
+ if ((retval = c4_detect(card)) != 0) {
+ printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+ driver->name, card->port, retval);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
+ c4_reset(card);
+
+ request_region(p->port, AVMB1_PORTLEN, card->name);
+
+ retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
+ if (retval) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+ driver->name, card->irq);
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+
+ for (i=0; i < 4; i++) {
+ cinfo = &card->ctrlinfo[i];
+ cinfo->card = card;
+ cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+ if (!cinfo->capi_ctrl) {
+ printk(KERN_ERR "%s: attach controller failed (%d).\n",
+ driver->name, i);
+ for (i--; i >= 0; i--) {
+ cinfo = &card->ctrlinfo[i];
+ di->detach_ctr(cinfo->capi_ctrl);
+ }
+ iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+ free_irq(card->irq, card);
+ release_region(card->port, AVMB1_PORTLEN);
+ kfree(card->dma);
+ kfree(card->ctrlinfo);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+ if (i == 0)
+ card->cardnr = cinfo->capi_ctrl->cnr;
+ }
+
+ skb_queue_head_init(&card->dma->send_queue);
+
+ printk(KERN_INFO
+ "%s: AVM C4 at i/o %#x, irq %d, mem %#lx\n",
+ driver->name, card->port, card->irq, card->membase);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver c4_driver = {
+ "c4",
+ "0.0",
+ c4_load_firmware,
+ c4_reset_ctr,
+ c4_remove_ctr,
+ c4_register_appl,
+ c4_release_appl,
+ c4_send_message,
+
+ c4_procinfo,
+ c4_read_proc,
+ 0, /* use standard driver_read_proc */
+
+ 0, /* no add_card function */
+};
+
+#ifdef MODULE
+#define c4_init init_module
+void cleanup_module(void);
+#endif
+
+
+static int ncards = 0;
+
+int c4_init(void)
+{
+ struct capi_driver *driver = &c4_driver;
+ struct pci_dev *dev = NULL;
+ char *p;
+ int retval;
+
+ 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;
+ }
+
+#ifdef CONFIG_PCI
+ if (!pci_present()) {
+ printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
+ detach_capi_driver(driver);
+ return -EIO;
+ }
+
+ while ((dev = pci_find_subsys(
+ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285,
+ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, dev))) {
+ struct capicardparams param;
+
+ param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK;
+ param.irq = dev->irq;
+ param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK;
+
+ printk(KERN_INFO
+ "%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n",
+ driver->name, param.port, param.irq, param.membase);
+ retval = c4_add_card(driver, &param);
+ if (retval != 0) {
+ printk(KERN_ERR
+ "%s: no AVM-C4 at i/o %#x, irq %d detected, mem %#x\n",
+ driver->name, param.port, param.irq, param.membase);
+#ifdef MODULE
+ cleanup_module();
+#endif
+ return retval;
+ }
+ ncards++;
+ }
+ if (ncards) {
+ printk(KERN_INFO "%s: %d C4 card(s) detected\n",
+ driver->name, ncards);
+ return 0;
+ }
+ printk(KERN_ERR "%s: NO C4 card detected\n", driver->name);
+ return -ESRCH;
+#else
+ printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+ return -EIO;
+#endif
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ detach_capi_driver(&c4_driver);
+}
+#endif
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index 6214a7c75..62f246407 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -128,6 +128,7 @@
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
+#include <linux/devfs_fs_kernel.h>
#include "capiutil.h"
#include "capicmd.h"
@@ -511,13 +512,18 @@ capi_release(struct inode *inode, struct file *file)
static struct file_operations capi_fops =
{
- llseek: capi_llseek,
- read: capi_read,
- write: capi_write,
- poll: capi_poll,
- ioctl: capi_ioctl,
- open: capi_open,
- release: capi_release,
+ capi_llseek,
+ capi_read,
+ capi_write,
+ NULL, /* capi_readdir */
+ capi_poll,
+ capi_ioctl,
+ NULL, /* capi_mmap */
+ capi_open,
+ NULL, /* capi_flush */
+ capi_release,
+ NULL, /* capi_fsync */
+ NULL, /* capi_fasync */
};
/* -------- /proc functions ----------------------------------- */
@@ -616,14 +622,36 @@ int capi_init(void)
init_waitqueue_head(&capidevs[j].recv_wait);
}
- if (register_chrdev(capi_major, "capi20", &capi_fops)) {
+ if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) {
printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
return -EIO;
}
+ devfs_register (NULL, "isdn/capi20", 0, DEVFS_FL_DEFAULT,
+ capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &capi_fops, NULL);
+ devfs_register_series (NULL, "isdn/capi20.0%u", 10, DEVFS_FL_DEFAULT,
+ capi_major, 1,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &capi_fops, NULL);
+ devfs_register_series (NULL, "isdn/capi20.1%u", 10, DEVFS_FL_DEFAULT,
+ capi_major, 11,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &capi_fops, NULL);
printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
if ((capifuncs = attach_capi_interface(&cuser)) == 0) {
- unregister_chrdev(capi_major, "capi20");
+ devfs_unregister_chrdev(capi_major, "capi20");
+ devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
+ capi_major, 0,
+ DEVFS_SPECIAL_CHR, 0));
+ for (j = 0; j < 10; j++) {
+ char devname[32];
+
+ sprintf(devname, "isdn/capi20.0%i", j);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 1, DEVFS_SPECIAL_CHR, 0));
+ sprintf (devname, "isdn/capi20.1%i", j);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 11, DEVFS_SPECIAL_CHR, 0));
+ }
return -EIO;
}
(void)proc_init();
@@ -633,8 +661,18 @@ int capi_init(void)
#ifdef MODULE
void cleanup_module(void)
{
+ int i;
+ char devname[32];
+
(void)proc_exit();
- unregister_chrdev(capi_major, "capi20");
+ devfs_unregister_chrdev(capi_major, "capi20");
+ devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", 0, capi_major, 0, DEVFS_SPECIAL_CHR, 0));
+ for (i = 0; i < 10; i++) {
+ sprintf (devname, "isdn/capi20.0%i", i);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 1, DEVFS_SPECIAL_CHR, 0));
+ sprintf (devname, "isdn/capi20.1%i", i);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 11, DEVFS_SPECIAL_CHR, 0));
+ }
(void) detach_capi_interface(&cuser);
}
diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c
index 6db170e42..79bb370d1 100644
--- a/drivers/isdn/avmb1/capidrv.c
+++ b/drivers/isdn/avmb1/capidrv.c
@@ -1,11 +1,14 @@
/*
- * $Id: capidrv.c,v 1.28 1999/11/05 16:22:37 calle Exp $
+ * $Id: capidrv.c,v 1.29 1999/12/06 17:13:06 calle Exp $
*
* ISDN4Linux Driver, using capi20 interface (kernelcapi)
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capidrv.c,v $
+ * Revision 1.29 1999/12/06 17:13:06 calle
+ * Added controller watchdog.
+ *
* Revision 1.28 1999/11/05 16:22:37 calle
* Bugfix: Missing break in switch on ISDN_CMD_HANGUP.
*
@@ -168,7 +171,7 @@
#include "capicmd.h"
#include "capidrv.h"
-static char *revision = "$Revision: 1.28 $";
+static char *revision = "$Revision: 1.29 $";
int debugmode = 0;
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -196,6 +199,7 @@ struct capidrv_contr {
int state;
__u32 cipmask;
__u32 cipmask2;
+ struct timer_list listentimer;
/*
* ID of capi message sent
@@ -2188,6 +2192,29 @@ static void disable_dchannel_trace(capidrv_contr *card)
send_message(card, &cmdcmsg);
}
+static void send_listen(capidrv_contr *card)
+{
+ capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
+ card->msgid++,
+ card->contrnr, /* controller */
+ 1 << 6, /* Infomask */
+ card->cipmask,
+ card->cipmask2,
+ 0, 0);
+ send_message(card, &cmdcmsg);
+ listen_change_state(card, EV_LISTEN_REQ);
+}
+
+static void listentimerfunc(unsigned long x)
+{
+ capidrv_contr *card = (capidrv_contr *)x;
+ if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
+ printk(KERN_ERR "%s: controller dead ??\n", card->name);
+ send_listen(card);
+ mod_timer(&card->listentimer, jiffies + 60*HZ);
+}
+
+
static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
{
capidrv_contr *card;
@@ -2202,6 +2229,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
return -1;
}
memset(card, 0, sizeof(capidrv_contr));
+ init_timer(&card->listentimer);
strcpy(card->name, id);
card->contrnr = contr;
card->nbchan = profp->nbchannel;
@@ -2258,15 +2286,11 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
card->cipmask = 0x1FFF03FF; /* any */
card->cipmask2 = 0;
- capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
- card->msgid++,
- contr, /* controller */
- 1 << 6, /* Infomask */
- card->cipmask,
- card->cipmask2,
- 0, 0);
- send_message(card, &cmdcmsg);
- listen_change_state(card, EV_LISTEN_REQ);
+ send_listen(card);
+
+ card->listentimer.data = (unsigned long)card;
+ card->listentimer.function = listentimerfunc;
+ mod_timer(&card->listentimer, jiffies + 60*HZ);
printk(KERN_INFO "%s: now up (%d B channels)\n",
card->name, card->nbchan);
@@ -2312,6 +2336,7 @@ static int capidrv_delcontr(__u16 contr)
printk(KERN_ERR "capidrv: bug in free_plci()\n");
}
kfree(card->bchans);
+ del_timer(&card->listentimer);
printk(KERN_INFO "%s: now down.\n", card->name);
diff --git a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c
index 84fb0d2f7..d82fbc496 100644
--- a/drivers/isdn/avmb1/kcapi.c
+++ b/drivers/isdn/avmb1/kcapi.c
@@ -1,11 +1,18 @@
/*
- * $Id: kcapi.c,v 1.10 1999/10/26 15:30:32 calle Exp $
+ * $Id: kcapi.c,v 1.12 2000/01/28 16:45:39 calle Exp $
*
* Kernel CAPI 2.0 Module
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: kcapi.c,v $
+ * Revision 1.12 2000/01/28 16:45:39 calle
+ * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
+ * will search named driver and call the add_card function if one exist.
+ *
+ * Revision 1.11 1999/11/23 13:29:29 calle
+ * Bugfix: incoming capi message were never traced.
+ *
* Revision 1.10 1999/10/26 15:30:32 calle
* Generate error message if user want to add card, but driver module is
* not loaded.
@@ -79,7 +86,7 @@
#include <linux/b1lli.h>
#endif
-static char *revision = "$Revision: 1.10 $";
+static char *revision = "$Revision: 1.12 $";
/* ------------------------------------------------------------- */
@@ -154,10 +161,6 @@ 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;
@@ -703,9 +706,9 @@ static void controllercb_handle_capimsg(struct capi_ctr * card,
if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
card->nrecvdatapkt++;
if (card->traceflag > 2) showctl |= 2;
- if (card->traceflag) showctl |= 2;
} else {
card->nrecvctlpkt++;
+ if (card->traceflag) showctl |= 2;
}
showctl |= (card->traceflag & 1);
if (showctl & 2) {
@@ -877,8 +880,14 @@ drivercb_attach_ctr(struct capi_driver *driver, char *name, void *driverdata)
*pp = card;
driver->ncontroller++;
sprintf(card->procfn, "capi/controllers/%d", card->cnr);
- card->procent = create_proc_read_entry(card->procfn, 0, 0,
- driver->ctr_read_proc, card);
+ 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);
@@ -947,18 +956,18 @@ struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver)
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_read_entry(driver->procfn, 0, 0,
- driver->driver_read_proc
- ? driver->driver_read_proc
- : driver_read_proc,
- driver);
+ 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;
}
@@ -968,10 +977,6 @@ void detach_capi_driver(struct capi_driver *driver)
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);
@@ -1186,6 +1191,15 @@ static __u16 capi_get_profile(__u32 contr, struct capi_profile *profp)
return CAPI_NOERROR;
}
+static struct capi_driver *find_driver(char *name)
+{
+ struct capi_driver *dp;
+ for (dp = drivers; dp; dp = dp->next)
+ if (strcmp(dp->name, name) == 0)
+ return dp;
+ return 0;
+}
+
#ifdef CONFIG_AVMB1_COMPAT
static int old_capi_manufacturer(unsigned int cmd, void *data)
{
@@ -1217,9 +1231,15 @@ static int old_capi_manufacturer(unsigned int cmd, void *data)
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;
+ case AVM_CARDTYPE_B1:
+ driver = find_driver("b1isa");
+ break;
+ case AVM_CARDTYPE_T1:
+ driver = find_driver("t1isa");
+ break;
+ default:
+ driver = 0;
+ break;
}
if (!driver) {
printk(KERN_ERR "kcapi: driver not loaded.\n");
@@ -1331,9 +1351,7 @@ static int old_capi_manufacturer(unsigned int cmd, void *data)
return -ESRCH;
gdef.cardstate = card->cardstate;
- if (card->driver == b1isa_driver)
- gdef.cardtype = AVM_CARDTYPE_B1;
- else if (card->driver == t1isa_driver)
+ if (card->driver == find_driver("t1isa"))
gdef.cardtype = AVM_CARDTYPE_T1;
else gdef.cardtype = AVM_CARDTYPE_B1;
@@ -1377,7 +1395,6 @@ static int old_capi_manufacturer(unsigned int cmd, void *data)
static int capi_manufacturer(unsigned int cmd, void *data)
{
struct capi_ctr *card;
- kcapi_flagdef fdef;
int retval;
switch (cmd) {
@@ -1392,6 +1409,9 @@ static int capi_manufacturer(unsigned int cmd, void *data)
return old_capi_manufacturer(cmd, data);
#endif
case KCAPI_CMD_TRACE:
+ {
+ kcapi_flagdef fdef;
+
if ((retval = copy_from_user((void *) &fdef, data,
sizeof(kcapi_flagdef))))
return retval;
@@ -1406,6 +1426,44 @@ static int capi_manufacturer(unsigned int cmd, void *data)
card->cnr, card->traceflag);
return 0;
}
+
+ case KCAPI_CMD_ADDCARD:
+ {
+ struct capi_driver *driver;
+ capicardparams cparams;
+ kcapi_carddef cdef;
+
+ if ((retval = copy_from_user((void *) &cdef, data,
+ sizeof(cdef))))
+ return retval;
+
+ cparams.port = cdef.port;
+ cparams.irq = cdef.irq;
+ cparams.membase = cdef.membase;
+ cparams.cardnr = cdef.cardnr;
+ cparams.cardtype = 0;
+ cdef.driver[sizeof(cdef.driver)-1] = 0;
+
+ if ((driver = find_driver(cdef.driver)) == 0) {
+ printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
+ cdef.driver);
+ return -ESRCH;
+ }
+
+ if (!driver->add_card) {
+ printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
+ return -EIO;
+ }
+
+ return driver->add_card(driver, &cparams);
+ }
+
+ default:
+ printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
+ cmd);
+ break;
+
+ }
return -EINVAL;
}
diff --git a/drivers/isdn/avmb1/t1isa.c b/drivers/isdn/avmb1/t1isa.c
index 22a07f2ad..e1efd3939 100644
--- a/drivers/isdn/avmb1/t1isa.c
+++ b/drivers/isdn/avmb1/t1isa.c
@@ -1,11 +1,19 @@
/*
- * $Id: t1isa.c,v 1.8 1999/11/05 16:38:01 calle Exp $
+ * $Id: t1isa.c,v 1.10 2000/02/02 18:36:04 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.10 2000/02/02 18:36:04 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.9 2000/01/25 14:37:39 calle
+ * new message after successfull detection including card revision and
+ * used resources.
+ *
* Revision 1.8 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
@@ -73,7 +81,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.8 $";
+static char *revision = "$Revision: 1.10 $";
/* ------------------------------------------------------------- */
@@ -413,10 +421,13 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
avmcard *card;
int retval;
+ MOD_INC_USE_COUNT;
+
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
@@ -424,6 +435,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
@@ -440,6 +452,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->port);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EINVAL;
}
@@ -449,6 +462,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
if (hema_irq_table[card->irq & 0xf] == 0) {
@@ -456,6 +470,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->irq);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EINVAL;
}
for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) {
@@ -465,6 +480,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->cardnr, cardp->port);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
}
@@ -473,6 +489,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
driver->name, card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
t1_disable_irq(card->port);
@@ -487,6 +504,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
@@ -498,10 +516,14 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
- MOD_INC_USE_COUNT;
+ printk(KERN_INFO
+ "%s: AVM T1 ISA at i/o %#x, irq %d, card %d\n",
+ driver->name, card->port, card->irq, card->cardnr);
+
return 0;
}
diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c
index d77340bff..d24894d9b 100644
--- a/drivers/isdn/avmb1/t1pci.c
+++ b/drivers/isdn/avmb1/t1pci.c
@@ -1,11 +1,20 @@
/*
- * $Id: t1pci.c,v 1.3 1999/11/13 21:27:16 keil Exp $
+ * $Id: t1pci.c,v 1.5 2000/02/02 18:36:04 calle Exp $
*
* Module for AVM T1 PCI-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: t1pci.c,v $
+ * Revision 1.5 2000/02/02 18:36:04 calle
+ * - Modules are now locked while init_module is running
+ * - fixed problem with memory mapping if address is not aligned
+ *
+ * Revision 1.4 2000/01/25 14:33:38 calle
+ * - Added Support AVM B1 PCI V4.0 (tested with prototype)
+ * - splitted up t1pci.c into b1dma.c for common function with b1pciv4
+ * - support for revision register
+ *
* Revision 1.3 1999/11/13 21:27:16 keil
* remove KERNELVERSION
*
@@ -38,7 +47,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.3 $";
+static char *revision = "$Revision: 1.5 $";
#undef CONFIG_T1PCI_DEBUG
#undef CONFIG_T1PCI_POLLDEBUG
@@ -55,712 +64,20 @@ static char *revision = "$Revision: 1.3 $";
/* ------------------------------------------------------------- */
-int suppress_pollack = 0;
-
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
-MODULE_PARM(suppress_pollack, "0-1i");
-
-
/* ------------------------------------------------------------- */
static struct capi_driver_interface *di;
/* ------------------------------------------------------------- */
-static void t1pci_dispatch_tx(avmcard *card);
-
-/* ------------------------------------------------------------- */
-
-/* S5933 */
-
-#define AMCC_RXPTR 0x24
-#define AMCC_RXLEN 0x28
-#define AMCC_TXPTR 0x2c
-#define AMCC_TXLEN 0x30
-
-#define AMCC_INTCSR 0x38
-# define EN_READ_TC_INT 0x00008000L
-# define EN_WRITE_TC_INT 0x00004000L
-# define EN_TX_TC_INT EN_READ_TC_INT
-# define EN_RX_TC_INT EN_WRITE_TC_INT
-# define AVM_FLAG 0x30000000L
-
-# define ANY_S5933_INT 0x00800000L
-# define READ_TC_INT 0x00080000L
-# define WRITE_TC_INT 0x00040000L
-# define TX_TC_INT READ_TC_INT
-# define RX_TC_INT WRITE_TC_INT
-# define MASTER_ABORT_INT 0x00100000L
-# define TARGET_ABORT_INT 0x00200000L
-# define BUS_MASTER_INT 0x00200000L
-# define ALL_INT 0x000C0000L
-
-#define AMCC_MCSR 0x3c
-# define A2P_HI_PRIORITY 0x00000100L
-# define EN_A2P_TRANSFERS 0x00000400L
-# define P2A_HI_PRIORITY 0x00001000L
-# define EN_P2A_TRANSFERS 0x00004000L
-# define RESET_A2P_FLAGS 0x04000000L
-# define RESET_P2A_FLAGS 0x02000000L
-
-/* ------------------------------------------------------------- */
-
-#define t1outmeml(addr, value) writel(value, addr)
-#define t1inmeml(addr) readl(addr)
-#define t1outmemw(addr, value) writew(value, addr)
-#define t1inmemw(addr) readw(addr)
-#define t1outmemb(addr, value) writeb(value, addr)
-#define t1inmemb(addr) readb(addr)
-
-/* ------------------------------------------------------------- */
-
-static inline int t1pci_tx_empty(unsigned int port)
-{
- return inb(port + 0x03) & 0x1;
-}
-
-static inline int t1pci_rx_full(unsigned int port)
-{
- return inb(port + 0x02) & 0x1;
-}
-
-static int t1pci_tolink(avmcard *card, void *buf, unsigned int len)
-{
- unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
- unsigned char *s = (unsigned char *)buf;
- while (len--) {
- while ( !t1pci_tx_empty(card->port)
- && time_before(jiffies, stop));
- if (!t1pci_tx_empty(card->port))
- return -1;
- t1outp(card->port, 0x01, *s++);
- }
- return 0;
-}
-
-static int t1pci_fromlink(avmcard *card, void *buf, unsigned int len)
-{
- unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
- unsigned char *s = (unsigned char *)buf;
- while (len--) {
- while ( !t1pci_rx_full(card->port)
- && time_before(jiffies, stop));
- if (!t1pci_rx_full(card->port))
- return -1;
- *s++ = t1inp(card->port, 0x00);
- }
- return 0;
-}
-
-static int WriteReg(avmcard *card, __u32 reg, __u8 val)
-{
- __u8 cmd = 0x00;
- if ( t1pci_tolink(card, &cmd, 1) == 0
- && t1pci_tolink(card, &reg, 4) == 0) {
- __u32 tmp = val;
- return t1pci_tolink(card, &tmp, 4);
- }
- return -1;
-}
-
-static __u8 ReadReg(avmcard *card, __u32 reg)
-{
- __u8 cmd = 0x01;
- if ( t1pci_tolink(card, &cmd, 1) == 0
- && t1pci_tolink(card, &reg, 4) == 0) {
- __u32 tmp;
- if (t1pci_fromlink(card, &tmp, 4) == 0)
- return (__u8)tmp;
- }
- return 0xff;
-}
-
-/* ------------------------------------------------------------- */
-
-static inline void _put_byte(void **pp, __u8 val)
-{
- __u8 *s = *pp;
- *s++ = val;
- *pp = s;
-}
-
-static inline void _put_word(void **pp, __u32 val)
-{
- __u8 *s = *pp;
- *s++ = val & 0xff;
- *s++ = (val >> 8) & 0xff;
- *s++ = (val >> 16) & 0xff;
- *s++ = (val >> 24) & 0xff;
- *pp = s;
-}
-
-static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
-{
- unsigned i = len;
- _put_word(pp, i);
- while (i-- > 0)
- _put_byte(pp, *dp++);
-}
-
-static inline __u8 _get_byte(void **pp)
-{
- __u8 *s = *pp;
- __u8 val;
- val = *s++;
- *pp = s;
- return val;
-}
-
-static inline __u32 _get_word(void **pp)
-{
- __u8 *s = *pp;
- __u32 val;
- val = *s++;
- val |= (*s++ << 8);
- val |= (*s++ << 16);
- val |= (*s++ << 24);
- *pp = s;
- return val;
-}
-
-static inline __u32 _get_slice(void **pp, unsigned char *dp)
-{
- unsigned int len, i;
-
- len = i = _get_word(pp);
- while (i-- > 0) *dp++ = _get_byte(pp);
- return len;
-}
-
-/* ------------------------------------------------------------- */
-
-static void t1pci_reset(avmcard *card)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- card->csr = 0x0;
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
- t1outmeml(card->mbase+AMCC_MCSR, 0);
- t1outmeml(card->mbase+AMCC_RXLEN, 0);
- t1outmeml(card->mbase+AMCC_TXLEN, 0);
-
- t1outp(card->port, T1_RESETLINK, 0x00);
- t1outp(card->port, 0x07, 0x00);
-
- restore_flags(flags);
-
- t1outmeml(card->mbase+AMCC_MCSR, 0);
- udelay(10 * 1000);
- t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
- udelay(10 * 1000);
- t1outmeml(card->mbase+AMCC_MCSR, 0);
- udelay(42 * 1000);
-
-}
-
-/* ------------------------------------------------------------- */
-
-static int t1pci_detect(avmcard *card)
-{
- t1outmeml(card->mbase+AMCC_MCSR, 0);
- udelay(10 * 1000);
- t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
- udelay(10 * 1000);
- t1outmeml(card->mbase+AMCC_MCSR, 0);
- udelay(42 * 1000);
-
- t1outmeml(card->mbase+AMCC_RXLEN, 0);
- t1outmeml(card->mbase+AMCC_TXLEN, 0);
- card->csr = 0x0;
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
-
- if (t1inmeml(card->mbase+AMCC_MCSR) != 0x000000E6)
- return 1;
-
- t1outmeml(card->mbase+AMCC_RXPTR, 0xffffffff);
- t1outmeml(card->mbase+AMCC_TXPTR, 0xffffffff);
- if ( t1inmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc
- || t1inmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc)
- return 2;
-
- t1outmeml(card->mbase+AMCC_RXPTR, 0x0);
- t1outmeml(card->mbase+AMCC_TXPTR, 0x0);
- if ( t1inmeml(card->mbase+AMCC_RXPTR) != 0x0
- || t1inmeml(card->mbase+AMCC_TXPTR) != 0x0)
- return 3;
-
- t1outp(card->port, T1_RESETLINK, 0x00);
- t1outp(card->port, 0x07, 0x00);
-
- t1outp(card->port, 0x02, 0x02);
- t1outp(card->port, 0x03, 0x02);
-
- if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02
- || t1inp(card->port, 0x3) != 0x03)
- return 4;
-
- t1outp(card->port, 0x02, 0x00);
- t1outp(card->port, 0x03, 0x00);
-
- if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00
- || t1inp(card->port, 0x3) != 0x01)
- return 5;
-
- /* Transputer test */
-
- if ( WriteReg(card, 0x80001000, 0x11) != 0
- || WriteReg(card, 0x80101000, 0x22) != 0
- || WriteReg(card, 0x80201000, 0x33) != 0
- || WriteReg(card, 0x80301000, 0x44) != 0)
- return 6;
-
- if ( ReadReg(card, 0x80001000) != 0x11
- || ReadReg(card, 0x80101000) != 0x22
- || ReadReg(card, 0x80201000) != 0x33
- || ReadReg(card, 0x80301000) != 0x44)
- return 7;
-
- if ( WriteReg(card, 0x80001000, 0x55) != 0
- || WriteReg(card, 0x80101000, 0x66) != 0
- || WriteReg(card, 0x80201000, 0x77) != 0
- || WriteReg(card, 0x80301000, 0x88) != 0)
- return 8;
-
- if ( ReadReg(card, 0x80001000) != 0x55
- || ReadReg(card, 0x80101000) != 0x66
- || ReadReg(card, 0x80201000) != 0x77
- || ReadReg(card, 0x80301000) != 0x88)
- return 9;
-
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-static void t1pci_dispatch_tx(avmcard *card)
-{
- avmcard_dmainfo *dma = card->dma;
- unsigned long flags;
- struct sk_buff *skb;
- __u8 cmd, subcmd;
- __u16 len;
- __u32 txlen;
- int inint;
- void *p;
-
- save_flags(flags);
- cli();
-
- inint = card->interrupt;
-
- if (card->csr & EN_TX_TC_INT) { /* tx busy */
- restore_flags(flags);
- return;
- }
-
- skb = skb_dequeue(&dma->send_queue);
- if (!skb) {
-#ifdef CONFIG_T1PCI_DEBUG
- printk(KERN_DEBUG "tx(%d): underrun\n", inint);
-#endif
- restore_flags(flags);
- return;
- }
-
- len = CAPIMSG_LEN(skb->data);
-
- if (len) {
- cmd = CAPIMSG_COMMAND(skb->data);
- subcmd = CAPIMSG_SUBCOMMAND(skb->data);
-
- p = dma->sendbuf;
-
- if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
- __u16 dlen = CAPIMSG_DATALEN(skb->data);
- _put_byte(&p, SEND_DATA_B3_REQ);
- _put_slice(&p, skb->data, len);
- _put_slice(&p, skb->data + len, dlen);
- } else {
- _put_byte(&p, SEND_MESSAGE);
- _put_slice(&p, skb->data, len);
- }
- txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
-#ifdef CONFIG_T1PCI_DEBUG
- printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
- inint, txlen);
-#endif
- } else {
- txlen = skb->len-2;
-#ifdef CONFIG_T1PCI_POLLDEBUG
- if (skb->data[2] == SEND_POLLACK)
- printk(KERN_INFO "%s: ack to t1\n", card->name);
-#endif
-#ifdef CONFIG_T1PCI_DEBUG
- printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n",
- inint, skb->data[2], txlen);
-#endif
- memcpy(dma->sendbuf, skb->data+2, skb->len-2);
- }
- txlen = (txlen + 3) & ~3;
-
- t1outmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf));
- t1outmeml(card->mbase+AMCC_TXLEN, txlen);
-
- card->csr |= EN_TX_TC_INT;
-
- if (!inint)
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
-
- restore_flags(flags);
- dev_kfree_skb(skb);
-}
-
-/* ------------------------------------------------------------- */
-
-static void queue_pollack(avmcard *card)
-{
- struct sk_buff *skb;
- void *p;
-
- skb = alloc_skb(3, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_CRIT "%s: no memory, lost poll ack\n",
- card->name);
- return;
- }
- p = skb->data;
- _put_byte(&p, 0);
- _put_byte(&p, 0);
- _put_byte(&p, SEND_POLLACK);
- skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
-
- skb_queue_tail(&card->dma->send_queue, skb);
- t1pci_dispatch_tx(card);
-}
-
-/* ------------------------------------------------------------- */
-
-static void t1pci_handle_rx(avmcard *card)
-{
- avmctrl_info *cinfo = &card->ctrlinfo[0];
- avmcard_dmainfo *dma = card->dma;
- struct capi_ctr *ctrl = cinfo->capi_ctrl;
- struct sk_buff *skb;
- void *p = dma->recvbuf+4;
- __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
- __u8 b1cmd = _get_byte(&p);
-
-#ifdef CONFIG_T1PCI_DEBUG
- printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
-#endif
-
- switch (b1cmd) {
- case RECEIVE_DATA_B3_IND:
-
- ApplId = (unsigned) _get_word(&p);
- MsgLen = _get_slice(&p, card->msgbuf);
- DataB3Len = _get_slice(&p, card->databuf);
-
- if (MsgLen < 30) { /* not CAPI 64Bit */
- memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
- MsgLen = 30;
- CAPIMSG_SETLEN(card->msgbuf, 30);
- }
- 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);
- ctrl->handle_capimsg(ctrl, ApplId, skb);
- }
- break;
-
- case RECEIVE_MESSAGE:
-
- ApplId = (unsigned) _get_word(&p);
- MsgLen = _get_slice(&p, 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 = _get_word(&p);
- NCCI = _get_word(&p);
- WindowSize = _get_word(&p);
-
- ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
-
- break;
-
- case RECEIVE_FREE_NCCI:
-
- ApplId = _get_word(&p);
- NCCI = _get_word(&p);
-
- if (NCCI != 0xffffffff)
- ctrl->free_ncci(ctrl, ApplId, NCCI);
- else ctrl->appl_released(ctrl, ApplId);
- break;
-
- case RECEIVE_START:
-#ifdef CONFIG_T1PCI_POLLDEBUG
- printk(KERN_INFO "%s: poll from t1\n", card->name);
-#endif
- if (!suppress_pollack)
- queue_pollack(card);
- ctrl->resume_output(ctrl);
- break;
-
- case RECEIVE_STOP:
- ctrl->suspend_output(ctrl);
- break;
-
- case RECEIVE_INIT:
-
- cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
- b1_parse_version(cinfo);
- printk(KERN_INFO "%s: %s-card (%s) now active\n",
- card->name,
- cinfo->version[VER_CARDTYPE],
- cinfo->version[VER_DRIVER]);
- ctrl->ready(ctrl);
- break;
-
- case RECEIVE_TASK_READY:
- ApplId = (unsigned) _get_word(&p);
- MsgLen = _get_slice(&p, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
- printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
- card->name, ApplId, card->msgbuf);
- break;
-
- case RECEIVE_DEBUGMSG:
- MsgLen = _get_slice(&p, card->msgbuf);
- card->msgbuf[MsgLen--] = 0;
- while ( MsgLen >= 0
- && ( card->msgbuf[MsgLen] == '\n'
- || card->msgbuf[MsgLen] == '\r'))
- card->msgbuf[MsgLen--] = 0;
- printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
- break;
-
- default:
- printk(KERN_ERR "%s: t1pci_interrupt: 0x%x ???\n",
- card->name, b1cmd);
- return;
- }
-}
-
-/* ------------------------------------------------------------- */
-
-static void t1pci_handle_interrupt(avmcard *card)
-{
- __u32 status = t1inmeml(card->mbase+AMCC_INTCSR);
- __u32 newcsr;
-
- if ((status & ANY_S5933_INT) == 0)
- return;
-
- newcsr = card->csr | (status & ALL_INT);
- if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
- if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
- t1outmeml(card->mbase+AMCC_INTCSR, newcsr);
-
- if ((status & RX_TC_INT) != 0) {
- __u8 *recvbuf = card->dma->recvbuf;
- __u32 rxlen;
- if (card->dma->recvlen == 0) {
- card->dma->recvlen = *((__u32 *)recvbuf);
- rxlen = (card->dma->recvlen + 3) & ~3;
- t1outmeml(card->mbase+AMCC_RXPTR,
- virt_to_phys(recvbuf+4));
- t1outmeml(card->mbase+AMCC_RXLEN, rxlen);
- } else {
- t1pci_handle_rx(card);
- card->dma->recvlen = 0;
- t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf));
- t1outmeml(card->mbase+AMCC_RXLEN, 4);
- }
- }
-
- if ((status & TX_TC_INT) != 0) {
- card->csr &= ~EN_TX_TC_INT;
- t1pci_dispatch_tx(card);
- } else if (card->csr & EN_TX_TC_INT) {
- if (t1inmeml(card->mbase+AMCC_TXLEN) == 0) {
- card->csr &= ~EN_TX_TC_INT;
- t1pci_dispatch_tx(card);
- }
- }
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
-}
-
-static void t1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
-{
- avmcard *card;
-
- card = (avmcard *) devptr;
-
- if (!card) {
- printk(KERN_WARNING "t1pci: interrupt: wrong device\n");
- return;
- }
- if (card->interrupt) {
- printk(KERN_ERR "%s: reentering interrupt hander\n", card->name);
- return;
- }
-
- card->interrupt = 1;
-
- t1pci_handle_interrupt(card);
-
- card->interrupt = 0;
-}
-
-/* ------------------------------------------------------------- */
-
-static int t1pci_loaded(avmcard *card)
-{
- unsigned long stop;
- unsigned char ans;
- unsigned long tout = 2;
- unsigned int base = card->port;
-
- for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
- if (b1_tx_empty(base))
- break;
- }
- if (!b1_tx_empty(base)) {
- printk(KERN_ERR "%s: t1pci_loaded: tx err, corrupted t4 file ?\n",
- card->name);
- return 0;
- }
- b1_put_byte(base, SEND_POLLACK);
- for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
- if (b1_rx_full(base)) {
- if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
- return 1;
- }
- printk(KERN_ERR "%s: t1pci_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
- return 0;
- }
- }
- printk(KERN_ERR "%s: t1pci_loaded: firmware not running\n", card->name);
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-static void t1pci_send_init(avmcard *card)
-{
- struct sk_buff *skb;
- void *p;
-
- skb = alloc_skb(15, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_CRIT "%s: no memory, lost register appl.\n",
- card->name);
- return;
- }
- p = skb->data;
- _put_byte(&p, 0);
- _put_byte(&p, 0);
- _put_byte(&p, SEND_INIT);
- _put_word(&p, AVM_NAPPS);
- _put_word(&p, AVM_NCCI_PER_CHANNEL*30);
- _put_word(&p, card->cardnr - 1);
- skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
-
- skb_queue_tail(&card->dma->send_queue, skb);
- t1pci_dispatch_tx(card);
-}
-
-static int t1pci_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- unsigned long flags;
- int retval;
-
- t1pci_reset(card);
-
- if ((retval = b1_load_t4file(card, &data->firmware))) {
- t1pci_reset(card);
- 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(card, &data->configuration))) {
- t1pci_reset(card);
- printk(KERN_ERR "%s: failed to load config!!\n",
- card->name);
- return retval;
- }
- }
-
- if (!t1pci_loaded(card)) {
- t1pci_reset(card);
- printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
- return -EIO;
- }
-
- save_flags(flags);
- cli();
-
- card->csr = AVM_FLAG;
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
- t1outmeml(card->mbase+AMCC_MCSR,
- EN_A2P_TRANSFERS|EN_P2A_TRANSFERS
- |A2P_HI_PRIORITY|P2A_HI_PRIORITY
- |RESET_A2P_FLAGS|RESET_P2A_FLAGS);
- t1outp(card->port, 0x07, 0x30);
- t1outp(card->port, 0x10, 0xF0);
-
- card->dma->recvlen = 0;
- t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf));
- t1outmeml(card->mbase+AMCC_RXLEN, 4);
- card->csr |= EN_RX_TC_INT;
- t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
- restore_flags(flags);
-
- t1pci_send_init(card);
-
- return 0;
-}
-
-void t1pci_reset_ctr(struct capi_ctr *ctrl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
-
- t1pci_reset(card);
-
- memset(cinfo->version, 0, sizeof(cinfo->version));
- ctrl->reseted(ctrl);
-}
-
static void t1pci_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
- t1pci_reset(card);
+ b1dma_reset(card);
di->detach_ctr(ctrl);
free_irq(card->irq, card);
@@ -776,210 +93,20 @@ static void t1pci_remove_ctr(struct capi_ctr *ctrl)
/* ------------------------------------------------------------- */
-
-void t1pci_register_appl(struct capi_ctr *ctrl,
- __u16 appl,
- capi_register_params *rp)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- struct sk_buff *skb;
- int want = rp->level3cnt;
- int nconn;
- void *p;
-
- if (want > 0) nconn = want;
- else nconn = ctrl->profile.nbchannel * -want;
- if (nconn == 0) nconn = ctrl->profile.nbchannel;
-
- skb = alloc_skb(23, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_CRIT "%s: no memory, lost register appl.\n",
- card->name);
- return;
- }
- p = skb->data;
- _put_byte(&p, 0);
- _put_byte(&p, 0);
- _put_byte(&p, SEND_REGISTER);
- _put_word(&p, appl);
- _put_word(&p, 1024 * (nconn+1));
- _put_word(&p, nconn);
- _put_word(&p, rp->datablkcnt);
- _put_word(&p, rp->datablklen);
- skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
-
- skb_queue_tail(&card->dma->send_queue, skb);
- t1pci_dispatch_tx(card);
-
- ctrl->appl_registered(ctrl, appl);
-}
-
-/* ------------------------------------------------------------- */
-
-void t1pci_release_appl(struct capi_ctr *ctrl, __u16 appl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- struct sk_buff *skb;
- void *p;
-
- skb = alloc_skb(7, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_CRIT "%s: no memory, lost release appl.\n",
- card->name);
- return;
- }
- p = skb->data;
- _put_byte(&p, 0);
- _put_byte(&p, 0);
- _put_byte(&p, SEND_RELEASE);
- _put_word(&p, appl);
-
- skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
- skb_queue_tail(&card->dma->send_queue, skb);
- t1pci_dispatch_tx(card);
-}
-
-/* ------------------------------------------------------------- */
-
-
-static void t1pci_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- skb_queue_tail(&card->dma->send_queue, skb);
- t1pci_dispatch_tx(card);
-}
-
-/* ------------------------------------------------------------- */
-
-static char *t1pci_procinfo(struct capi_ctr *ctrl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-
- if (!cinfo)
- return "";
- sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
- cinfo->cardname[0] ? cinfo->cardname : "-",
- cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
- cinfo->card ? cinfo->card->port : 0x0,
- cinfo->card ? cinfo->card->irq : 0,
- cinfo->card ? cinfo->card->membase : 0
- );
- return cinfo->infobuf;
-}
-
-static int t1pci_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctrl)
-{
- avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
- avmcard *card = cinfo->card;
- unsigned long flags;
- __u8 flag;
- int len = 0;
- char *s;
- __u32 txaddr, txlen, rxaddr, rxlen, csr;
-
- 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);
- len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
- 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 ((s = cinfo->version[VER_DRIVER]) != 0)
- len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
- if ((s = cinfo->version[VER_CARDTYPE]) != 0)
- len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
- if ((s = cinfo->version[VER_SERIAL]) != 0)
- len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
-
- 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", cinfo->cardname);
-
- save_flags(flags);
- cli();
-
- txaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x2c));
- txaddr -= (__u32)card->dma->sendbuf;
- txlen = t1inmeml(card->mbase+0x30);
-
- rxaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x24));
- rxaddr -= (__u32)card->dma->recvbuf;
- rxlen = t1inmeml(card->mbase+0x28);
-
- csr = t1inmeml(card->mbase+AMCC_INTCSR);
-
- restore_flags(flags);
-
- len += sprintf(page+len, "%-16s 0x%lx\n",
- "csr (cached)", (unsigned long)card->csr);
- len += sprintf(page+len, "%-16s 0x%lx\n",
- "csr", (unsigned long)csr);
- len += sprintf(page+len, "%-16s %lu\n",
- "txoff", (unsigned long)txaddr);
- len += sprintf(page+len, "%-16s %lu\n",
- "txlen", (unsigned long)txlen);
- len += sprintf(page+len, "%-16s %lu\n",
- "rxoff", (unsigned long)rxaddr);
- len += sprintf(page+len, "%-16s %lu\n",
- "rxlen", (unsigned long)rxlen);
-
- if (off+count >= len)
- *eof = 1;
- if (len < off)
- return 0;
- *start = page + off;
- return ((count < len-off) ? count : len-off);
-}
-
-/* ------------------------------------------------------------- */
-
static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
{
- unsigned long page_offset, base;
+ unsigned long base, page_offset;
avmcard *card;
avmctrl_info *cinfo;
int retval;
+ MOD_INC_USE_COUNT;
+
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
@@ -987,6 +114,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
if (!card->dma) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card->dma, 0, sizeof(avmcard_dmainfo));
@@ -995,6 +123,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card->dma);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
@@ -1013,14 +142,26 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
- base = card->membase & PAGE_MASK;
+ base = card->membase & PAGE_MASK;
page_offset = card->membase - base;
card->mbase = ioremap_nocache(base, page_offset + 64);
+ if (card->mbase) {
+ card->mbase += page_offset;
+ } else {
+ printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
+ driver->name, card->membase);
+ kfree(card->ctrlinfo);
+ kfree(card->dma);
+ kfree(card);
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
- t1pci_reset(card);
+ b1dma_reset(card);
if ((retval = t1pci_detect(card)) != 0) {
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
@@ -1029,13 +170,14 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
- t1pci_reset(card);
+ b1dma_reset(card);
request_region(p->port, AVMB1_PORTLEN, card->name);
- retval = request_irq(card->irq, t1pci_interrupt, SA_SHIRQ, card->name, card);
+ retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
driver->name, card->irq);
@@ -1044,6 +186,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
@@ -1056,31 +199,52 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -EBUSY;
}
card->cardnr = cinfo->capi_ctrl->cnr;
skb_queue_head_init(&card->dma->send_queue);
- MOD_INC_USE_COUNT;
+ printk(KERN_INFO
+ "%s: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
+ driver->name, card->port, card->irq, card->membase);
return 0;
}
/* ------------------------------------------------------------- */
+static char *t1pci_procinfo(struct capi_ctr *ctrl)
+{
+ avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+ if (!cinfo)
+ return "";
+ sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
+ cinfo->cardname[0] ? cinfo->cardname : "-",
+ cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+ cinfo->card ? cinfo->card->port : 0x0,
+ cinfo->card ? cinfo->card->irq : 0,
+ cinfo->card ? cinfo->card->membase : 0
+ );
+ return cinfo->infobuf;
+}
+
+/* ------------------------------------------------------------- */
+
static struct capi_driver t1pci_driver = {
"t1pci",
"0.0",
- t1pci_load_firmware,
- t1pci_reset_ctr,
+ b1dma_load_firmware,
+ b1dma_reset_ctr,
t1pci_remove_ctr,
- t1pci_register_appl,
- t1pci_release_appl,
- t1pci_send_message,
+ b1dma_register_appl,
+ b1dma_release_appl,
+ b1dma_send_message,
t1pci_procinfo,
- t1pci_read_proc,
+ b1dmactl_read_proc,
0, /* use standard driver_read_proc */
0, /* no add_card function */
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 38b2944f7..110b5a172 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -1,10 +1,10 @@
-/*
- * $Id: divert_procfs.c,v 1.5 1999/09/14 20:31:01 werner Exp $
+/*
+ * $Id: divert_procfs.c,v 1.6 2000/02/14 19:23:03 werner 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)
@@ -17,9 +17,13 @@
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: divert_procfs.c,v $
+ * Revision 1.6 2000/02/14 19:23:03 werner
+ *
+ * Changed handling of proc filesystem tables to a more portable version
+ *
* Revision 1.5 1999/09/14 20:31:01 werner
*
* Removed obsoleted functions for proc fs and synced with new ones.
@@ -44,9 +48,9 @@
#include <linux/version.h>
#include <linux/poll.h>
#ifdef CONFIG_PROC_FS
- #include <linux/proc_fs.h>
+#include <linux/proc_fs.h>
#else
- #include <linux/fs.h>
+#include <linux/fs.h>
#endif
#include <linux/isdnif.h>
#include "isdn_divert.h"
@@ -54,220 +58,239 @@
/*********************************/
/* 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 */
+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 */
static wait_queue_head_t rd_queue;
/*********************************/
/* 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 */
+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 */
/**********************************/
-static ssize_t isdn_divert_read(struct file *file, char *buf, size_t count, loff_t *off)
-{ 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 */
+static ssize_t
+isdn_divert_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+ 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 */
/**********************************/
-static ssize_t isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t *off)
+static ssize_t
+isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
- return(-ENODEV);
-} /* isdn_divert_write */
+ return (-ENODEV);
+} /* isdn_divert_write */
/***************************************/
/* select routines for various kernels */
/***************************************/
-static unsigned int isdn_divert_poll(struct file *file, poll_table * wait)
-{ unsigned int mask = 0;
+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 */
+ poll_wait(file, &(rd_queue), wait);
+ /* mask = POLLOUT | POLLWRNORM; */
+ if (*((struct divert_info **) file->private_data)) {
+ mask |= POLLIN | POLLRDNORM;
+ }
+ return mask;
+} /* isdn_divert_poll */
/****************/
/* 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 */
+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 */
/*******************/
-static int isdn_divert_close(struct inode *ino, struct file *filep)
-{ 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;
- return(0);
-} /* isdn_divert_close */
+static int
+isdn_divert_close(struct inode *ino, struct file *filep)
+{
+ 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;
+ return (0);
+} /* 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 */
+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
@@ -279,63 +302,66 @@ isdn_divert_lseek(struct file *file, loff_t offset, int orig)
static struct file_operations isdn_fops =
{
- llseek: isdn_divert_lseek,
- read: isdn_divert_read,
- write: isdn_divert_write,
- poll: isdn_divert_poll,
- ioctl: isdn_divert_ioctl,
- open: isdn_divert_open,
- release: isdn_divert_close,
-};
-
-struct inode_operations divert_file_inode_operations = {
- &isdn_fops, /* default proc file-ops */
+ 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 */
};
+struct inode_operations divert_file_inode_operations;
/****************************/
/* isdn subdir in /proc/net */
/****************************/
static struct proc_dir_entry *isdn_proc_entry = NULL;
static struct proc_dir_entry *isdn_divert_entry = NULL;
-#endif CONFIG_PROC_FS
+#endif /* CONFIG_PROC_FS */
/***************************************************************************/
/* divert_dev_init must be called before the proc filesystem may be used */
/***************************************************************************/
-int divert_dev_init(void)
-{ int i;
+int
+divert_dev_init(void)
+{
init_waitqueue_head(&rd_queue);
#ifdef CONFIG_PROC_FS
- isdn_proc_entry = proc_mkdir("isdn", proc_net);
- if (!isdn_proc_entry)
- return(-1);
- isdn_divert_entry = create_proc_entry("divert",0,isdn_proc_entry);
- if (!isdn_divert_entry)
- {
- remove_proc_entry("isdn",proc_net);
- return(-1);
- }
- isdn_divert_entry->ops = &divert_file_inode_operations;
-#endif CONFIG_PROC_FS
-
- return(0);
-} /* divert_dev_init */
+ isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
+ if (!isdn_proc_entry)
+ return (-1);
+ isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry);
+ if (!isdn_divert_entry) {
+ remove_proc_entry("isdn", proc_net);
+ return (-1);
+ }
+ memset(&divert_file_inode_operations, 0, sizeof(struct inode_operations));
+ divert_file_inode_operations.default_file_ops = &isdn_fops;
+ isdn_divert_entry->ops = &divert_file_inode_operations;
+#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;
+int
+divert_dev_deinit(void)
+{
#ifdef CONFIG_PROC_FS
- remove_proc_entry("divert",isdn_proc_entry);
- remove_proc_entry("isdn",proc_net);
-#endif CONFIG_PROC_FS
-
- return(0);
-} /* divert_dev_deinit */
+ remove_proc_entry("divert", isdn_proc_entry);
+ remove_proc_entry("isdn", proc_net);
+#endif /* CONFIG_PROC_FS */
+ return (0);
+} /* divert_dev_deinit */
diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h
index 88af10416..5ad164518 100644
--- a/drivers/isdn/eicon/eicon.h
+++ b/drivers/isdn/eicon/eicon.h
@@ -1,10 +1,10 @@
-/* $Id: eicon.h,v 1.17 1999/10/26 21:15:33 armin Exp $
+/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * ISDN low-level module for Eicon active ISDN-Cards.
*
* Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.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
@@ -21,6 +21,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon.h,v $
+ * Revision 1.19 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.18 1999/11/25 11:43:27 armin
+ * Fixed statectrl and connect message.
+ * X.75 fix and HDLC/transparent with autoconnect.
+ * Minor cleanup.
+ *
* Revision 1.17 1999/10/26 21:15:33 armin
* using define for checking phone number len to avoid buffer overflow.
*
@@ -258,7 +267,7 @@ typedef struct {
/* Macro for delay via schedule() */
#define SLEEP(j) { \
- set_current_state(TASK_INTERRUPTIBLE); \
+ set_current_state(TASK_UNINTERRUPTIBLE); \
schedule_timeout(j); \
}
@@ -277,6 +286,8 @@ typedef struct {
#define XLOG_ERR_UNKNOWN (18)
#define XLOG_OK (0)
+#define TRACE_OK (1)
+
typedef struct {
__u8 Id __attribute__ ((packed));
__u8 uX __attribute__ ((packed));
@@ -494,12 +505,13 @@ typedef struct {
typedef struct {
int No; /* Channel Number */
unsigned short fsm_state; /* Current D-Channel state */
+ unsigned short statectrl; /* State controling bits */
unsigned short eazmask; /* EAZ-Mask for this Channel */
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;
+ struct sk_buff *tskb1; /* temp skb 1 */
+ struct sk_buff *tskb2; /* temp skb 2 */
unsigned char l2prot; /* Layer 2 protocol */
unsigned char l3prot; /* Layer 3 protocol */
#ifdef CONFIG_ISDN_TTY_FAX
@@ -600,21 +612,16 @@ typedef struct eicon_card {
struct eicon_card *next; /* Pointer to next device struct */
int myid; /* Driver-Nr. assigned by linklevel */
unsigned long flags; /* Statusflags */
- unsigned long ilock; /* Semaphores for IRQ-Routines */
struct sk_buff_head rcvq; /* Receive-Message queue */
struct sk_buff_head sndq; /* Send-Message queue */
struct sk_buff_head rackq; /* Req-Ack-Message queue */
struct sk_buff_head sackq; /* Data-Ack-Message queue */
struct sk_buff_head statq; /* Status-Message queue */
int statq_entries;
- u_char *ack_msg; /* Ptr to User Data in User skb */
- __u16 need_b3ack; /* Flag: Need ACK for current skb */
- struct sk_buff *sbuf; /* skb which is currently sent */
struct tq_struct snd_tq; /* Task struct for xmit bh */
struct tq_struct rcv_tq; /* Task struct for rcv bh */
struct tq_struct ack_tq; /* Task struct for ack bh */
msn_entry *msn_list;
- unsigned short msgnum; /* Message number for sending */
eicon_chan* IdTable[256]; /* Table to find entity */
__u16 ref_in;
__u16 ref_out;
@@ -696,6 +703,7 @@ extern int eicon_info(char *, int , void *);
extern ulong DebugVar;
extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
+extern void eicon_putstatus(eicon_card * card, char * buf);
#endif /* __KERNEL__ */
diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h
index 9ffbd9bdb..420d73f6e 100644
--- a/drivers/isdn/eicon/eicon_dsp.h
+++ b/drivers/isdn/eicon/eicon_dsp.h
@@ -1,10 +1,10 @@
-/* $Id: eicon_dsp.h,v 1.4 1999/07/25 15:12:02 armin Exp $
+/* $Id: eicon_dsp.h,v 1.5 2000/01/23 21:21:23 armin Exp $
*
- * ISDN lowlevel-module for Eicon.Diehl active cards.
+ * ISDN lowlevel-module for Eicon active cards.
* DSP definitions
*
- * Copyright 1999 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1999,2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.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
@@ -21,6 +21,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_dsp.h,v $
+ * Revision 1.5 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
* Revision 1.4 1999/07/25 15:12:02 armin
* fix of some debug logs.
* enabled ISA-cards option.
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c
index d8634bdbe..e53469070 100644
--- a/drivers/isdn/eicon/eicon_idi.c
+++ b/drivers/isdn/eicon/eicon_idi.c
@@ -1,10 +1,10 @@
-/* $Id: eicon_idi.c,v 1.24 1999/10/26 21:15:33 armin Exp $
+/* $Id: eicon_idi.c,v 1.29 2000/01/23 21:21:23 armin Exp $
*
- * ISDN lowlevel-module for Eicon.Diehl active cards.
+ * ISDN lowlevel-module for Eicon active cards.
* IDI interface
*
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH
* for sponsoring and testing fax
@@ -26,6 +26,25 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.c,v $
+ * Revision 1.29 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.28 2000/01/20 19:55:34 keil
+ * Add FAX Class 1 support
+ *
+ * Revision 1.27 1999/11/29 13:12:03 armin
+ * Autoconnect on L2_TRANS doesn't work with link_level correctly,
+ * changed back to former mode.
+ *
+ * Revision 1.26 1999/11/25 11:43:27 armin
+ * Fixed statectrl and connect message.
+ * X.75 fix and HDLC/transparent with autoconnect.
+ * Minor cleanup.
+ *
+ * Revision 1.25 1999/11/18 20:30:55 armin
+ * removed old workaround for ISA cards.
+ *
* Revision 1.24 1999/10/26 21:15:33 armin
* using define for checking phone number len to avoid buffer overflow.
*
@@ -130,7 +149,7 @@
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.24 $";
+char *eicon_idi_revision = "$Revision: 1.29 $";
eicon_manifbuf *manbuf;
@@ -187,16 +206,13 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
reqbuf->XBuffer.P[l++] = LLC;
reqbuf->XBuffer.P[l++] = 2;
switch(chan->l2prot) {
- case ISDN_PROTO_L2_HDLC:
- reqbuf->XBuffer.P[l++] = 2;
+ case ISDN_PROTO_L2_TRANS:
+ reqbuf->XBuffer.P[l++] = 2; /* transparent */
break;
case ISDN_PROTO_L2_X75I:
case ISDN_PROTO_L2_X75UI:
case ISDN_PROTO_L2_X75BUI:
- reqbuf->XBuffer.P[l++] = 5;
- break;
- case ISDN_PROTO_L2_TRANS:
- reqbuf->XBuffer.P[l++] = 2;
+ reqbuf->XBuffer.P[l++] = 5; /* X.75 */
break;
case ISDN_PROTO_L2_MODEM:
if (chan->fsm_state == EICON_STATE_IWAIT)
@@ -204,17 +220,18 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
else
reqbuf->XBuffer.P[l++] = 10; /* V.42 */
break;
+ case ISDN_PROTO_L2_HDLC:
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;
+ reqbuf->XBuffer.P[l++] = 2; /* transparent */
break;
default:
reqbuf->XBuffer.P[l++] = 1;
}
switch(chan->l3prot) {
- case ISDN_PROTO_L3_FAX:
+ case ISDN_PROTO_L3_FCLASS2:
#ifdef CONFIG_ISDN_TTY_FAX
reqbuf->XBuffer.P[l++] = 6;
reqbuf->XBuffer.P[l++] = NLC;
@@ -404,8 +421,10 @@ eicon_idi_listen_req(eicon_card *card, eicon_chan *chan)
idi_do_req(card, chan, ASSIGN, 0);
}
if (chan->fsm_state == EICON_STATE_NULL) {
- idi_do_req(card, chan, INDICATE_REQ, 0);
- chan->fsm_state = EICON_STATE_LISTEN;
+ if (!(chan->statectrl & HAVE_CONN_REQ)) {
+ idi_do_req(card, chan, INDICATE_REQ, 0);
+ chan->fsm_state = EICON_STATE_LISTEN;
+ }
}
return(0);
}
@@ -462,6 +481,7 @@ idi_hangup(eicon_card *card, eicon_chan *chan)
}
if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
if (chan->fsm_state != EICON_STATE_NULL) {
+ chan->statectrl |= WAITING_FOR_HANGUP;
idi_do_req(card, chan, HANGUP, 0);
chan->fsm_state = EICON_STATE_NULL;
}
@@ -479,7 +499,6 @@ idi_connect_res(eicon_card *card, eicon_chan *chan)
return 1;
chan->fsm_state = EICON_STATE_IWAIT;
- idi_do_req(card, chan, CALL_RES, 0);
/* check if old NetID has been removed */
if (chan->e.B2Id) {
@@ -489,6 +508,7 @@ idi_connect_res(eicon_card *card, eicon_chan *chan)
}
idi_do_req(card, chan, ASSIGN, 1);
+ idi_do_req(card, chan, CALL_RES, 0);
return(0);
}
@@ -656,9 +676,18 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
reqbuf->XBuffer.length = l;
reqbuf->Reference = 0; /* Sig Entity */
- skb_queue_tail(&chan->e.X, skb);
- skb_queue_tail(&card->sndq, skb2);
- eicon_schedule_tx(card);
+ if (chan->statectrl & WAITING_FOR_HANGUP) {
+ /* If the line did not disconnect yet,
+ we have to delay this command */
+ eicon_log(card, 32, "idi_req: Ch%d: delaying conn_req\n", chan->No);
+ chan->statectrl |= HAVE_CONN_REQ;
+ chan->tskb1 = skb;
+ chan->tskb2 = skb2;
+ } else {
+ skb_queue_tail(&chan->e.X, skb);
+ skb_queue_tail(&card->sndq, skb2);
+ eicon_schedule_tx(card);
+ }
eicon_log(card, 8, "idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
return(0);
@@ -1433,6 +1462,7 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BCONN;
cmd.arg = chan->No;
+ strcpy(cmd.parm.num, "");
ccard->interface.statcallb(&cmd);
cmd.driver = ccard->myid;
@@ -1489,6 +1519,8 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
break;
case 2: /* session end */
default:
+ /* send_edata produces error on some */
+ /* fax-machines here, so we don't */
/* idi_send_edata(ccard, chan); */
break;
}
@@ -1505,6 +1537,7 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BCONN;
cmd.arg = chan->No;
+ strcpy(cmd.parm.num, "");
ccard->interface.statcallb(&cmd);
cmd.driver = ccard->myid;
@@ -2277,6 +2310,51 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int
}
void
+eicon_parse_trace(eicon_card *ccard, unsigned char *buffer, int len)
+{
+ int i,j,n;
+ int buflen = len * 3 + 30;
+ char *p;
+ struct trace_s {
+ unsigned long time;
+ unsigned short size;
+ unsigned short code;
+ unsigned char data[1];
+ } *q;
+
+ if (!(p = kmalloc(buflen, GFP_KERNEL))) {
+ eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n");
+ return;
+ }
+ memset(p, 0, buflen);
+ q = (struct trace_s *)buffer;
+
+ if (DebugVar & 512) {
+ if ((q->code == 3) || (q->code == 4)) {
+ n = (short) *(q->data);
+ if (n) {
+ j = sprintf(p, "DTRC:");
+ for (i = 0; i < n; i++) {
+ j += sprintf(p + j, "%02x ", q->data[i+2]);
+ }
+ j += sprintf(p + j, "\n");
+ }
+ }
+ } else {
+ j = sprintf(p, "XLOG: %lx %04x %04x ",
+ q->time, q->size, q->code);
+
+ for (i = 0; i < q->size; i++) {
+ j += sprintf(p + j, "%02x ", q->data[i]);
+ }
+ j += sprintf(p + j, "\n");
+ }
+ if (strlen(p))
+ eicon_putstatus(ccard, p);
+ kfree(p);
+}
+
+void
idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
{
int tmp;
@@ -2307,7 +2385,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
else
dlev = 128;
- eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
+ eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%x Id=%x Ch=%x MInd=%x MLen=%x Len=%x\n", chan->No,
ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
free_buff = 1;
@@ -2347,12 +2425,25 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
} else {
if (chan->e.B2Id)
idi_do_req(ccard, chan, REMOVE, 1);
- chan->fsm_state = EICON_STATE_NULL;
- cmd.driver = ccard->myid;
- cmd.arg = chan->No;
- cmd.command = ISDN_STAT_DHUP;
- ccard->interface.statcallb(&cmd);
- eicon_idi_listen_req(ccard, chan);
+ chan->statectrl &= ~WAITING_FOR_HANGUP;
+ if (chan->statectrl & HAVE_CONN_REQ) {
+ eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No);
+ chan->statectrl &= ~HAVE_CONN_REQ;
+ if ((chan->tskb1) && (chan->tskb2)) {
+ skb_queue_tail(&chan->e.X, chan->tskb1);
+ skb_queue_tail(&ccard->sndq, chan->tskb2);
+ eicon_schedule_tx(ccard);
+ }
+ chan->tskb1 = NULL;
+ chan->tskb2 = NULL;
+ } else {
+ chan->fsm_state = EICON_STATE_NULL;
+ cmd.driver = ccard->myid;
+ cmd.arg = chan->No;
+ cmd.command = ISDN_STAT_DHUP;
+ ccard->interface.statcallb(&cmd);
+ eicon_idi_listen_req(ccard, chan);
+ }
}
break;
case INDICATE_IND:
@@ -2450,8 +2541,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
case ISDN_PROTO_L2_MODEM:
/* do nothing, wait for connect */
break;
- default:
+ case ISDN_PROTO_L2_TRANS:
idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+ break;
+ default:
+ /* On most incoming calls we use automatic connect */
+ /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */
}
} else
idi_hangup(ccard, chan);
@@ -2495,8 +2590,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
if (chan->No == ccard->nchannels) {
/* Management Indication */
- idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
- chan->fsm_state = 1;
+ if (ind->Ind == 0x04) { /* Trace_Ind */
+ eicon_parse_trace(ccard, ind->RBuffer.P, ind->RBuffer.length);
+ } else {
+ idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
+ chan->fsm_state = 1;
+ }
}
else
switch(ind->Ind) {
@@ -2530,6 +2629,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BCONN;
cmd.arg = chan->No;
+ strcpy(cmd.parm.num, "64000");
ccard->interface.statcallb(&cmd);
break;
case IDI_N_CONNECT:
@@ -2546,6 +2646,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BCONN;
cmd.arg = chan->No;
+ strcpy(cmd.parm.num, "64000");
ccard->interface.statcallb(&cmd);
break;
case IDI_N_DISC:
@@ -2576,6 +2677,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.arg = chan->No;
ccard->interface.statcallb(&cmd);
chan->fsm_state = EICON_STATE_NULL;
+ chan->statectrl |= WAITING_FOR_HANGUP;
}
#ifdef CONFIG_ISDN_TTY_FAX
chan->fax = 0;
@@ -2631,7 +2733,8 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
isdn_ctrl cmd;
if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
- /* I dont know why this happens, just ignoring this RC */
+ /* I dont know why this happens, should not ! */
+ /* just ignoring this RC */
eicon_log(ccard, 16, "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;
@@ -2640,16 +2743,16 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
/* Management Interface */
if (chan->No == ccard->nchannels) {
/* Managementinterface: changing state */
- if (chan->e.Req == 0x04)
+ if (chan->e.Req != 0x02)
chan->fsm_state = 1;
}
/* Remove an Id */
if (chan->e.Req == REMOVE) {
if (ack->Reference != chan->e.ref) {
+ /* This should not happen anymore */
eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
ack->Reference, chan->e.ref);
- return 0;
}
save_flags(flags);
cli();
@@ -2807,11 +2910,14 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
dCh, ack->Rc, ack->RcId, ack->RcCh);
break;
default:
- eicon_log(ccard, 1, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
- dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
+ if (dCh != ccard->nchannels)
+ eicon_log(ccard, 1, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
+ dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
}
if (dCh == ccard->nchannels) { /* Management */
chan->fsm_state = 2;
+ eicon_log(ccard, 8, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
+ dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
} else if (dCh >= 0) {
/* any other channel */
/* card reports error: we hangup */
@@ -3011,38 +3117,36 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
chan = &(card->bch[card->nchannels]);
- if (chan->e.D3Id)
- return -EBUSY;
- chan->e.D3Id = 1;
- while((skb2 = skb_dequeue(&chan->e.X)))
- dev_kfree_skb(skb2);
- chan->e.busy = 0;
+ if (!(chan->e.D3Id)) {
+ chan->e.D3Id = 1;
+ while((skb2 = skb_dequeue(&chan->e.X)))
+ dev_kfree_skb(skb2);
+ chan->e.busy = 0;
- if ((ret = eicon_idi_manage_assign(card))) {
- chan->e.D3Id = 0;
- return(ret);
- }
+ if ((ret = eicon_idi_manage_assign(card))) {
+ chan->e.D3Id = 0;
+ return(ret);
+ }
- timeout = jiffies + 50;
- while (timeout > jiffies) {
- if (chan->e.B2Id) break;
- SLEEP(10);
- }
- if (!chan->e.B2Id) {
- chan->e.D3Id = 0;
- return -EIO;
+ timeout = jiffies + 50;
+ while (timeout > jiffies) {
+ if (chan->e.B2Id) break;
+ SLEEP(10);
+ }
+ if (!chan->e.B2Id) {
+ chan->e.D3Id = 0;
+ return -EIO;
+ }
}
chan->fsm_state = 0;
if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) {
eicon_log(card, 1, "idi_err: alloc_manifbuf failed\n");
- chan->e.D3Id = 0;
return -ENOMEM;
}
if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) {
kfree(manbuf);
- chan->e.D3Id = 0;
return -EFAULT;
}
@@ -3056,7 +3160,6 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
if (skb2)
dev_kfree_skb(skb2);
kfree(manbuf);
- chan->e.D3Id = 0;
return -ENOMEM;
}
@@ -3093,25 +3196,14 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
SLEEP(10);
}
if ((!chan->fsm_state) || (chan->fsm_state == 2)) {
- eicon_idi_manage_remove(card);
kfree(manbuf);
- chan->e.D3Id = 0;
return -EIO;
}
-
- 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;
}
kfree(manbuf);
- chan->e.D3Id = 0;
return(0);
}
diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h
index e09c1954d..2fe6167a4 100644
--- a/drivers/isdn/eicon/eicon_idi.h
+++ b/drivers/isdn/eicon/eicon_idi.h
@@ -1,10 +1,10 @@
-/* $Id: eicon_idi.h,v 1.7 1999/08/22 20:26:46 calle Exp $
+/* $Id: eicon_idi.h,v 1.9 2000/01/23 21:21:23 armin Exp $
*
- * ISDN lowlevel-module for the Eicon.Diehl active cards.
+ * ISDN lowlevel-module for the Eicon active cards.
* IDI-Interface
*
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.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
@@ -21,6 +21,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.h,v $
+ * Revision 1.9 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.8 1999/11/25 11:43:27 armin
+ * Fixed statectrl and connect message.
+ * X.75 fix and HDLC/transparent with autoconnect.
+ * Minor cleanup.
+ *
* Revision 1.7 1999/08/22 20:26:46 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
@@ -170,6 +179,10 @@
/*------------------------------------------------------------------*/
+/* defines for statectrl */
+#define WAITING_FOR_HANGUP 0x01
+#define HAVE_CONN_REQ 0x02
+
typedef struct {
char cpn[32];
char oad[32];
diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c
index 779f241e0..4f4180ed6 100644
--- a/drivers/isdn/eicon/eicon_io.c
+++ b/drivers/isdn/eicon/eicon_io.c
@@ -1,12 +1,12 @@
-/* $Id: eicon_io.c,v 1.8 1999/10/08 22:09:34 armin Exp $
+/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * ISDN low-level module for Eicon active ISDN-Cards.
* Code for communicating with hardware.
*
- * Copyright 1999 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1999,2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
- * Thanks to Eicon Technology Diehl GmbH & Co. oHG for
+ * Thanks to Eicon Technology GmbH & Co. oHG for
* documents, informations and hardware.
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_io.c,v $
+ * Revision 1.10 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.9 1999/11/18 20:55:25 armin
+ * Ready_Int fix of ISA cards.
+ *
* Revision 1.8 1999/10/08 22:09:34 armin
* Some fixes of cards interface handling.
* Bugfix of NULL pointer occurence.
@@ -470,7 +477,7 @@ eicon_io_transmit(eicon_card *ccard) {
save_flags(flags);
cli();
if (scom) {
- if (ram_inb(ccard, &com->Req)) {
+ if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) {
if (!ccard->ReadyInt) {
tmp = ram_inb(ccard, &com->ReadyInt) + 1;
ram_outb(ccard, &com->ReadyInt, tmp);
@@ -566,7 +573,8 @@ eicon_io_transmit(eicon_card *ccard) {
chan->e.busy = 1;
eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n",
reqbuf->Req,
- ram_inb(ccard, &ReqOut->ReqId),
+ (scom) ? ram_inb(ccard, &com->ReqId) :
+ ram_inb(ccard, &ReqOut->ReqId),
reqbuf->ReqCh, reqbuf->XBuffer.length,
chan->e.ref);
}
@@ -754,6 +762,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
if (ccard->ReadyInt) {
ccard->ReadyInt--;
ram_outb(ccard, &com->Rc, 0);
+ eicon_schedule_tx(ccard);
}
} else {
skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c
index a89d18b12..86e6c0ef7 100644
--- a/drivers/isdn/eicon/eicon_isa.c
+++ b/drivers/isdn/eicon/eicon_isa.c
@@ -1,11 +1,11 @@
-/* $Id: eicon_isa.c,v 1.9 1999/09/08 20:17:31 armin Exp $
+/* $Id: eicon_isa.c,v 1.13 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for old ISA cards.
*
- * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.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
@@ -22,8 +22,21 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_isa.c,v $
+ * Revision 1.13 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.12 1999/11/27 12:56:19 armin
+ * Forgot some iomem changes for last ioremap compat.
+ *
+ * Revision 1.11 1999/11/25 11:33:09 armin
+ * Microchannel fix from Erik Weber (exrz73@ibm.net).
+ *
+ * Revision 1.10 1999/11/18 21:14:30 armin
+ * New ISA memory mapped IO
+ *
* Revision 1.9 1999/09/08 20:17:31 armin
- * Added microchannel patch from Erik Weber.
+ * Added microchannel patch from Erik Weber (exrz73@ibm.net).
*
* Revision 1.8 1999/09/06 07:29:35 fritz
* Changed my mail-address.
@@ -70,7 +83,7 @@
#define release_shmem release_region
#define request_shmem request_region
-char *eicon_isa_revision = "$Revision: 1.9 $";
+char *eicon_isa_revision = "$Revision: 1.13 $";
#undef EICON_MCA_DEBUG
@@ -87,8 +100,10 @@ static int eicon_isa_valid_irq[] = {
static void
eicon_isa_release_shmem(eicon_isa_card *card) {
- if (card->mvalid)
- release_shmem((unsigned long)card->shmem, card->ramsize);
+ if (card->mvalid) {
+ iounmap(card->shmem);
+ release_mem_region(card->physmem, card->ramsize);
+ }
card->mvalid = 0;
}
@@ -117,7 +132,7 @@ eicon_isa_printpar(eicon_isa_card *card) {
case EICON_CTYPE_S2M:
printk(KERN_INFO "Eicon %s at 0x%lx, irq %d.\n",
eicon_ctype_name[card->type],
- (unsigned long)card->shmem,
+ card->physmem,
card->irq);
}
}
@@ -126,6 +141,7 @@ int
eicon_isa_find_card(int Mem, int Irq, char * Id)
{
int primary = 1;
+ unsigned long amem;
if (!strlen(Id))
return -1;
@@ -138,24 +154,27 @@ eicon_isa_find_card(int Mem, int Irq, char * Id)
Mem, Id);
return -1;
}
- if (check_shmem(Mem, RAMSIZE)) {
+ if (check_mem_region(Mem, RAMSIZE)) {
printk(KERN_WARNING "eicon_isa_boot: memory at 0x%x already in use.\n", Mem);
return -1;
}
- writew(0x55aa, Mem + 0x402);
- if (readw(Mem + 0x402) != 0x55aa) primary = 0;
- writew(0, Mem + 0x402);
- if (readw(Mem + 0x402) != 0) primary = 0;
+ amem = (unsigned long) ioremap(Mem, RAMSIZE);
+ writew(0x55aa, amem + 0x402);
+ if (readw(amem + 0x402) != 0x55aa) primary = 0;
+ writew(0, amem + 0x402);
+ if (readw(amem + 0x402) != 0) primary = 0;
printk(KERN_INFO "Eicon: Driver-ID: %s\n", Id);
if (primary) {
printk(KERN_INFO "Eicon: assuming pri card at 0x%x\n", Mem);
- writeb(0, Mem + 0x3ffe);
+ writeb(0, amem + 0x3ffe);
+ iounmap((unsigned char *)amem);
return EICON_CTYPE_ISAPRI;
} else {
printk(KERN_INFO "Eicon: assuming bri card at 0x%x\n", Mem);
- writeb(0, Mem + 0x400);
+ writeb(0, amem + 0x400);
+ iounmap((unsigned char *)amem);
return EICON_CTYPE_ISABRI;
}
return -1;
@@ -187,57 +206,65 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
return -EFAULT;
}
+ if (card->type == EICON_CTYPE_ISAPRI)
+ card->ramsize = RAMSIZE_P;
+ else
+ card->ramsize = RAMSIZE;
+
+ if (check_mem_region(card->physmem, card->ramsize)) {
+ printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",
+ card->physmem);
+ kfree(code);
+ return -EBUSY;
+ }
+ request_mem_region(card->physmem, card->ramsize, "Eicon ISA ISDN");
+ card->shmem = (eicon_isa_shmem *) ioremap(card->physmem, card->ramsize);
+#ifdef EICON_MCA_DEBUG
+ printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize);
+#endif
+ card->mvalid = 1;
+
switch(card->type) {
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
case EICON_CTYPE_ISABRI:
- card->ramsize = RAMSIZE;
card->intack = (__u8 *)card->shmem + INTACK;
card->startcpu = (__u8 *)card->shmem + STARTCPU;
card->stopcpu = (__u8 *)card->shmem + STOPCPU;
break;
case EICON_CTYPE_S2M:
case EICON_CTYPE_ISAPRI:
- card->ramsize = RAMSIZE_P;
card->intack = (__u8 *)card->shmem + INTACK_P;
card->startcpu = (__u8 *)card->shmem + STARTCPU_P;
card->stopcpu = (__u8 *)card->shmem + STOPCPU_P;
break;
default:
printk(KERN_WARNING "eicon_isa_boot: Invalid card type %d\n", card->type);
+ eicon_isa_release_shmem(card);
+ kfree(code);
return -EINVAL;
}
- /* Register shmem */
- if (check_shmem((unsigned long)card->shmem, card->ramsize)) {
- printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",
- (unsigned long)card->shmem);
- kfree(code);
- return -EBUSY;
- }
- request_shmem((unsigned long)card->shmem, card->ramsize, "Eicon ISA ISDN");
-#ifdef EICON_MCA_DEBUG
- printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize);
-#endif
- card->mvalid = 1;
-
/* clear any pending irq's */
readb(card->intack);
#ifdef CONFIG_MCA
- if (card->type == EICON_CTYPE_SCOM) {
- outb_p(0,card->io+1);
- }
- else {
- printk(KERN_WARNING "eicon_isa_boot: Card type yet not supported.\n");
- return -EINVAL;
- };
+ if (MCA_bus) {
+ if (card->type == EICON_CTYPE_SCOM) {
+ outb_p(0,card->io+1);
+ }
+ else {
+ printk(KERN_WARNING "eicon_isa_boot: Card type not supported yet.\n");
+ eicon_isa_release_shmem(card);
+ return -EINVAL;
+ };
#ifdef EICON_MCA_DEBUG
printk(KERN_INFO "eicon_isa_boot: card->io = %x.\n", card->io);
printk(KERN_INFO "eicon_isa_boot: card->irq = %d.\n", (int)card->irq);
#endif
+ }
#else
/* set reset-line active */
writeb(0, card->stopcpu);
@@ -269,7 +296,9 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
/* Start CPU */
writeb(cbuf.boot_opt, &boot->ctrl);
#ifdef CONFIG_MCA
- outb_p(0, card->io);
+ if (MCA_bus) {
+ outb_p(0, card->io);
+ }
#else
writeb(0, card->startcpu);
#endif /* CONFIG_MCA */
@@ -320,7 +349,7 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
}
printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]);
if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) {
- tmp = eicon_addcard(card->type, (unsigned long)card->shmem, card->irq,
+ tmp = eicon_addcard(card->type, card->physmem, card->irq,
((eicon_card *)card->card)->regname);
printk(KERN_INFO "Eicon: %d adapters added\n", tmp);
}
diff --git a/drivers/isdn/eicon/eicon_isa.h b/drivers/isdn/eicon/eicon_isa.h
index b0d0b0eb9..b53adfcbf 100644
--- a/drivers/isdn/eicon/eicon_isa.h
+++ b/drivers/isdn/eicon/eicon_isa.h
@@ -1,10 +1,10 @@
-/* $Id: eicon_isa.h,v 1.6 1999/11/15 19:37:04 keil Exp $
+/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * ISDN low-level module for Eicon active ISDN-Cards.
*
- * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.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
@@ -21,6 +21,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_isa.h,v $
+ * Revision 1.8 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.7 1999/11/18 21:14:30 armin
+ * New ISA memory mapped IO
+ *
* Revision 1.6 1999/11/15 19:37:04 keil
* need config.h
*
@@ -116,6 +123,7 @@ typedef union {
typedef struct {
int ramsize;
int irq; /* IRQ */
+ unsigned long physmem; /* physical memory address */
#ifdef CONFIG_MCA
int io; /* IO-port for MCA brand */
#endif /* CONFIG_MCA */
diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
index 8797e6aed..688d74de3 100644
--- a/drivers/isdn/eicon/eicon_mod.c
+++ b/drivers/isdn/eicon/eicon_mod.c
@@ -1,12 +1,12 @@
-/* $Id: eicon_mod.c,v 1.19 1999/11/12 13:21:44 armin Exp $
+/* $Id: eicon_mod.c,v 1.24 2000/01/23 21:21:23 armin Exp $
*
- * ISDN lowlevel-module for Eicon.Diehl active cards.
+ * ISDN lowlevel-module for Eicon active cards.
*
- * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
- * Thanks to Eicon Technology Diehl GmbH & Co. oHG for
+ * Thanks to Eicon Technology GmbH & Co. oHG for
* documents, informations and hardware.
*
* Deutsche Telekom AG for S2M support.
@@ -31,6 +31,23 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_mod.c,v $
+ * Revision 1.24 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
+ * Revision 1.23 2000/01/20 19:55:34 keil
+ * Add FAX Class 1 support
+ *
+ * Revision 1.22 1999/11/27 12:56:19 armin
+ * Forgot some iomem changes for last ioremap compat.
+ *
+ * Revision 1.21 1999/11/25 11:35:10 armin
+ * Microchannel fix from Erik Weber (exrz73@ibm.net).
+ * Minor cleanup.
+ *
+ * Revision 1.20 1999/11/18 21:14:30 armin
+ * New ISA memory mapped IO
+ *
* Revision 1.19 1999/11/12 13:21:44 armin
* Bugfix of undefined reference with CONFIG_MCA
*
@@ -46,7 +63,7 @@
* Improved debug and log via readstat()
*
* Revision 1.15 1999/09/08 20:17:31 armin
- * Added microchannel patch from Erik Weber.
+ * Added microchannel patch from Erik Weber (exrz73@ibm.net).
*
* Revision 1.14 1999/09/06 07:29:35 fritz
* Changed my mail-address.
@@ -123,7 +140,7 @@
static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains
start of card-list */
-static char *eicon_revision = "$Revision: 1.19 $";
+static char *eicon_revision = "$Revision: 1.24 $";
extern char *eicon_pci_revision;
extern char *eicon_isa_revision;
@@ -144,7 +161,7 @@ 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_DESCRIPTION( "Driver for Eicon active ISDN cards");
MODULE_AUTHOR( "Armin Schindler");
MODULE_SUPPORTED_DEVICE( "ISDN subsystem");
MODULE_PARM_DESC(id, "ID-String of first card");
@@ -659,7 +676,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
break;
chan->l3prot = (c->arg >> 8);
#ifdef CONFIG_ISDN_TTY_FAX
- if (chan->l3prot == ISDN_PROTO_L3_FAX)
+ if (chan->l3prot == ISDN_PROTO_L3_FCLASS2)
chan->fax = c->parm.fax;
#endif
return 0;
@@ -839,8 +856,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
}
/* jiftime() copied from HiSax */
-inline int
-jiftime(char *s, long mark)
+static inline int jiftime(char *s, long mark)
{
s += 8;
@@ -1000,19 +1016,28 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
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;
+ if (MCA_bus) {
+ 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.physmem = (unsigned long)membase;
+ card->hwif.isa.master = 1;
+
+ card->hwif.isa.irq = irq;
+ card->hwif.isa.type = Type;
+ card->nchannels = 2;
+ card->interface.channels = 1;
+ } else {
+ printk(KERN_WARNING
+ "eicon (%s): no MCA bus detected.\n",
+ card->interface.id);
+ kfree(card);
+ return;
+ }
break;
#endif /* CONFIG_MCA */
case EICON_CTYPE_QUADRO:
@@ -1023,6 +1048,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
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.physmem = (unsigned long)(membase + (i+1) * EICON_ISA_QOFFSET);
card->hwif.isa.master = 0;
strcpy(card->interface.id, id);
if (id[strlen(id) - 1] == 'a') {
@@ -1067,7 +1093,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
ISDN_FEATURE_L2_MODEM |
ISDN_FEATURE_L2_FAX |
ISDN_FEATURE_L3_TRANSDSP |
- ISDN_FEATURE_L3_FAX;
+ ISDN_FEATURE_L3_FCLASS2;
card->hwif.pci.card = (void *)card;
card->hwif.pci.PCIreg = pcic->PCIreg;
card->hwif.pci.PCIcfg = pcic->PCIcfg;
@@ -1091,7 +1117,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
ISDN_FEATURE_L2_MODEM |
ISDN_FEATURE_L2_FAX |
ISDN_FEATURE_L3_TRANSDSP |
- ISDN_FEATURE_L3_FAX;
+ ISDN_FEATURE_L3_FCLASS2;
card->hwif.pci.card = (void *)card;
card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem;
card->hwif.pci.PCIreg = pcic->PCIreg;
@@ -1116,6 +1142,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->bus = EICON_BUS_ISA;
card->hwif.isa.card = (void *)card;
card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
+ card->hwif.isa.physmem = (unsigned long)membase;
card->hwif.isa.master = 1;
card->hwif.isa.irq = irq;
card->hwif.isa.type = Type;
@@ -1130,6 +1157,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->bus = EICON_BUS_ISA;
card->hwif.isa.card = (void *)card;
card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
+ card->hwif.isa.physmem = (unsigned long)membase;
card->hwif.isa.master = 1;
card->hwif.isa.irq = irq;
card->hwif.isa.type = Type;
@@ -1151,14 +1179,15 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
}
for (j=0; j< (card->nchannels + 1); j++) {
memset((char *)&card->bch[j], 0, sizeof(eicon_chan));
- card->bch[j].plci = 0x8000;
- card->bch[j].ncci = 0x8000;
+ card->bch[j].statectrl = 0;
card->bch[j].l2prot = ISDN_PROTO_L2_X75I;
card->bch[j].l3prot = ISDN_PROTO_L3_TRANS;
card->bch[j].e.D3Id = 0;
card->bch[j].e.B2Id = 0;
card->bch[j].e.Req = 0;
card->bch[j].No = j;
+ card->bch[j].tskb1 = NULL;
+ card->bch[j].tskb2 = NULL;
skb_queue_head_init(&card->bch[j].e.X);
skb_queue_head_init(&card->bch[j].e.R);
}
diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c
index 5c96302cb..47196f953 100644
--- a/drivers/isdn/eicon/eicon_pci.c
+++ b/drivers/isdn/eicon/eicon_pci.c
@@ -1,12 +1,12 @@
-/* $Id: eicon_pci.c,v 1.10 1999/08/22 20:26:49 calle Exp $
+/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for PCI cards.
*
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
- * Thanks to Eicon Technology Diehl GmbH & Co. oHG for
+ * Thanks to Eicon Technology GmbH & Co. oHG for
* documents, informations and hardware.
*
* Deutsche Telekom AG for S2M support.
@@ -26,6 +26,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_pci.c,v $
+ * Revision 1.11 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
* Revision 1.10 1999/08/22 20:26:49 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
@@ -77,7 +81,7 @@
#include "eicon_pci.h"
-char *eicon_pci_revision = "$Revision: 1.10 $";
+char *eicon_pci_revision = "$Revision: 1.11 $";
#if CONFIG_PCI /* intire stuff is only for PCI */
diff --git a/drivers/isdn/eicon/eicon_pci.h b/drivers/isdn/eicon/eicon_pci.h
index a23faade2..384cc422c 100644
--- a/drivers/isdn/eicon/eicon_pci.h
+++ b/drivers/isdn/eicon/eicon_pci.h
@@ -1,9 +1,9 @@
-/* $Id: eicon_pci.h,v 1.3 1999/03/29 11:19:51 armin Exp $
+/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $
*
- * ISDN low-level module for Eicon.Diehl active ISDN-Cards (PCI part).
+ * ISDN low-level module for Eicon active ISDN-Cards (PCI part).
*
- * Copyright 1998,99 by Armin Schindler (mac@melware.de)
- * Copyright 1999 Cytronics & Melware (info@melware.de)
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
+ * Copyright 1999,2000 Cytronics & Melware (info@melware.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
@@ -20,6 +20,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_pci.h,v $
+ * Revision 1.4 2000/01/23 21:21:23 armin
+ * Added new trace capability and some updates.
+ * DIVA Server BRI now supports data for ISDNLOG.
+ *
* Revision 1.3 1999/03/29 11:19:51 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index e37d9c404..7bc340de9 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -137,6 +137,10 @@ ifeq ($(CONFIG_HISAX_HFC_PCI),y)
HFC_2BDS0 += hfc_pci.o
endif
+ifeq ($(CONFIG_HISAX_HFC_SX),y)
+ HFC_2BDS0 += hfc_sx.o
+endif
+
ifeq ($(CONFIG_HISAX_NICCY),y)
O_OBJS += niccy.o
ISAC_OBJ := isac.o
diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c
index e8abc9de2..5b3f3aadb 100644
--- a/drivers/isdn/hisax/arcofi.c
+++ b/drivers/isdn/hisax/arcofi.c
@@ -1,12 +1,19 @@
-/* $Id: arcofi.c,v 1.8 1999/08/25 16:50:51 keil Exp $
+/* $Id: arcofi.c,v 1.10 1999/12/23 15:09:32 keil Exp $
* arcofi.c Ansteuerung ARCOFI 2165
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
*
* $Log: arcofi.c,v $
+ * Revision 1.10 1999/12/23 15:09:32 keil
+ * change email
+ *
+ * Revision 1.9 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.8 1999/08/25 16:50:51 keil
* Fix bugs which cause 2.3.14 hangs (waitqueue init)
*
@@ -83,7 +90,7 @@ arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
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);
+ wake_up(&cs->dc.isac.arcofi_wait);
return(1);
}
switch (cs->dc.isac.arcofi_state) {
@@ -109,7 +116,7 @@ arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
del_timer(&cs->dc.isac.arcofitimer);
}
cs->dc.isac.arcofi_state = ARCOFI_NOP;
- wake_up_interruptible(&cs->dc.isac.arcofi_wait);
+ wake_up(&cs->dc.isac.arcofi_wait);
}
}
}
@@ -126,7 +133,7 @@ arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
del_timer(&cs->dc.isac.arcofitimer);
}
cs->dc.isac.arcofi_state = ARCOFI_NOP;
- wake_up_interruptible(&cs->dc.isac.arcofi_wait);
+ wake_up(&cs->dc.isac.arcofi_wait);
}
}
break;
diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h
index 86617d6a1..7d1c445e5 100644
--- a/drivers/isdn/hisax/arcofi.h
+++ b/drivers/isdn/hisax/arcofi.h
@@ -1,12 +1,15 @@
-/* $Id: arcofi.h,v 1.4 1999/07/01 08:11:18 keil Exp $
+/* $Id: arcofi.h,v 1.5 1999/12/23 15:09:32 keil Exp $
* arcofi.h Ansteuerung ARCOFI 2165
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
*
* $Log: arcofi.h,v $
+ * Revision 1.5 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.4 1999/07/01 08:11:18 keil
* Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
*
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
index 10657ad63..98c9736b6 100644
--- a/drivers/isdn/hisax/asuscom.c
+++ b/drivers/isdn/hisax/asuscom.c
@@ -1,4 +1,4 @@
-/* $Id: asuscom.c,v 1.8 1999/09/04 06:20:05 keil Exp $
+/* $Id: asuscom.c,v 1.9 1999/12/19 13:09:41 keil Exp $
* asuscom.c low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
*
@@ -8,6 +8,10 @@
*
*
* $Log: asuscom.c,v $
+ * Revision 1.9 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.8 1999/09/04 06:20:05 keil
* Changes from kernel set_current_state()
*
@@ -42,7 +46,7 @@
extern const char *CardType[];
-const char *Asuscom_revision = "$Revision: 1.8 $";
+const char *Asuscom_revision = "$Revision: 1.9 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -291,13 +295,13 @@ reset_asuscom(struct IsdnCardState *cs)
byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
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 */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
if (cs->subtyp == ASUS_IPAC) {
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index f343bfb5a..319e0b264 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.12 1999/09/04 06:20:05 keil Exp $
+/* $Id: avm_pci.c,v 1.14 1999/12/19 13:09:41 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,13 @@
*
*
* $Log: avm_pci.c,v $
+ * Revision 1.14 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
+ * Revision 1.13 1999/12/03 12:10:14 keil
+ * Bugfix: Wrong channel use on hangup of channel 2
+ *
* Revision 1.12 1999/09/04 06:20:05 keil
* Changes from kernel set_current_state()
*
@@ -56,7 +63,7 @@
#include <linux/interrupt.h>
extern const char *CardType[];
-static const char *avm_pci_rev = "$Revision: 1.12 $";
+static const char *avm_pci_rev = "$Revision: 1.14 $";
#define AVM_FRITZ_PCI 1
#define AVM_FRITZ_PNP 2
@@ -269,18 +276,26 @@ modehdlc(struct BCState *bcs, int mode, int bc)
int hdlc = bcs->channel;
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hdlc %c mode %d ichan %d",
- 'A' + hdlc, mode, bc);
- bcs->mode = mode;
- bcs->channel = bc;
+ debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d",
+ 'A' + hdlc, bcs->mode, mode, hdlc, bc);
bcs->hw.hdlc.ctrl.ctrl = 0;
switch (mode) {
+ case (-1): /* used for init */
+ bcs->mode = 1;
+ bcs->channel = bc;
+ bc = 0;
case (L1_MODE_NULL):
+ if (bcs->mode == L1_MODE_NULL)
+ return;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
write_ctrl(bcs, 5);
+ bcs->mode = L1_MODE_NULL;
+ bcs->channel = bc;
break;
case (L1_MODE_TRANS):
+ bcs->mode = mode;
+ bcs->channel = bc;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
write_ctrl(bcs, 5);
@@ -290,6 +305,8 @@ modehdlc(struct BCState *bcs, int mode, int bc)
hdlc_sched_event(bcs, B_XMTBUFREADY);
break;
case (L1_MODE_HDLC):
+ bcs->mode = mode;
+ bcs->channel = bc;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG;
write_ctrl(bcs, 5);
@@ -695,8 +712,8 @@ inithdlc(struct IsdnCardState *cs))
cs->bcs[1].BC_SetStack = setstack_hdlc;
cs->bcs[0].BC_Close = close_hdlcstate;
cs->bcs[1].BC_Close = close_hdlcstate;
- modehdlc(cs->bcs, 0, 0);
- modehdlc(cs->bcs + 1, 0, 0);
+ modehdlc(cs->bcs, -1, 0);
+ modehdlc(cs->bcs + 1, -1, 1);
}
static void
@@ -734,11 +751,11 @@ reset_avmpcipnp(struct IsdnCardState *cs)
save_flags(flags);
sti();
outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3));
}
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
index cb999972c..ce02a1bc6 100644
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -1,4 +1,4 @@
-/* $Id: bkm_a4t.c,v 1.8 1999/09/04 06:20:05 keil Exp $
+/* $Id: bkm_a4t.c,v 1.9 1999/12/19 13:09:41 keil 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
@@ -7,6 +7,10 @@
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log: bkm_a4t.c,v $
+ * Revision 1.9 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.8 1999/09/04 06:20:05 keil
* Changes from kernel set_current_state()
*
@@ -48,7 +52,7 @@
extern const char *CardType[];
-const char *bkm_a4t_revision = "$Revision: 1.8 $";
+const char *bkm_a4t_revision = "$Revision: 1.9 $";
static inline u_char
@@ -231,11 +235,11 @@ reset_bkm(struct IsdnCardState *cs)
sti();
/* Issue the I20 soft reset */
pI20_Regs->i20SysControl = 0xFF; /* all in */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
/* Remove the soft reset */
pI20_Regs->i20SysControl = sysRESET | 0xFF;
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
/* Set our configuration */
pI20_Regs->i20SysControl = sysRESET | sysCFG;
@@ -246,14 +250,14 @@ reset_bkm(struct IsdnCardState *cs)
g_A4T_ISAC_RES |
g_A4T_JADE_BOOTR |
g_A4T_ISAR_BOOTR;
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
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);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
restore_flags(flags);
}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index fda6c213c..8ec2e9a08 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -1,4 +1,4 @@
-/* $Id: bkm_a8.c,v 1.8 1999/09/04 06:20:05 keil Exp $
+/* $Id: bkm_a8.c,v 1.9 1999/12/19 13:09:41 keil 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
@@ -7,6 +7,10 @@
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log: bkm_a8.c,v $
+ * Revision 1.9 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.8 1999/09/04 06:20:05 keil
* Changes from kernel set_current_state()
*
@@ -49,7 +53,7 @@
extern const char *CardType[];
-const char sct_quadro_revision[] = "$Revision: 1.8 $";
+const char sct_quadro_revision[] = "$Revision: 1.9 $";
/* To survive the startup phase */
typedef struct {
@@ -298,13 +302,13 @@ reset_bkm(struct IsdnCardState *cs)
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
/* Remove the soft reset */
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
restore_flags(flags);
}
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index e4c26d9de..4a01218c3 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.39 1999/10/14 20:25:28 keil Exp $
+/* $Id: callc.c,v 2.40 1999/12/19 12:59:56 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -11,6 +11,10 @@
* Fritz Elfert
*
* $Log: callc.c,v $
+ * Revision 2.40 1999/12/19 12:59:56 keil
+ * fix leased line handling
+ * and cosmetics
+ *
* Revision 2.39 1999/10/14 20:25:28 keil
* add a statistic for error monitoring
*
@@ -163,7 +167,7 @@
#define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
#endif /* MODULE */
-const char *lli_revision = "$Revision: 2.39 $";
+const char *lli_revision = "$Revision: 2.40 $";
extern struct IsdnCard cards[];
extern int nrcards;
@@ -199,8 +203,7 @@ static int chancount = 0;
/*
* Find card with given driverId
*/
-static inline struct IsdnCardState
-*
+static inline struct IsdnCardState *
hisax_findcard(int driverid)
{
int i;
@@ -239,39 +242,39 @@ link_debug(struct Channel *chanp, int direction, char *fmt, ...)
}
enum {
- 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 */
+ 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_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",
+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_IN_PROCEED_SEND",
+ "ST_IN_PROCEED_SEND",
};
enum {
@@ -333,19 +336,19 @@ static char *strEvent[] =
static inline void
HL_LL(struct Channel *chanp, int command)
{
- isdn_ctrl ic;
+ isdn_ctrl ic;
- ic.driver = chanp->cs->myid;
- ic.command = command;
- ic.arg = chanp->chan;
- chanp->cs->iif.statcallb(&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;
-
+ isdn_ctrl ic;
+
if (chanp->proc->para.cause == NO_CAUSE)
return;
ic.driver = chanp->cs->myid;
@@ -363,42 +366,42 @@ lli_deliver_cause(struct Channel *chanp)
static inline void
lli_close(struct FsmInst *fi)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- FsmChangeState(fi, ST_NULL);
- chanp->Flags = 0;
- chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
+ FsmChangeState(fi, ST_NULL);
+ chanp->Flags = 0;
+ chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
}
- static void
+static void
lli_leased_in(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+ int ret;
- 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;
+ if (!chanp->leased)
+ return;
+ 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);
- }
+ 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);
+ }
}
@@ -408,14 +411,14 @@ lli_leased_in(struct FsmInst *fi, int event, void *arg)
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);
+ 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
@@ -427,14 +430,13 @@ lli_prep_dialout(struct FsmInst *fi, int event, void *arg)
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_SETUP | REQUEST, chanp);
- }
+ 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
@@ -442,18 +444,17 @@ lli_resume(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- 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);
- }
+ 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
@@ -521,15 +522,15 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
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 */
+ 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);
- }
+ 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 */
break;
@@ -590,17 +591,17 @@ lli_init_bchan_in(struct FsmInst *fi, int event, void *arg)
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);
+ 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);
+ 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);
- }
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
+ }
}
/* Call suspend */
@@ -616,51 +617,84 @@ lli_suspend(struct FsmInst *fi, int event, void *arg)
/* Call clearing */
static void
+lli_leased_hup(struct FsmInst *fi, struct Channel *chanp)
+{
+ isdn_ctrl ic;
+
+ ic.driver = chanp->cs->myid;
+ ic.command = ISDN_STAT_CAUSE;
+ ic.arg = chanp->chan;
+ sprintf(ic.parm.num, "L0010");
+ chanp->cs->iif.statcallb(&ic);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_DHUP");
+ HL_LL(chanp, ISDN_STAT_DHUP);
+ lli_close(fi);
+}
+
+static void
lli_disconnect_req(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- FsmChangeState(fi, ST_WAIT_DRELEASE);
- chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
- chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
+ if (chanp->leased) {
+ lli_leased_hup(fi, chanp);
+ } else {
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
+ chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
+ chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
+ chanp->proc);
+ }
}
static void
lli_disconnect_reject(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- 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);
+ if (chanp->leased) {
+ lli_leased_hup(fi, chanp);
+ } else {
+ 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_dhup_close(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ 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);
+ if (chanp->leased) {
+ lli_leased_hup(fi, chanp);
+ } else {
+ 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_reject_req(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
+ if (chanp->leased) {
+ lli_leased_hup(fi, chanp);
+ return;
+ }
#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);
+ 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);
+ 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
}
@@ -678,54 +712,45 @@ static void
lli_start_disc(struct FsmInst *fi, int event, void *arg)
{
struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
if (chanp->leased) {
- ic.command = ISDN_STAT_CAUSE;
- ic.arg = chanp->chan;
- sprintf(ic.parm.num, "L0010");
- chanp->cs->iif.statcallb(&ic);
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_DHUP");
- HL_LL(chanp, ISDN_STAT_DHUP);
- lli_close(fi);
+ lli_leased_hup(fi, chanp);
} else {
- lli_disconnect_req(fi, event, arg);
+ lli_disconnect_req(fi, event, arg);
}
}
static void
lli_rel_b_disc(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
-
- release_b_st(chanp);
- lli_start_disc(fi, event, arg);
+ struct Channel *chanp = fi->userdata;
+
+ release_b_st(chanp);
+ lli_start_disc(fi, event, arg);
}
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);
+ struct Channel *chanp = fi->userdata;
- lli_rel_b_disc(fi, event, arg);
+ 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;
+ 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);
+ 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
@@ -742,63 +767,65 @@ lli_release_bchan(struct FsmInst *fi, int event, void *arg)
static void
lli_rel_b_dhup(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- release_b_st(chanp);
- lli_dhup_close(fi, event, arg);
+ release_b_st(chanp);
+ lli_dhup_close(fi, event, arg);
}
static void
lli_bhup_dhup(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
-
- lli_rel_b_dhup(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_abort(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- chanp->data_open = 0;
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
-
- lli_bhup_dhup(fi, event, arg);
+ 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);
+ struct Channel *chanp = fi->userdata;
+
+ if (chanp->leased) {
+ lli_leased_hup(fi, chanp);
+ } else {
+ 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);
+ 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);
+ struct Channel *chanp = fi->userdata;
- lli_rel_b_release_req(fi, event, arg);
+ if (chanp->debug & 1)
+ link_debug(chanp, 0, "STAT_BHUP");
+ HL_LL(chanp, ISDN_STAT_BHUP);
+ lli_rel_b_release_req(fi, event, arg);
}
@@ -825,7 +852,7 @@ lli_dchan_not_ready(struct FsmInst *fi, int event, void *arg)
if (chanp->debug & 1)
link_debug(chanp, 0, "STAT_DHUP");
- HL_LL(chanp, ISDN_STAT_DHUP);
+ HL_LL(chanp, ISDN_STAT_DHUP);
}
static void
@@ -836,67 +863,65 @@ lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
if (chanp->debug & 1)
link_debug(chanp, 0, "STAT_DHUP");
HL_LL(chanp, ISDN_STAT_DHUP);
- lli_close(fi);
+ lli_close(fi);
}
static void
lli_error(struct FsmInst *fi, int event, void *arg)
{
- FsmChangeState(fi, ST_WAIT_DRELEASE);
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
}
static void
lli_failure_l(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
+ 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);
+ 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_rel_b_fail(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- release_b_st(chanp);
- lli_failure_l(fi, event, arg);
+ release_b_st(chanp);
+ lli_failure_l(fi, event, arg);
}
static void
lli_bhup_fail(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- if (chanp->debug & 1)
- link_debug(chanp, 0, "STAT_BHUP");
- HL_LL(chanp, ISDN_STAT_BHUP);
-
- lli_rel_b_fail(fi, event, arg);
+ 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_failure_a(struct FsmInst *fi, int event, void *arg)
{
- struct Channel *chanp = fi->userdata;
+ struct Channel *chanp = fi->userdata;
- chanp->data_open = 0;
- chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
-
- lli_bhup_fail(fi, event, arg);
+ 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 =
- {
+/* *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},
@@ -959,10 +984,9 @@ lli_failure_a(struct FsmInst *fi, int event, void *arg)
{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))
@@ -985,9 +1009,9 @@ release_b_st(struct Channel *chanp)
{
struct PStack *st = chanp->b_st;
- if(test_and_clear_bit(FLG_START_B, &chanp->Flags)) {
- chanp->bcs->BC_Close(chanp->bcs);
- switch (chanp->l2_active_protocol) {
+ 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;
@@ -995,10 +1019,10 @@ release_b_st(struct Channel *chanp)
case (ISDN_PROTO_L2_TRANS):
case (ISDN_PROTO_L2_MODEM):
case (ISDN_PROTO_L2_FAX):
- releasestack_transl2(st);
- break;
- }
- }
+ releasestack_transl2(st);
+ break;
+ }
+ }
}
struct Channel
@@ -1013,10 +1037,10 @@ struct Channel
else
i=0;
- if (!bch)
- { i = 2; /* virtual channel */
- chanp += 2;
- }
+ if (!bch) {
+ i = 2; /* virtual channel */
+ chanp += 2;
+ }
while (i < ((bch) ? cs->chanlimit : (2 + MAX_WAITING_CALLS))) {
if (chanp->fi.state == ST_NULL)
@@ -1025,17 +1049,17 @@ struct Channel
i++;
}
- 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++;
- }
- }
+ 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 (NULL);
}
@@ -1053,19 +1077,19 @@ 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;
- 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;
+ 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;
@@ -1121,8 +1145,8 @@ dchan_l3l4(struct PStack *st, int pr, void *arg)
break;
case (CC_REDIR | INDICATION):
stat_redir_result(cs, chanp->chan, pc->redir_result);
- break;
- default:
+ break;
+ default:
if (chanp->debug & 0x800) {
HiSax_putstatus(chanp->cs, "Ch",
"%d L3->L4 unknown primitiv %#x",
@@ -1147,7 +1171,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.l3ml3 = dummy_pstack;
(*stp)->l3.l3l4 = dummy_pstack;
(*stp)->lli.l4l3 = dummy_pstack;
(*stp)->ma.layer = dummy_pstack;
@@ -1230,8 +1254,8 @@ init_chan(int chan, struct IsdnCardState *csta)
}
int
-CallcNewChan(struct IsdnCardState *csta)
-{ int i;
+CallcNewChan(struct IsdnCardState *csta) {
+ int i;
chancount += 2;
init_chan(0, csta);
@@ -1240,8 +1264,7 @@ CallcNewChan(struct IsdnCardState *csta)
for (i = 0; i < MAX_WAITING_CALLS; i++)
init_chan(i+2,csta);
- printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n");
-
+ 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");
csta->channel->d_st->lli.l4l3(csta->channel->d_st,
@@ -1272,13 +1295,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) {
- 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);
@@ -1311,7 +1334,7 @@ lldata_handler(struct PStack *st, int pr, void *arg)
break;
default:
printk(KERN_WARNING "lldata_handler unknown primitive %#x\n",
- pr);
+ pr);
break;
}
}
@@ -1341,7 +1364,7 @@ lltrans_handler(struct PStack *st, int pr, void *arg)
break;
default:
printk(KERN_WARNING "lltrans_handler unknown primitive %#x\n",
- pr);
+ pr);
break;
}
}
@@ -1444,7 +1467,7 @@ leased_l4l3(struct PStack *st, int pr, void *arg)
break;
default:
printk(KERN_WARNING "transd_l4l3 unknown primitive %#x\n",
- pr);
+ pr);
break;
}
}
@@ -1598,7 +1621,7 @@ HiSax_command(isdn_ctrl * ic)
if (!csta) {
printk(KERN_ERR
"HiSax: if_command %d called with invalid driverId %d!\n",
- ic->command, ic->driver);
+ ic->command, ic->driver);
return -ENODEV;
}
switch (ic->command) {
@@ -1771,11 +1794,18 @@ HiSax_command(isdn_ctrl * ic)
num = *(unsigned int *) ic->parm.num;
chanp = csta->channel + (num & 1);
num = num >>1;
- test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
- chanp->d_st->l2.tei = num;
- HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num);
- printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
- num);
+ if (num == 127) {
+ test_and_clear_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
+ chanp->d_st->l2.tei = -1;
+ HiSax_putstatus(csta, "set card ", "in VAR TEI mode");
+ printk(KERN_DEBUG "HiSax: set card in VAR TEI mode\n");
+ } else {
+ test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
+ chanp->d_st->l2.tei = num;
+ HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num);
+ printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
+ num);
+ }
chanp->d_st->lli.l4l3(chanp->d_st,
DL_ESTABLISH | REQUEST, NULL);
break;
@@ -1811,7 +1841,7 @@ HiSax_command(isdn_ctrl * ic)
if (csta->auxcmd)
return(csta->auxcmd(csta, ic));
printk(KERN_DEBUG "HiSax: invalid ioclt %d\n",
- (int) ic->arg);
+ (int) ic->arg);
return (-EINVAL);
}
break;
@@ -1839,11 +1869,11 @@ HiSax_command(isdn_ctrl * ic)
break;
/* protocol specific io commands */
- case (ISDN_CMD_PROT_IO):
+ 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);
+ return(-EINVAL);
break;
default:
if (csta->auxcmd)
@@ -1865,7 +1895,7 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
if (!csta) {
printk(KERN_ERR
- "HiSax: if_sendbuf called with invalid driverId!\n");
+ "HiSax: if_sendbuf called with invalid driverId!\n");
return -ENODEV;
}
chanp = csta->channel + chan;
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index a75810f02..8d389c623 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1,10 +1,21 @@
-/* $Id: config.c,v 2.40 1999/10/30 13:09:45 keil Exp $
+/* $Id: config.c,v 2.43 2000/01/20 19:49:36 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
*
*
* $Log: config.c,v $
+ * Revision 2.43 2000/01/20 19:49:36 keil
+ * Support teles 13.3c vendor version 2.1
+ *
+ * Revision 2.42 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
+ * Revision 2.41 1999/11/18 00:00:43 werner
+ *
+ * Added support for HFC-S+ and HFC-SP cards
+ *
* Revision 2.40 1999/10/30 13:09:45 keil
* Version 3.3c
*
@@ -202,6 +213,7 @@
* 34 Gazel ISDN cards
* 35 HFC 2BDS0 PCI none
* 36 Winbond 6692 PCI none
+ * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase
*
* protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
*
@@ -217,6 +229,7 @@ const char *CardType[] =
"AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
"Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir",
"Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
+ "HFC 2BDS0 SX",
};
void HiSax_closecard(int cardnr);
@@ -352,6 +365,13 @@ EXPORT_SYMBOL(sedl_init_pcmcia);
#define DEFAULT_CFG {0,0,0,0}
#endif
+#ifdef CONFIG_HISAX_HFC_SX
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_HFC_SX
+#define DEFAULT_CFG {5,0x2E0,0,0}
+#endif
+
#ifdef CONFIG_HISAX_AMD7930
#undef DEFAULT_CARD
@@ -529,9 +549,9 @@ HiSaxVersion(void))
printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
#ifdef MODULE
- printk(KERN_INFO "HiSax: Version 3.3c (module)\n");
+ printk(KERN_INFO "HiSax: Version 3.3d (module)\n");
#else
- printk(KERN_INFO "HiSax: Version 3.3c (kernel)\n");
+ printk(KERN_INFO "HiSax: Version 3.3d (kernel)\n");
#endif
strcpy(tmp, l1_revision);
printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
@@ -687,6 +707,10 @@ extern int setup_hfcs(struct IsdnCard *card);
extern int setup_hfcpci(struct IsdnCard *card);
#endif
+#if CARD_HFC_SX
+extern int setup_hfcsx(struct IsdnCard *card);
+#endif
+
#if CARD_AMD7930
extern int setup_amd7930(struct IsdnCard *card);
#endif
@@ -994,7 +1018,7 @@ HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
while (cnt) {
cs->cardmsg(cs, CARD_INIT, NULL);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
/* Timeout 10ms */
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
@@ -1208,6 +1232,11 @@ checkcard(int cardnr, char *id, int *busy_flag))
ret = setup_hfcpci(card);
break;
#endif
+#if CARD_HFC_SX
+ case ISDN_CTYPE_HFC_SX:
+ ret = setup_hfcsx(card);
+ break;
+#endif
#if CARD_NICCY
case ISDN_CTYPE_NICCY:
ret = setup_niccy(card);
@@ -1515,6 +1544,7 @@ HiSax_init(void))
case ISDN_CTYPE_FRITZPCI:
case ISDN_CTYPE_HSTSAPHIR:
case ISDN_CTYPE_GAZEL:
+ case ISDN_CTYPE_HFC_SX:
cards[i].para[0] = irq[i];
cards[i].para[1] = io[i];
break;
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index f1161e63d..5dc868942 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -1,4 +1,4 @@
-/* $Id: diva.c,v 1.17 1999/09/04 06:20:06 keil Exp $
+/* $Id: diva.c,v 1.18 1999/12/19 13:09:41 keil Exp $
* diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards
*
@@ -12,6 +12,10 @@
*
*
* $Log: diva.c,v $
+ * Revision 1.18 1999/12/19 13:09:41 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.17 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -80,7 +84,7 @@
extern const char *CardType[];
-const char *Diva_revision = "$Revision: 1.17 $";
+const char *Diva_revision = "$Revision: 1.18 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -750,30 +754,30 @@ reset_diva(struct IsdnCardState *cs)
sti();
if (cs->subtyp == DIVA_IPAC_ISA) {
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0);
} 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;
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
*ireg = PITA_PARA_MPX_MODE;
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
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);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */
byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
if (cs->subtyp == DIVA_ISA)
cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 4dbe40c38..1e425ccc5 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -1,4 +1,4 @@
-/* $Id: elsa.c,v 2.19 1999/09/04 06:20:06 keil Exp $
+/* $Id: elsa.c,v 2.20 1999/12/19 13:09:42 keil Exp $
* elsa.c low level stuff for Elsa isdn cards
*
@@ -14,6 +14,10 @@
* for ELSA PCMCIA support
*
* $Log: elsa.c,v $
+ * Revision 2.20 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 2.19 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -99,7 +103,7 @@
extern const char *CardType[];
-const char *Elsa_revision = "$Revision: 2.19 $";
+const char *Elsa_revision = "$Revision: 2.20 $";
const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
"PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI",
@@ -578,10 +582,10 @@ reset_elsa(struct IsdnCardState *cs)
save_flags(flags);
sti();
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
restore_flags(flags);
@@ -785,7 +789,7 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
byteout(cs->hw.elsa.timer, 0);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((110*HZ)/1000);
restore_flags(flags);
cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c
index aa0ff4adb..665fa2c74 100644
--- a/drivers/isdn/hisax/fsm.c
+++ b/drivers/isdn/hisax/fsm.c
@@ -1,12 +1,15 @@
-/* $Id: fsm.c,v 1.10 1998/11/15 23:54:39 keil Exp $
+/* $Id: fsm.c,v 1.11 1999/12/23 15:09:32 keil Exp $
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
* $Log: fsm.c,v $
+ * Revision 1.11 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.10 1998/11/15 23:54:39 keil
* changes from 2.0
*
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index bb388c5c2..2b22cdfea 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -1,11 +1,14 @@
-/* $Id: hfc_2bds0.c,v 1.10 1999/10/14 20:25:28 keil Exp $
+/* $Id: hfc_2bds0.c,v 1.11 1999/12/23 15:09:32 keil Exp $
*
* specific routines for CCD's HFC 2BDS0
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: hfc_2bds0.c,v $
+ * Revision 1.11 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.10 1999/10/14 20:25:28 keil
* add a statistic for error monitoring
*
diff --git a/drivers/isdn/hisax/hfc_2bds0.h b/drivers/isdn/hisax/hfc_2bds0.h
index d11e8b503..32f703662 100644
--- a/drivers/isdn/hisax/hfc_2bds0.h
+++ b/drivers/isdn/hisax/hfc_2bds0.h
@@ -1,11 +1,14 @@
-/* $Id: hfc_2bds0.h,v 1.2 1998/02/02 13:26:15 keil Exp $
+/* $Id: hfc_2bds0.h,v 1.3 1999/12/23 15:09:32 keil Exp $
* specific defines for CCD's HFC 2BDS0
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: hfc_2bds0.h,v $
+ * Revision 1.3 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.2 1998/02/02 13:26:15 keil
* New
*
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index 6620b90ec..f3edefa3e 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.10 1999/10/14 20:25:28 keil Exp $
+/* $Id: hfc_2bs0.c,v 1.12 1999/12/19 14:17:12 keil Exp $
* specific routines for CCD's HFC 2BS0
*
@@ -6,6 +6,13 @@
*
*
* $Log: hfc_2bs0.c,v $
+ * Revision 1.12 1999/12/19 14:17:12 keil
+ * fix compiler warning
+ *
+ * Revision 1.11 1999/11/21 12:41:18 werner
+ *
+ * Implemented full audio support
+ *
* Revision 1.10 1999/10/14 20:25:28 keil
* add a statistic for error monitoring
*
@@ -210,7 +217,7 @@ hfc_empty_fifo(struct BCState *bcs, int count)
WaitForBusy(cs);
return (NULL);
}
- if (count < 4) {
+ if ((count < 4) && (bcs->mode != L1_MODE_TRANS)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hfc_empty_fifo: incoming packet too small");
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
@@ -225,47 +232,55 @@ hfc_empty_fifo(struct BCState *bcs, int count)
#endif
return (NULL);
}
- if (!(skb = dev_alloc_skb(count - 3)))
+ if (bcs->mode == L1_MODE_TRANS)
+ count -= 1;
+ else
+ count -= 3;
+ if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HFC: receive out of memory\n");
else {
- ptr = skb_put(skb, count - 3);
+ ptr = skb_put(skb, count);
idx = 0;
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
while ((idx < count - 3) && WaitNoBusy(cs)) {
*ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
idx++;
}
- if (idx != count - 3) {
+ if (idx != count) {
debugl1(cs, "RFIFO BUSY error");
printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
dev_kfree_skb(skb);
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
- HFC_CHANNEL(bcs->channel));
- WaitForBusy(cs);
+ if (bcs->mode != L1_MODE_TRANS) {
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+ HFC_CHANNEL(bcs->channel));
+ WaitForBusy(cs);
+ }
return (NULL);
}
- WaitNoBusy(cs);
- chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
- WaitNoBusy(cs);
- chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
- bcs->channel, chksum, stat);
- if (stat) {
- debugl1(cs, "FIFO CRC error");
- dev_kfree_skb(skb);
- skb = NULL;
+ if (bcs->mode != L1_MODE_TRANS) {
+ WaitNoBusy(cs);
+ chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
+ WaitNoBusy(cs);
+ chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
+ bcs->channel, chksum, stat);
+ if (stat) {
+ debugl1(cs, "FIFO CRC error");
+ dev_kfree_skb(skb);
+ skb = NULL;
#ifdef ERROR_STATISTIC
- bcs->err_crc++;
+ bcs->err_crc++;
#endif
+ }
+ WaitNoBusy(cs);
+ stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+ HFC_CHANNEL(bcs->channel));
+ WaitForBusy(cs);
}
- WaitNoBusy(cs);
- stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
- HFC_CHANNEL(bcs->channel));
- WaitForBusy(cs);
}
return (skb);
}
@@ -277,6 +292,7 @@ hfc_fill_fifo(struct BCState *bcs)
long flags;
int idx, fcnt;
int count;
+ int z1, z2;
u_char cip;
if (!bcs->tx_skb)
@@ -288,29 +304,39 @@ hfc_fill_fifo(struct BCState *bcs)
cli();
cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel);
if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
- cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
- WaitForBusy(cs);
+ cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
+ WaitForBusy(cs);
}
WaitNoBusy(cs);
- bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
- bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
- bcs->hw.hfc.send[bcs->hw.hfc.f1]);
- fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
- if (fcnt < 0)
- fcnt += 32;
- if (fcnt > 30) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo more as 30 frames");
- restore_flags(flags);
- return;
- }
- count = GetFreeFifoBytes(bcs);
+ if (bcs->mode != L1_MODE_TRANS) {
+ bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
+ bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
+ bcs->hw.hfc.send[bcs->hw.hfc.f1]);
+ fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
+ if (fcnt < 0)
+ fcnt += 32;
+ if (fcnt > 30) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc_fill_fifo more as 30 frames");
+ restore_flags(flags);
+ return;
+ }
+ count = GetFreeFifoBytes(bcs);
+ }
+ else {
+ WaitForBusy(cs);
+ z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
+ z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
+ count = z1 - z2;
+ if (count < 0)
+ count += cs->hw.hfc.fifosize;
+ } /* L1_MODE_TRANS */
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_fill_fifo %d count(%ld/%d)",
bcs->channel, bcs->tx_skb->len,
@@ -335,9 +361,11 @@ hfc_fill_fifo(struct BCState *bcs)
count = -1;
dev_kfree_skb(bcs->tx_skb);
bcs->tx_skb = NULL;
- WaitForBusy(cs);
- WaitNoBusy(cs);
- cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
+ if (bcs->mode != L1_MODE_TRANS) {
+ WaitForBusy(cs);
+ WaitNoBusy(cs);
+ cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
+ }
if (bcs->st->lli.l1writewakeup && (count >= 0))
bcs->st->lli.l1writewakeup(bcs->st, count);
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
@@ -366,32 +394,39 @@ main_irq_hfc(struct BCState *bcs)
WaitForBusy(cs);
}
WaitNoBusy(cs);
- f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
- WaitNoBusy(cs);
- f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
- if (f1 != f2) {
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
- bcs->channel, f1, f2);
+ receive = 0;
+ if (bcs->mode == L1_MODE_HDLC) {
+ f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
+ WaitNoBusy(cs);
+ f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+ if (f1 != f2) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
+ bcs->channel, f1, f2);
+ receive = 1;
+ }
+ }
+ if (receive || (bcs->mode == L1_MODE_TRANS)) {
WaitForBusy(cs);
z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
rcnt = z1 - z2;
if (rcnt < 0)
rcnt += cs->hw.hfc.fifosize;
- rcnt++;
- if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
- bcs->channel, z1, z2, rcnt);
-/* sti(); */
- if ((skb = hfc_empty_fifo(bcs, rcnt))) {
- skb_queue_tail(&bcs->rqueue, skb);
- hfc_sched_event(bcs, B_RCVBUFREADY);
+ if ((bcs->mode == L1_MODE_HDLC) || (rcnt)) {
+ rcnt++;
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
+ bcs->channel, z1, z2, rcnt);
+ /* sti(); */
+ if ((skb = hfc_empty_fifo(bcs, rcnt))) {
+ skb_queue_tail(&bcs->rqueue, skb);
+ hfc_sched_event(bcs, B_RCVBUFREADY);
+ }
}
receive = 1;
- } else
- receive = 0;
+ }
restore_flags(flags);
udelay(1);
cli();
@@ -432,12 +467,19 @@ mode_hfc(struct BCState *bcs, int mode, int bc)
switch (mode) {
case (L1_MODE_NULL):
- if (bc)
+ if (bc) {
+ cs->hw.hfc.ctmt &= ~1;
cs->hw.hfc.isac_spcr &= ~0x03;
- else
+ }
+ else {
+ cs->hw.hfc.ctmt &= ~2;
cs->hw.hfc.isac_spcr &= ~0x0c;
+ }
break;
case (L1_MODE_TRANS):
+ cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */
+ cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
+ hfc_clear_fifo(bcs); /* complete fifo clear */
if (bc) {
cs->hw.hfc.ctmt |= 1;
cs->hw.hfc.isac_spcr &= ~0x03;
@@ -462,7 +504,7 @@ mode_hfc(struct BCState *bcs, int mode, int bc)
}
cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr);
- if (mode)
+ if (mode == L1_MODE_HDLC)
hfc_clear_fifo(bcs);
}
diff --git a/drivers/isdn/hisax/hfc_2bs0.h b/drivers/isdn/hisax/hfc_2bs0.h
index cce8e4a35..981ae7cb3 100644
--- a/drivers/isdn/hisax/hfc_2bs0.h
+++ b/drivers/isdn/hisax/hfc_2bs0.h
@@ -1,11 +1,14 @@
-/* $Id: hfc_2bs0.h,v 1.1 1997/09/11 17:31:34 keil Exp $
+/* $Id: hfc_2bs0.h,v 1.2 1999/12/23 15:09:32 keil Exp $
* specific defines for CCD's HFC 2BS0
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: hfc_2bs0.h,v $
+ * Revision 1.2 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.1 1997/09/11 17:31:34 keil
* Common part for HFC 2BS0 based cards
*
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 518c1670a..76f353861 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.23 1999/11/07 17:01:55 keil Exp $
+/* $Id: hfc_pci.c,v 1.26 2000/02/09 20:22:55 werner Exp $
* hfc_pci.c low level driver for CCD´s hfc-pci based cards
*
@@ -23,6 +23,18 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hfc_pci.c,v $
+ * Revision 1.26 2000/02/09 20:22:55 werner
+ *
+ * Updated PCI-ID table
+ *
+ * Revision 1.25 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
+ * Revision 1.24 1999/11/17 23:59:55 werner
+ *
+ * removed unneeded data
+ *
* Revision 1.23 1999/11/07 17:01:55 keil
* fix for 2.3 pci structs
*
@@ -114,7 +126,7 @@
extern const char *CardType[];
-static const char *hfcpci_revision = "$Revision: 1.23 $";
+static const char *hfcpci_revision = "$Revision: 1.26 $";
/* table entry in the PCI devices list */
typedef struct {
@@ -143,26 +155,12 @@ static const PCI_ENTRY id_list[] =
{0x1051, 0x0100, "Motorola MC145575", "MC145575"},
{0x1397, 0xB100, "Seyeon", "B100"},
{0x15B0, 0x2BD0, "Zoltrix", "2BD0"},
+ {0x114f, 0x71, "Digi intl.","Digicom"},
{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 */
@@ -179,13 +177,12 @@ release_io_hfcpci(struct IsdnCardState *cs)
restore_flags(flags);
Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */
#if CONFIG_PCI
pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0); /* disable 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;
@@ -211,10 +208,10 @@ reset_hfcpci(struct IsdnCardState *cs)
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 */
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
if (Read_hfc(cs, HFCPCI_STATUS) & 2)
printk(KERN_WARNING "HFC-PCI init bit busy\n");
@@ -1647,24 +1644,6 @@ hfcpci_bh(struct IsdnCardState *cs)
}
-/*************************************/
-/* Alloc memory send data for queues */
-/*************************************/
-__initfunc(unsigned int
- *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 */
/********************************/
@@ -1676,10 +1655,6 @@ __initfunc(void
cs->dbusytimer.data = (long) cs;
init_timer(&cs->dbusytimer);
cs->tqueue.routine = (void *) (void *) hfcpci_bh;
- 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;
@@ -1712,7 +1687,7 @@ hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
inithfcpci(cs);
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */
/* now switch timer interrupt off */
cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
@@ -1746,8 +1721,6 @@ __initfunc(int
printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
#if CONFIG_PCI
cs->hw.hfcpci.int_s1 = 0;
- 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) {
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
new file mode 100644
index 000000000..462de9d91
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -0,0 +1,1583 @@
+/* $Id: hfc_sx.c,v 1.3 2000/01/20 19:49:36 keil Exp $
+
+ * hfc_sx.c low level driver for CCD´s hfc-s+/sp based cards
+ *
+ * Author Werner Cornelius (werner@isdn4linux.de)
+ * based on existing driver for CCD HFC PCI cards
+ *
+ * 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_sx.c,v $
+ * Revision 1.3 2000/01/20 19:49:36 keil
+ * Support teles 13.3c vendor version 2.1
+ *
+ * Revision 1.2 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
+ * Revision 1.1 1999/11/18 00:09:18 werner
+ *
+ * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM.
+ * Audio and Echo are supported.
+ *
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_sx.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+extern const char *CardType[];
+
+static const char *hfcsx_revision = "$Revision: 1.3 $";
+
+/***************************************/
+/* IRQ-table for CCDs demo board */
+/* IRQs 6,5,10,11,12,15 are supported */
+/***************************************/
+
+/* Teles 16.3c Vendor Id TAG2620, Version 1.0, Vendor version 2.1
+ *
+ * Thanks to Uwe Wisniewski
+ *
+ * ISA-SLOT Signal PIN
+ * B25 IRQ3 92 IRQ_G
+ * B23 IRQ5 94 IRQ_A
+ * B4 IRQ2/9 95 IRQ_B
+ * D3 IRQ10 96 IRQ_C
+ * D4 IRQ11 97 IRQ_D
+ * D5 IRQ12 98 IRQ_E
+ * D6 IRQ15 99 IRQ_F
+ */
+
+#undef CCD_DEMO_BOARD
+#ifdef CCD_DEMO_BOARD
+static u_char ccd_sp_irqtab[16] = {
+ 0,0,0,0,0,2,1,0,0,0,3,4,5,0,0,6
+};
+#else /* Teles 16.3c */
+static u_char ccd_sp_irqtab[16] = {
+ 0,0,0,7,0,1,0,0,0,2,3,4,5,0,0,6
+};
+#endif
+#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+/******************************/
+/* In/Out access to registers */
+/******************************/
+static inline void
+Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val)
+{ register int flags;
+
+ save_flags(flags);
+ cli();
+ byteout(cs->hw.hfcsx.base+1, regnum);
+ byteout(cs->hw.hfcsx.base, val);
+ restore_flags(flags);
+}
+
+static inline u_char
+Read_hfc(struct IsdnCardState *cs, u_char regnum)
+{ register int flags;
+ register u_char ret;
+
+ save_flags(flags);
+ cli();
+ byteout(cs->hw.hfcsx.base+1, regnum);
+ ret = bytein(cs->hw.hfcsx.base);
+ restore_flags(flags);
+ return(ret);
+}
+
+
+/**************************************************/
+/* select a fifo and remember which one for reuse */
+/**************************************************/
+static void
+fifo_select(struct IsdnCardState *cs, u_char fifo)
+{ int flags;
+
+ if (fifo == cs->hw.hfcsx.last_fifo)
+ return; /* still valid */
+
+ save_flags(flags);
+ cli();
+ byteout(cs->hw.hfcsx.base+1, HFCSX_FIF_SEL);
+ byteout(cs->hw.hfcsx.base, fifo);
+ while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+ udelay(4);
+ byteout(cs->hw.hfcsx.base, fifo);
+ while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+ restore_flags(flags);
+}
+
+/******************************************/
+/* reset the specified fifo to defaults. */
+/* If its a send fifo init needed markers */
+/******************************************/
+static void
+reset_fifo(struct IsdnCardState *cs, u_char fifo)
+{ int flags;
+
+ save_flags(flags);
+ cli();
+ fifo_select(cs, fifo); /* first select the fifo */
+ byteout(cs->hw.hfcsx.base+1, HFCSX_CIRM);
+ byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.cirm | 0x80); /* reset cmd */
+ udelay(1);
+ while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+ restore_flags(flags);
+}
+
+
+/*************************************************************/
+/* write_fifo writes the skb contents to the desired fifo */
+/* if no space is available or an error occurs 0 is returned */
+/* the skb is not released in any way. */
+/*************************************************************/
+static int
+write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max)
+{ unsigned short *msp;
+ int fifo_size, count, z1, z2;
+ u_char f_msk, f1, f2, *src;
+
+ if (skb->len <= 0) return(0);
+ if (fifo & 1) return(0); /* no write fifo */
+
+ fifo_select(cs, fifo);
+ if (fifo & 4) {
+ fifo_size = D_FIFO_SIZE; /* D-channel */
+ f_msk = MAX_D_FRAMES;
+ if (trans_max) return(0); /* only HDLC */
+ }
+ else {
+ fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
+ f_msk = MAX_B_FRAMES;
+ }
+
+ z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
+ z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
+
+ /* Check for transparent mode */
+ if (trans_max) {
+ z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
+ z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
+ count = z2 - z1;
+ if (count <= 0)
+ count += fifo_size; /* free bytes */
+ if (count < skb->len+1) return(0); /* no room */
+ count = fifo_size - count; /* bytes still not send */
+ if (count > 2 * trans_max) return(0); /* delay to long */
+ count = skb->len;
+ src = skb->data;
+ while (count--)
+ Write_hfc(cs, HFCSX_FIF_DWR, *src++);
+ return(1); /* success */
+ }
+
+ msp = ((struct hfcsx_extra *)(cs->hw.hfcsx.extra))->marker;
+ msp += (((fifo >> 1) & 3) * (MAX_B_FRAMES+1));
+ f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
+ f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
+
+ count = f1 - f2; /* frame count actually buffered */
+ if (count < 0)
+ count += (f_msk + 1); /* if wrap around */
+ if (count > f_msk-1) {
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_write_fifo %d more as %d frames",fifo,f_msk-1);
+ return(0);
+ }
+
+ *(msp + f1) = z1; /* remember marker */
+
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_write_fifo %d f1(%x) f2(%x) z1(f1)(%x)",
+ fifo, f1, f2, z1);
+ /* now determine free bytes in FIFO buffer */
+ count = *(msp + f2) - z1;
+ if (count <= 0)
+ count += fifo_size; /* count now contains available bytes */
+
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)",
+ fifo, skb->len, count);
+ if (count < skb->len) {
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo);
+ return(0);
+ }
+
+ count = skb->len; /* get frame len */
+ src = skb->data; /* source pointer */
+ while (count--)
+ Write_hfc(cs, HFCSX_FIF_DWR, *src++);
+
+ Read_hfc(cs, HFCSX_FIF_INCF1); /* increment F1 */
+ udelay(1);
+ while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+ return(1);
+}
+
+/***************************************************************/
+/* read_fifo reads data to an skb from the desired fifo */
+/* if no data is available or an error occurs NULL is returned */
+/* the skb is not released in any way. */
+/***************************************************************/
+static struct sk_buff *
+read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
+{ int fifo_size, count, z1, z2;
+ u_char f_msk, f1, f2, *dst;
+ struct sk_buff *skb;
+
+ if (!(fifo & 1)) return(NULL); /* no read fifo */
+ fifo_select(cs, fifo);
+ if (fifo & 4) {
+ fifo_size = D_FIFO_SIZE; /* D-channel */
+ f_msk = MAX_D_FRAMES;
+ if (trans_max) return(NULL); /* only hdlc */
+ }
+ else {
+ fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
+ f_msk = MAX_B_FRAMES;
+ }
+
+ /* transparent mode */
+ if (trans_max) {
+ z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
+ z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
+ z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
+ z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
+ /* now determine bytes in actual FIFO buffer */
+ count = z1 - z2;
+ if (count <= 0)
+ count += fifo_size; /* count now contains buffered bytes */
+ count++;
+ if (count > trans_max)
+ count = trans_max; /* limit length */
+ if ((skb = dev_alloc_skb(count))) {
+ dst = skb_put(skb, count);
+ while (count--)
+ *dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
+ return(skb);
+ }
+ else return(NULL); /* no memory */
+ }
+
+ do {
+ f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
+ f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
+
+ if (f1 == f2) return(NULL); /* no frame available */
+
+ z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
+ z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
+ z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
+ z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
+
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_read_fifo %d f1(%x) f2(%x) z1(f2)(%x) z2(f2)(%x)",
+ fifo, f1, f2, z1, z2);
+ /* now determine bytes in actual FIFO buffer */
+ count = z1 - z2;
+ if (count <= 0)
+ count += fifo_size; /* count now contains buffered bytes */
+ count++;
+
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_read_fifo %d count %ld)",
+ fifo, count);
+
+ if ((count > fifo_size) || (count < 4)) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfcsx_read_fifo %d paket inv. len %d ", fifo , count);
+ while (count) {
+ count--; /* empty fifo */
+ Read_hfc(cs, HFCSX_FIF_DRD);
+ }
+ skb = NULL;
+ } else
+ if ((skb = dev_alloc_skb(count - 3))) {
+ count -= 3;
+ dst = skb_put(skb, count);
+
+ while (count--)
+ *dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
+
+ Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */
+ Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */
+ if (Read_hfc(cs, HFCSX_FIF_DRD)) {
+ dev_kfree_skb(skb);
+ if (cs->debug & L1_DEB_ISAC_FIFO)
+ debugl1(cs, "hfcsx_read_fifo %d crc error", fifo);
+ skb = NULL;
+ }
+ } else {
+ printk(KERN_WARNING "HFC-SX: receive out of memory\n");
+ return(NULL);
+ }
+
+ Read_hfc(cs, HFCSX_FIF_INCF2); /* increment F2 */
+ udelay(1);
+ while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+ udelay(1);
+ } while (!skb); /* retry in case of crc error */
+ return(skb);
+}
+
+/******************************************/
+/* free hardware resources used by driver */
+/******************************************/
+void
+release_io_hfcsx(struct IsdnCardState *cs)
+{
+ int flags;
+
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */
+ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+ restore_flags(flags);
+ Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */
+ sti();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
+ Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */
+ del_timer(&cs->hw.hfcsx.timer);
+ release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */
+ kfree(cs->hw.hfcsx.extra);
+ cs->hw.hfcsx.extra = NULL;
+}
+
+/**********************************************************/
+/* set_fifo_size determines the size of the RAM and FIFOs */
+/* returning 0 -> need to reset the chip again. */
+/**********************************************************/
+static int set_fifo_size(struct IsdnCardState *cs)
+{
+
+ if (cs->hw.hfcsx.b_fifo_size) return(1); /* already determined */
+
+ if ((cs->hw.hfcsx.chip >> 4) == 9) {
+ cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_32K;
+ return(1);
+ }
+
+ cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_8K;
+ cs->hw.hfcsx.cirm |= 0x10; /* only 8K of ram */
+ return(0);
+
+}
+
+/********************************************************************************/
+/* function called to reset the HFC SX chip. A complete software reset of chip */
+/* and fifos is done. */
+/********************************************************************************/
+static void
+reset_hfcsx(struct IsdnCardState *cs)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */
+ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+
+ printk(KERN_INFO "HFC_SX: resetting card\n");
+ while (1) {
+ Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */
+ sti();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
+ Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+ if (Read_hfc(cs, HFCSX_STATUS) & 2)
+ printk(KERN_WARNING "HFC-SX init bit busy\n");
+ cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */
+ if (!set_fifo_size(cs)) continue;
+ break;
+ }
+
+ cs->hw.hfcsx.trm = 0 + HFCSX_BTRANS_THRESMASK; /* no echo connect , threshold */
+ Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
+
+ Write_hfc(cs, HFCSX_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */
+ cs->hw.hfcsx.sctrl_e = HFCSX_AUTO_AWAKE;
+ Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); /* S/T Auto awake */
+ cs->hw.hfcsx.bswapped = 0; /* no exchange */
+ cs->hw.hfcsx.nt_mode = 0; /* we are in TE mode */
+ cs->hw.hfcsx.ctmt = HFCSX_TIM3_125 | HFCSX_AUTO_TIMER;
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
+
+ cs->hw.hfcsx.int_m1 = HFCSX_INTS_DTRANS | HFCSX_INTS_DREC |
+ HFCSX_INTS_L1STATE | HFCSX_INTS_TIMER;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+
+ /* Clear already pending ints */
+ if (Read_hfc(cs, HFCSX_INT_S1));
+
+ Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */
+ udelay(10);
+ Write_hfc(cs, HFCSX_STATES, 2); /* HFC ST 2 */
+ cs->hw.hfcsx.mst_m = HFCSX_MASTER; /* HFC Master Mode */
+
+ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+ cs->hw.hfcsx.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
+ Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
+ cs->hw.hfcsx.sctrl_r = 0;
+ Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.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.hfcsx.conn = 0x36; /* set data flow directions */
+ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+ Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */
+ Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */
+ Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */
+ Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */
+
+ /* Finally enable IRQ output */
+ cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE;
+ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+ if (Read_hfc(cs, HFCSX_INT_S2));
+ restore_flags(flags);
+}
+
+/***************************************************/
+/* Timer function called when kernel timer expires */
+/***************************************************/
+static void
+hfcsx_Timer(struct IsdnCardState *cs)
+{
+ cs->hw.hfcsx.timer.expires = jiffies + 75;
+ /* WD RESET */
+/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcsx.ctmt | 0x80);
+ add_timer(&cs->hw.hfcsx.timer);
+ */
+}
+
+
+/*********************************/
+/* schedule a new D-channel task */
+/*********************************/
+static void
+sched_event_D_sx(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
+hfcsx_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);
+}
+
+/*******************************/
+/* D-channel receive procedure */
+/*******************************/
+static
+int
+receive_dmsg(struct IsdnCardState *cs)
+{
+ struct sk_buff *skb;
+ int count = 5;
+
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ debugl1(cs, "rec_dmsg blocked");
+ return (1);
+ }
+
+ do {
+ skb = read_fifo(cs, HFCSX_SEL_D_RX, 0);
+ if (skb) {
+ skb_queue_tail(&cs->rq, skb);
+ sched_event_D_sx(cs, D_RCVBUFREADY);
+ }
+ } while (--count && skb);
+
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ return (1);
+}
+
+/**********************************/
+/* B-channel main receive routine */
+/**********************************/
+void
+main_rec_hfcsx(struct BCState *bcs)
+{
+ long flags;
+ struct IsdnCardState *cs = bcs->cs;
+ int count = 5;
+ struct sk_buff *skb;
+
+ save_flags(flags);
+
+ 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();
+ skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ?
+ HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX,
+ (bcs->mode == L1_MODE_TRANS) ?
+ HFCSX_BTRANS_THRESHOLD : 0);
+
+ if (skb) {
+ cli();
+ skb_queue_tail(&bcs->rqueue, skb);
+ sti();
+ hfcsx_sched_event(bcs, B_RCVBUFREADY);
+ }
+
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ if (count && skb)
+ goto Begin;
+ restore_flags(flags);
+ return;
+}
+
+/**************************/
+/* D-channel send routine */
+/**************************/
+static void
+hfcsx_fill_dfifo(struct IsdnCardState *cs)
+{
+ if (!cs->tx_skb)
+ return;
+ if (cs->tx_skb->len <= 0)
+ return;
+
+ if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) {
+ dev_kfree_skb(cs->tx_skb);
+ cs->tx_skb = NULL;
+ }
+ return;
+}
+
+/**************************/
+/* B-channel send routine */
+/**************************/
+static void
+hfcsx_fill_fifo(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int flags;
+
+ if (!bcs->tx_skb)
+ return;
+ if (bcs->tx_skb->len <= 0)
+ return;
+
+ save_flags(flags);
+ sti();
+
+ if (write_fifo(cs, bcs->tx_skb,
+ ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ?
+ HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX,
+ (bcs->mode == L1_MODE_TRANS) ?
+ HFCSX_BTRANS_THRESHOLD : 0)) {
+
+ 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);
+ dev_kfree_skb(bcs->tx_skb);
+ bcs->tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+
+ cli();
+ restore_flags(flags);
+ return;
+}
+
+/**********************************************/
+/* D-channel l1 state call for leased NT-mode */
+/**********************************************/
+static void
+dch_nt_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+
+ switch (pr) {
+ case (PH_DATA | REQUEST):
+ case (PH_PULL | REQUEST):
+ case (PH_PULL | INDICATION):
+ st->l1.l1hw(st, pr, arg);
+ break;
+ case (PH_ACTIVATE | REQUEST):
+ st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+ break;
+ case (PH_TESTLOOP | REQUEST):
+ if (1 & (long) arg)
+ debugl1(cs, "PH_TEST_LOOP B1");
+ if (2 & (long) arg)
+ debugl1(cs, "PH_TEST_LOOP B2");
+ if (!(3 & (long) arg))
+ debugl1(cs, "PH_TEST_LOOP DISABLED");
+ st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
+ break;
+ default:
+ if (cs->debug)
+ debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr);
+ break;
+ }
+}
+
+
+
+/***********************/
+/* set/reset echo mode */
+/***********************/
+static int
+hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
+{
+ int flags;
+ int i = *(unsigned int *) ic->parm.num;
+
+ if ((ic->arg == 98) &&
+ (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) {
+ save_flags(flags);
+ cli();
+ Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0); /* HFC ST G0 */
+ udelay(10);
+ cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT;
+ Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); /* set NT-mode */
+ udelay(10);
+ Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 1); /* HFC ST G1 */
+ udelay(10);
+ Write_hfc(cs, HFCSX_STATES, 1 | HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+ cs->dc.hfcsx.ph_state = 1;
+ cs->hw.hfcsx.nt_mode = 1;
+ cs->hw.hfcsx.nt_timer = 0;
+ cs->stlist->l2.l2l1 = dch_nt_l2l1;
+ restore_flags(flags);
+ debugl1(cs, "NT mode activated");
+ return (0);
+ }
+ if ((cs->chanlimit > 1) || (cs->hw.hfcsx.bswapped) ||
+ (cs->hw.hfcsx.nt_mode) || (ic->arg != 12))
+ return (-EINVAL);
+
+ save_flags(flags);
+ cli();
+ if (i) {
+ cs->logecho = 1;
+ cs->hw.hfcsx.trm |= 0x20; /* enable echo chan */
+ cs->hw.hfcsx.int_m1 |= HFCSX_INTS_B2REC;
+ /* reset Channel !!!!! */
+ } else {
+ cs->logecho = 0;
+ cs->hw.hfcsx.trm &= ~0x20; /* disable echo chan */
+ cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_B2REC;
+ }
+ cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA;
+ cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
+ cs->hw.hfcsx.conn |= 0x10; /* B2-IOM -> B2-ST */
+ cs->hw.hfcsx.ctmt &= ~2;
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
+ Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
+ Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
+ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+ Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ restore_flags(flags);
+ return (0);
+} /* hfcsx_auxcmd */
+
+/*****************************/
+/* E-channel receive routine */
+/*****************************/
+static void
+receive_emsg(struct IsdnCardState *cs)
+{
+ int flags;
+ int count = 5;
+ u_char *ptr;
+ struct sk_buff *skb;
+
+
+ save_flags(flags);
+ cli();
+ if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ debugl1(cs, "echo_rec_data blocked");
+ restore_flags(flags);
+ return;
+ }
+ sti();
+
+ do {
+ skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0);
+ if (skb) {
+ if (cs->debug & DEB_DLOG_HEX) {
+ ptr = cs->dlog;
+ if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) {
+ *ptr++ = 'E';
+ *ptr++ = 'C';
+ *ptr++ = 'H';
+ *ptr++ = 'O';
+ *ptr++ = ':';
+ ptr += QuickHex(ptr, skb->data, skb->len);
+ ptr--;
+ *ptr++ = '\n';
+ *ptr = 0;
+ HiSax_putstatus(cs, NULL, cs->dlog);
+ } else
+ HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len);
+ }
+ dev_kfree_skb(skb);
+ }
+ } while (--count && skb);
+
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ restore_flags(flags);
+ return;
+} /* receive_emsg */
+
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static void
+hfcsx_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-SX: Spurious interrupt!\n");
+ return;
+ }
+ if (!(cs->hw.hfcsx.int_m2 & 0x08))
+ return; /* not initialised */
+
+ if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) {
+ val = Read_hfc(cs, HFCSX_INT_S1);
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val);
+ } else
+ return;
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFC-SX irq %x %s", val,
+ test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
+ "locked" : "unlocked");
+ val &= cs->hw.hfcsx.int_m1;
+ if (val & 0x40) { /* state machine irq */
+ exval = Read_hfc(cs, HFCSX_STATES) & 0xf;
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state,
+ exval);
+ cs->dc.hfcsx.ph_state = exval;
+ sched_event_D_sx(cs, D_L1STATECHANGE);
+ val &= ~0x40;
+ }
+ if (val & 0x80) { /* timer irq */
+ if (cs->hw.hfcsx.nt_mode) {
+ if ((--cs->hw.hfcsx.nt_timer) < 0)
+ sched_event_D_sx(cs, D_L1STATECHANGE);
+ }
+ val &= ~0x80;
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
+ }
+ while (val) {
+ save_flags(flags);
+ cli();
+ if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ cs->hw.hfcsx.int_s1 |= val;
+ restore_flags(flags);
+ return;
+ }
+ if (cs->hw.hfcsx.int_s1 & 0x18) {
+ exval = val;
+ val = cs->hw.hfcsx.int_s1;
+ cs->hw.hfcsx.int_s1 = exval;
+ }
+ if (val & 0x08) {
+ if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) {
+ if (cs->debug)
+ debugl1(cs, "hfcsx spurious 0x08 IRQ");
+ } else
+ main_rec_hfcsx(bcs);
+ }
+ if (val & 0x10) {
+ if (cs->logecho)
+ receive_emsg(cs);
+ else if (!(bcs = Sel_BCS(cs, 1))) {
+ if (cs->debug)
+ debugl1(cs, "hfcsx spurious 0x10 IRQ");
+ } else
+ main_rec_hfcsx(bcs);
+ }
+ if (val & 0x01) {
+ if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) {
+ if (cs->debug)
+ debugl1(cs, "hfcsx spurious 0x01 IRQ");
+ } else {
+ if (bcs->tx_skb) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_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)) {
+ hfcsx_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "fill_data %d blocked", bcs->channel);
+ } else {
+ hfcsx_sched_event(bcs, B_XMTBUFREADY);
+ }
+ }
+ }
+ }
+ if (val & 0x02) {
+ if (!(bcs = Sel_BCS(cs, 1))) {
+ if (cs->debug)
+ debugl1(cs, "hfcsx spurious 0x02 IRQ");
+ } else {
+ if (bcs->tx_skb) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_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)) {
+ hfcsx_fill_fifo(bcs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "fill_data %d blocked", bcs->channel);
+ } else {
+ hfcsx_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_sx(cs, D_CLEARBUSY);
+ if (cs->tx_skb) {
+ if (cs->tx_skb->len) {
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ debugl1(cs, "hfcsx_fill_dfifo irq blocked");
+ }
+ goto afterXPR;
+ } else {
+ dev_kfree_skb(cs->tx_skb);
+ cs->tx_cnt = 0;
+ cs->tx_skb = NULL;
+ }
+ }
+ if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+ cs->tx_cnt = 0;
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else {
+ debugl1(cs, "hfcsx_fill_dfifo irq blocked");
+ }
+ } else
+ sched_event_D_sx(cs, D_XMTBUFREADY);
+ }
+ afterXPR:
+ if (cs->hw.hfcsx.int_s1 && count--) {
+ val = cs->hw.hfcsx.int_s1;
+ cs->hw.hfcsx.int_s1 = 0;
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFC-SX 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
+hfcsx_dbusy_timer(struct IsdnCardState *cs)
+{
+}
+
+/*************************************/
+/* Layer 1 D-channel hardware access */
+/*************************************/
+static void
+HFCSX_l1hw(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+ struct sk_buff *skb = arg;
+ int flags;
+
+ 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)) {
+ hfcsx_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "hfcsx_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)) {
+ hfcsx_fill_dfifo(cs);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ } else
+ debugl1(cs, "hfcsx_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, HFCSX_STATES, HFCSX_LOAD_STATE | 3); /* HFC ST 3 */
+ udelay(6);
+ Write_hfc(cs, HFCSX_STATES, 3); /* HFC ST 2 */
+ cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
+ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+ Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+ l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+ break;
+ case (HW_ENABLE | REQUEST):
+ Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+ break;
+ case (HW_DEACTIVATE | REQUEST):
+ cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER;
+ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+ break;
+ case (HW_INFO3 | REQUEST):
+ cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
+ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+ break;
+ case (HW_TESTLOOP | REQUEST):
+ switch ((int) arg) {
+ case (1):
+ Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */
+ Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1;
+ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+ restore_flags(flags);
+ break;
+
+ case (2):
+ Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* tx slot */
+ Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* rx slot */
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08;
+ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+ restore_flags(flags);
+ break;
+
+ default:
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg);
+ return;
+ }
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */
+ Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
+ restore_flags(flags);
+ break;
+ default:
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfcsx_l1hw unknown pr %4x", pr);
+ break;
+ }
+}
+
+/***********************************************/
+/* called during init setting l1 stack pointer */
+/***********************************************/
+void
+setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs)
+{
+ st->l1.l1hw = HFCSX_l1hw;
+}
+
+/**************************************/
+/* send B-channel data if not blocked */
+/**************************************/
+static void
+hfcsx_send_data(struct BCState *bcs)
+{
+ struct IsdnCardState *cs = bcs->cs;
+
+ if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+ hfcsx_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_hfcsx(struct BCState *bcs, int mode, int bc)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ int flags, fifo2;
+
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HFCSX bchannel mode %d bchan %d/%d",
+ mode, bc, bcs->channel);
+ bcs->mode = mode;
+ bcs->channel = bc;
+ fifo2 = bc;
+ save_flags(flags);
+ cli();
+ if (cs->chanlimit > 1) {
+ cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
+ cs->hw.hfcsx.sctrl_e &= ~0x80;
+ } else {
+ if (bc) {
+ if (mode != L1_MODE_NULL) {
+ cs->hw.hfcsx.bswapped = 1; /* B1 and B2 exchanged */
+ cs->hw.hfcsx.sctrl_e |= 0x80;
+ } else {
+ cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
+ cs->hw.hfcsx.sctrl_e &= ~0x80;
+ }
+ fifo2 = 0;
+ } else {
+ cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */
+ cs->hw.hfcsx.sctrl_e &= ~0x80;
+ }
+ }
+ switch (mode) {
+ case (L1_MODE_NULL):
+ if (bc) {
+ cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
+ cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA;
+ } else {
+ cs->hw.hfcsx.sctrl &= ~SCTRL_B1_ENA;
+ cs->hw.hfcsx.sctrl_r &= ~SCTRL_B1_ENA;
+ }
+ if (fifo2) {
+ cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+ } else {
+ cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+ }
+ break;
+ case (L1_MODE_TRANS):
+ if (bc) {
+ cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
+ } else {
+ cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
+ }
+ if (fifo2) {
+ cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+ cs->hw.hfcsx.ctmt |= 2;
+ cs->hw.hfcsx.conn &= ~0x18;
+ } else {
+ cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+ cs->hw.hfcsx.ctmt |= 1;
+ cs->hw.hfcsx.conn &= ~0x03;
+ }
+ break;
+ case (L1_MODE_HDLC):
+ if (bc) {
+ cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
+ } else {
+ cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
+ }
+ if (fifo2) {
+ cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+ cs->hw.hfcsx.ctmt &= ~2;
+ cs->hw.hfcsx.conn &= ~0x18;
+ } else {
+ cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+ cs->hw.hfcsx.ctmt &= ~1;
+ cs->hw.hfcsx.conn &= ~0x03;
+ }
+ break;
+ case (L1_MODE_EXTRN):
+ if (bc) {
+ cs->hw.hfcsx.conn |= 0x10;
+ cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
+ cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+ } else {
+ cs->hw.hfcsx.conn |= 0x02;
+ cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
+ cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
+ cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+ }
+ break;
+ }
+ Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e);
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
+ Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
+ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+ if (mode != L1_MODE_EXTRN) {
+ reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX);
+ reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX);
+ }
+ restore_flags(flags);
+}
+
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+static void
+hfcsx_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_hfcsx(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_hfcsx(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_hfcsx(struct BCState *bcs)
+{
+ mode_hfcsx(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) {
+ dev_kfree_skb(bcs->tx_skb);
+ bcs->tx_skb = NULL;
+ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ }
+ }
+}
+
+/*************************************/
+/* init B-channel queues and control */
+/*************************************/
+static int
+open_hfcsxstate(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_hfcsxstate(st->l1.hardware, bcs))
+ return (-1);
+ st->l1.bcs = bcs;
+ st->l2.l2l1 = hfcsx_l2l1;
+ setstack_manager(st);
+ bcs->st = st;
+ setstack_l1_B(st);
+ return (0);
+}
+
+/***************************/
+/* handle L1 state changes */
+/***************************/
+static void
+hfcsx_bh(struct IsdnCardState *cs)
+{
+ int flags;
+/* struct PStack *stptr;
+ */
+ if (!cs)
+ return;
+ if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+ if (!cs->hw.hfcsx.nt_mode)
+ switch (cs->dc.hfcsx.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;
+ } else {
+ switch (cs->dc.hfcsx.ph_state) {
+ case (2):
+ save_flags(flags);
+ cli();
+ if (cs->hw.hfcsx.nt_timer < 0) {
+ cs->hw.hfcsx.nt_timer = 0;
+ cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ /* Clear already pending ints */
+ if (Read_hfc(cs, HFCSX_INT_S1));
+
+ Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE);
+ udelay(10);
+ Write_hfc(cs, HFCSX_STATES, 4);
+ cs->dc.hfcsx.ph_state = 4;
+ } else {
+ cs->hw.hfcsx.int_m1 |= HFCSX_INTS_TIMER;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ cs->hw.hfcsx.ctmt &= ~HFCSX_AUTO_TIMER;
+ cs->hw.hfcsx.ctmt |= HFCSX_TIM3_125;
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
+ Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
+ cs->hw.hfcsx.nt_timer = NT_T1_COUNT;
+ Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3); /* allow G2 -> G3 transition */
+ }
+ restore_flags(flags);
+ break;
+ case (1):
+ case (3):
+ case (4):
+ save_flags(flags);
+ cli();
+ cs->hw.hfcsx.nt_timer = 0;
+ cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ restore_flags(flags);
+ 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);
+}
+
+
+/********************************/
+/* called for card init message */
+/********************************/
+__initfunc(void
+ inithfcsx(struct IsdnCardState *cs))
+{
+ cs->setstack_d = setstack_hfcsx;
+ cs->dbusytimer.function = (void *) hfcsx_dbusy_timer;
+ cs->dbusytimer.data = (long) cs;
+ init_timer(&cs->dbusytimer);
+ cs->tqueue.routine = (void *) (void *) hfcsx_bh;
+ cs->BC_Send_Data = &hfcsx_send_data;
+ cs->bcs[0].BC_SetStack = setstack_2b;
+ cs->bcs[1].BC_SetStack = setstack_2b;
+ cs->bcs[0].BC_Close = close_hfcsx;
+ cs->bcs[1].BC_Close = close_hfcsx;
+ mode_hfcsx(cs->bcs, 0, 0);
+ mode_hfcsx(cs->bcs + 1, 0, 1);
+}
+
+
+
+/*******************************************/
+/* handle card messages from control layer */
+/*******************************************/
+static int
+hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ long flags;
+
+ if (cs->debug & L1_DEB_ISAC)
+ debugl1(cs, "HFCSX: card_msg %x", mt);
+ switch (mt) {
+ case CARD_RESET:
+ reset_hfcsx(cs);
+ return (0);
+ case CARD_RELEASE:
+ release_io_hfcsx(cs);
+ return (0);
+ case CARD_INIT:
+ inithfcsx(cs);
+ save_flags(flags);
+ sti();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */
+ /* now switch timer interrupt off */
+ cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ /* reinit mode reg */
+ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+ restore_flags(flags);
+ return (0);
+ case CARD_TEST:
+ return (0);
+ }
+ return (0);
+}
+
+
+
+__initfunc(int
+ setup_hfcsx(struct IsdnCard *card))
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ int flags;
+
+ strcpy(tmp, hfcsx_revision);
+ printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp));
+ cs->hw.hfcsx.base = card->para[1] & 0xfffe;
+ cs->irq = card->para[0];
+ cs->hw.hfcsx.int_s1 = 0;
+ cs->dc.hfcsx.ph_state = 0;
+ cs->hw.hfcsx.fifo = 255;
+ if (cs->typ == ISDN_CTYPE_HFC_SX) {
+ if ((!cs->hw.hfcsx.base) ||
+ check_region((cs->hw.hfcsx.base), 2)) {
+ printk(KERN_WARNING
+ "HiSax: HFC-SX io-base 0x%x already in use\n",
+ cs->hw.hfcsx.base);
+ return(0);
+ } else {
+ request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn");
+ }
+ byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF);
+ byteout(cs->hw.hfcsx.base + 1,
+ ((cs->hw.hfcsx.base >> 8) & 3) | 0x54);
+ udelay(10);
+ cs->hw.hfcsx.chip = Read_hfc(cs,HFCSX_CHIP_ID);
+ switch (cs->hw.hfcsx.chip >> 4) {
+ case 1:
+ tmp[0] ='+';
+ break;
+ case 9:
+ tmp[0] ='P';
+ break;
+ default:
+ printk(KERN_WARNING
+ "HFC-SX: invalid chip id 0x%x\n",
+ cs->hw.hfcsx.chip >> 4);
+ release_region(cs->hw.hfcsx.base, 2);
+ return(0);
+ }
+ if (!ccd_sp_irqtab[cs->irq & 0xF]) {
+ printk(KERN_WARNING
+ "HFC_SX: invalid irq %d specified\n",cs->irq & 0xF);
+ release_region(cs->hw.hfcsx.base, 2);
+ return(0);
+ }
+ save_flags(flags);
+ cli();
+ if (!(cs->hw.hfcsx.extra = (void *)
+ kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) {
+ restore_flags(flags);
+ release_region(cs->hw.hfcsx.base, 2);
+ printk(KERN_WARNING "HFC-SX: unable to allocate memory\n");
+ return(0);
+ }
+ restore_flags(flags);
+
+ printk(KERN_INFO
+ "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n",
+ tmp[0], (u_int) cs->hw.hfcsx.base,
+ cs->irq, HZ);
+ cs->hw.hfcsx.int_m2 = 0; /* disable alle interrupts */
+ cs->hw.hfcsx.int_m1 = 0;
+ Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+ } 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 = &hfcsx_interrupt;
+
+ cs->hw.hfcsx.timer.function = (void *) hfcsx_Timer;
+ cs->hw.hfcsx.timer.data = (long) cs;
+ cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */
+ cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */
+ init_timer(&cs->hw.hfcsx.timer);
+
+ reset_hfcsx(cs);
+ cs->cardmsg = &hfcsx_card_msg;
+ cs->auxcmd = &hfcsx_auxcmd;
+ return (1);
+}
+
+
+
+
diff --git a/drivers/isdn/hisax/hfc_sx.h b/drivers/isdn/hisax/hfc_sx.h
new file mode 100644
index 000000000..ebb8d3e7d
--- /dev/null
+++ b/drivers/isdn/hisax/hfc_sx.h
@@ -0,0 +1,216 @@
+/* $Id: hfc_sx.h,v 1.1 1999/11/18 00:09:18 werner Exp $
+
+ * specific defines for CCD's HFC 2BDS0 S+,SP 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_sx.h,v $
+ * Revision 1.1 1999/11/18 00:09:18 werner
+ *
+ * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM.
+ * Audio and Echo are supported.
+ *
+ *
+ *
+ */
+
+/*********************************************/
+/* thresholds for transparent B-channel mode */
+/* change mask and threshold simultaneously */
+/*********************************************/
+#define HFCSX_BTRANS_THRESHOLD 128
+#define HFCSX_BTRANS_THRESMASK 0x00
+
+/* GCI/IOM bus monitor registers */
+
+#define HFCSX_C_I 0x02
+#define HFCSX_TRxR 0x03
+#define HFCSX_MON1_D 0x0A
+#define HFCSX_MON2_D 0x0B
+
+
+/* GCI/IOM bus timeslot registers */
+
+#define HFCSX_B1_SSL 0x20
+#define HFCSX_B2_SSL 0x21
+#define HFCSX_AUX1_SSL 0x22
+#define HFCSX_AUX2_SSL 0x23
+#define HFCSX_B1_RSL 0x24
+#define HFCSX_B2_RSL 0x25
+#define HFCSX_AUX1_RSL 0x26
+#define HFCSX_AUX2_RSL 0x27
+
+/* GCI/IOM bus data registers */
+
+#define HFCSX_B1_D 0x28
+#define HFCSX_B2_D 0x29
+#define HFCSX_AUX1_D 0x2A
+#define HFCSX_AUX2_D 0x2B
+
+/* GCI/IOM bus configuration registers */
+
+#define HFCSX_MST_EMOD 0x2D
+#define HFCSX_MST_MODE 0x2E
+#define HFCSX_CONNECT 0x2F
+
+
+/* Interrupt and status registers */
+
+#define HFCSX_TRM 0x12
+#define HFCSX_B_MODE 0x13
+#define HFCSX_CHIP_ID 0x16
+#define HFCSX_CIRM 0x18
+#define HFCSX_CTMT 0x19
+#define HFCSX_INT_M1 0x1A
+#define HFCSX_INT_M2 0x1B
+#define HFCSX_INT_S1 0x1E
+#define HFCSX_INT_S2 0x1F
+#define HFCSX_STATUS 0x1C
+
+/* S/T section registers */
+
+#define HFCSX_STATES 0x30
+#define HFCSX_SCTRL 0x31
+#define HFCSX_SCTRL_E 0x32
+#define HFCSX_SCTRL_R 0x33
+#define HFCSX_SQ 0x34
+#define HFCSX_CLKDEL 0x37
+#define HFCSX_B1_REC 0x3C
+#define HFCSX_B1_SEND 0x3C
+#define HFCSX_B2_REC 0x3D
+#define HFCSX_B2_SEND 0x3D
+#define HFCSX_D_REC 0x3E
+#define HFCSX_D_SEND 0x3E
+#define HFCSX_E_REC 0x3F
+
+/****************/
+/* FIFO section */
+/****************/
+#define HFCSX_FIF_SEL 0x10
+#define HFCSX_FIF_Z1L 0x80
+#define HFCSX_FIF_Z1H 0x84
+#define HFCSX_FIF_Z2L 0x88
+#define HFCSX_FIF_Z2H 0x8C
+#define HFCSX_FIF_INCF1 0xA8
+#define HFCSX_FIF_DWR 0xAC
+#define HFCSX_FIF_F1 0xB0
+#define HFCSX_FIF_F2 0xB4
+#define HFCSX_FIF_INCF2 0xB8
+#define HFCSX_FIF_DRD 0xBC
+
+/* bits in status register (READ) */
+#define HFCSX_SX_PROC 0x02
+#define HFCSX_NBUSY 0x04
+#define HFCSX_TIMER_ELAP 0x10
+#define HFCSX_STATINT 0x20
+#define HFCSX_FRAMEINT 0x40
+#define HFCSX_ANYINT 0x80
+
+/* bits in CTMT (Write) */
+#define HFCSX_CLTIMER 0x80
+#define HFCSX_TIM3_125 0x04
+#define HFCSX_TIM25 0x10
+#define HFCSX_TIM50 0x14
+#define HFCSX_TIM400 0x18
+#define HFCSX_TIM800 0x1C
+#define HFCSX_AUTO_TIMER 0x20
+#define HFCSX_TRANSB2 0x02
+#define HFCSX_TRANSB1 0x01
+
+/* bits in CIRM (Write) */
+#define HFCSX_IRQ_SELMSK 0x07
+#define HFCSX_IRQ_SELDIS 0x00
+#define HFCSX_RESET 0x08
+#define HFCSX_FIFO_RESET 0x80
+
+
+/* bits in INT_M1 and INT_S1 */
+#define HFCSX_INTS_B1TRANS 0x01
+#define HFCSX_INTS_B2TRANS 0x02
+#define HFCSX_INTS_DTRANS 0x04
+#define HFCSX_INTS_B1REC 0x08
+#define HFCSX_INTS_B2REC 0x10
+#define HFCSX_INTS_DREC 0x20
+#define HFCSX_INTS_L1STATE 0x40
+#define HFCSX_INTS_TIMER 0x80
+
+/* bits in INT_M2 */
+#define HFCSX_PROC_TRANS 0x01
+#define HFCSX_GCI_I_CHG 0x02
+#define HFCSX_GCI_MON_REC 0x04
+#define HFCSX_IRQ_ENABLE 0x08
+
+/* bits in STATES */
+#define HFCSX_STATE_MSK 0x0F
+#define HFCSX_LOAD_STATE 0x10
+#define HFCSX_ACTIVATE 0x20
+#define HFCSX_DO_ACTION 0x40
+#define HFCSX_NT_G2_G3 0x80
+
+/* bits in HFCD_MST_MODE */
+#define HFCSX_MASTER 0x01
+#define HFCSX_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 HFCSX_AUTO_AWAKE 0x01
+#define HFCSX_DBIT_1 0x04
+#define HFCSX_IGNORE_COL 0x08
+#define HFCSX_CHG_B1_B2 0x80
+
+/**********************************/
+/* definitions for FIFO selection */
+/**********************************/
+#define HFCSX_SEL_D_RX 5
+#define HFCSX_SEL_D_TX 4
+#define HFCSX_SEL_B1_RX 1
+#define HFCSX_SEL_B1_TX 0
+#define HFCSX_SEL_B2_RX 3
+#define HFCSX_SEL_B2_TX 2
+
+#define MAX_D_FRAMES 15
+#define MAX_B_FRAMES 31
+#define B_SUB_VAL_32K 0x0200
+#define B_FIFO_SIZE_32K (0x2000 - B_SUB_VAL_32K)
+#define B_SUB_VAL_8K 0x1A00
+#define B_FIFO_SIZE_8K (0x2000 - B_SUB_VAL_8K)
+#define D_FIFO_SIZE 512
+#define D_FREG_MASK 0xF
+
+/************************************************************/
+/* structure holding additional dynamic data -> send marker */
+/************************************************************/
+struct hfcsx_extra {
+ unsigned short marker[2*(MAX_B_FRAMES+1) + (MAX_D_FRAMES+1)];
+};
+
+extern void main_irq_hfcsx(struct BCState *bcs);
+extern void inithfcsx(struct IsdnCardState *cs);
+extern void releasehfcsx(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
index 8654857fd..7015f4bb5 100644
--- a/drivers/isdn/hisax/hfcscard.c
+++ b/drivers/isdn/hisax/hfcscard.c
@@ -1,4 +1,4 @@
-/* $Id: hfcscard.c,v 1.5 1999/09/04 06:20:06 keil Exp $
+/* $Id: hfcscard.c,v 1.6 1999/12/19 13:09:42 keil Exp $
* hfcscard.c low level stuff for hfcs based cards (Teles3c, ACER P10)
*
@@ -6,6 +6,10 @@
*
*
* $Log: hfcscard.c,v $
+ * Revision 1.6 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.5 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -30,7 +34,7 @@
extern const char *CardType[];
-static const char *hfcs_revision = "$Revision: 1.5 $";
+static const char *hfcs_revision = "$Revision: 1.6 $";
static void
hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
@@ -85,13 +89,13 @@ reset_hfcs(struct IsdnCardState *cs)
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
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 */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
if (cs->typ == ISDN_CTYPE_TELES3C)
cs->hw.hfcD.cirm |= HFCD_INTB;
@@ -138,7 +142,7 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
init2bds0(cs);
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((80*HZ)/1000);
cs->hw.hfcD.ctmt |= HFCD_TIM800;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 0c67d5c4a..6f5b5615c 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1,8 +1,16 @@
-/* $Id: hisax.h,v 2.38 1999/11/14 23:37:03 keil Exp $
+/* $Id: hisax.h,v 2.40 2000/01/20 19:51:46 keil Exp $
* Basic declarations, defines and prototypes
*
* $Log: hisax.h,v $
+ * Revision 2.40 2000/01/20 19:51:46 keil
+ * Fix AddTimer message
+ * Change CONFIG defines
+ *
+ * Revision 2.39 1999/11/18 00:00:43 werner
+ *
+ * Added support for HFC-S+ and HFC-SP cards
+ *
* Revision 2.38 1999/11/14 23:37:03 keil
* new ISA memory mapped IO
*
@@ -784,6 +792,31 @@ struct hfcPCI_hw {
struct timer_list timer;
};
+struct hfcSX_hw {
+ unsigned int base;
+ 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 bswapped;
+ unsigned char nt_mode;
+ unsigned char chip;
+ int b_fifo_size;
+ unsigned char last_fifo;
+ void *extra;
+ int nt_timer;
+ struct timer_list timer;
+};
+
struct hfcD_hw {
unsigned int addr;
unsigned int bfifosize;
@@ -894,6 +927,10 @@ struct hfcpci_chip {
int ph_state;
};
+struct hfcsx_chip {
+ int ph_state;
+};
+
struct w6692_chip {
int ph_state;
};
@@ -934,6 +971,7 @@ struct IsdnCardState {
struct njet_hw njet;
struct hfcD_hw hfcD;
struct hfcPCI_hw hfcpci;
+ struct hfcSX_hw hfcsx;
struct ix1_hw niccy;
struct isurf_hw isurf;
struct saphir_hw saphir;
@@ -973,6 +1011,7 @@ struct IsdnCardState {
struct isac_chip isac;
struct hfcd_chip hfcd;
struct hfcpci_chip hfcpci;
+ struct hfcsx_chip hfcsx;
struct w6692_chip w6692;
} dc;
u_char *rcvbuf;
@@ -1032,7 +1071,8 @@ struct IsdnCardState {
#define ISDN_CTYPE_GAZEL 34
#define ISDN_CTYPE_HFC_PCI 35
#define ISDN_CTYPE_W6692 36
-#define ISDN_CTYPE_COUNT 36
+#define ISDN_CTYPE_HFC_SX 37
+#define ISDN_CTYPE_COUNT 37
#ifdef ISDN_CHIP_ISAC
@@ -1201,6 +1241,12 @@ struct IsdnCardState {
#define CARD_HFC_PCI 0
#endif
+#ifdef CONFIG_HISAX_HFC_SX
+#define CARD_HFC_SX 1
+#else
+#define CARD_HFC_SX 0
+#endif
+
#ifdef CONFIG_HISAX_AMD7930
#define CARD_AMD7930 1
#else
@@ -1298,19 +1344,6 @@ struct IsdnCardState {
#ifdef CONFIG_HISAX_EURO
#undef TEI_PER_CARD
#define TEI_PER_CARD 1
-#define HISAX_EURO_SENDCOMPLETE 1
-#define EXT_BEARER_CAPS 1
-#define HISAX_SEND_STD_LLC_IE 1
-#ifdef CONFIG_HISAX_NO_SENDCOMPLETE
-#undef HISAX_EURO_SENDCOMPLETE
-#endif
-#ifdef CONFIG_HISAX_NO_LLC
-#undef HISAX_SEND_STD_LLC_IE
-#endif
-#undef HISAX_DE_AOC
-#ifdef CONFIG_DE_AOC
-#define HISAX_DE_AOC 1
-#endif
#endif
/* L1 Debug */
diff --git a/drivers/isdn/hisax/hscx.h b/drivers/isdn/hisax/hscx.h
index 08801bc73..00b566a44 100644
--- a/drivers/isdn/hisax/hscx.h
+++ b/drivers/isdn/hisax/hscx.h
@@ -1,11 +1,14 @@
-/* $Id: hscx.h,v 1.4 1998/04/15 16:45:34 keil Exp $
+/* $Id: hscx.h,v 1.5 1999/12/23 15:09:32 keil Exp $
* hscx.h HSCX specific defines
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: hscx.h,v $
+ * Revision 1.5 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.4 1998/04/15 16:45:34 keil
* new init code
*
diff --git a/drivers/isdn/hisax/ipac.h b/drivers/isdn/hisax/ipac.h
index 82c5fa8f8..34a85dd6b 100644
--- a/drivers/isdn/hisax/ipac.h
+++ b/drivers/isdn/hisax/ipac.h
@@ -1,11 +1,14 @@
-/* $Id: ipac.h,v 1.3 1998/04/15 16:48:09 keil Exp $
+/* $Id: ipac.h,v 1.4 1999/12/23 15:09:32 keil Exp $
* ipac.h IPAC specific defines
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: ipac.h,v $
+ * Revision 1.4 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.3 1998/04/15 16:48:09 keil
* IPAC_ATX added
*
diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h
index bed887d4f..a8a46e135 100644
--- a/drivers/isdn/hisax/isac.h
+++ b/drivers/isdn/hisax/isac.h
@@ -1,11 +1,14 @@
-/* $Id: isac.h,v 1.5 1998/05/25 12:58:03 keil Exp $
+/* $Id: isac.h,v 1.6 1999/12/23 15:09:32 keil Exp $
* isac.h ISAC specific defines
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: isac.h,v $
+ * Revision 1.6 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 1.5 1998/05/25 12:58:03 keil
* HiSax golden code from certification, Don't use !!!
* No leased lines, no X75, but many changes.
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index 417f2157d..bfff86707 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.7 1999/10/14 20:25:29 keil Exp $
+/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $
* isar.c ISAR (Siemens PSB 7110) specific routines
*
@@ -6,6 +6,12 @@
*
*
* $Log: isar.c,v $
+ * Revision 1.9 2000/01/20 19:47:45 keil
+ * Add Fax Class 1 support
+ *
+ * Revision 1.8 1999/12/19 13:00:56 keil
+ * Fix races in setting a new mode
+ *
* Revision 1.7 1999/10/14 20:25:29 keil
* add a statistic for error monitoring
*
@@ -42,7 +48,17 @@
#define MIN(a,b) ((a<b)?a:b)
+#define DLE 0x10
+#define ETX 0x03
+
+
+const u_char faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146";
+const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
+#define FAXMODCNT 13
+
void isar_setup(struct IsdnCardState *cs);
+static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
+static inline void ll_deliver_faxstat(struct BCState *bcs, u_char status);
static inline int
waitforHIA(struct IsdnCardState *cs, int timeout)
@@ -432,6 +448,12 @@ static void
isar_bh(struct BCState *bcs)
{
BChannel_bh(bcs);
+ if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event))
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR);
+ if (test_and_clear_bit(B_LL_CONNECT, &bcs->event))
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+ if (test_and_clear_bit(B_LL_OK, &bcs->event))
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK);
}
static void
@@ -443,6 +465,42 @@ isar_sched_event(struct BCState *bcs, int event)
}
static inline void
+send_DLE_ETX(struct BCState *bcs)
+{
+ u_char dleetx[2] = {DLE,ETX};
+ struct sk_buff *skb;
+
+ if ((skb = dev_alloc_skb(2))) {
+ memcpy(skb_put(skb, 2), dleetx, 2);
+ skb_queue_tail(&bcs->rqueue, skb);
+ isar_sched_event(bcs, B_RCVBUFREADY);
+ } else {
+ printk(KERN_WARNING "HiSax: skb out of memory\n");
+ }
+}
+
+static inline int
+dle_count(unsigned char *buf, int len)
+{
+ int count = 0;
+
+ while (len--)
+ if (*buf++ == DLE)
+ count++;
+ return count;
+}
+
+static inline void
+insert_dle(unsigned char *dest, unsigned char *src, int count) {
+ /* <DLE> in input stream have to be flagged as <DLE><DLE> */
+ while (count--) {
+ *dest++ = *src;
+ if (*src++ == DLE)
+ *dest++ = DLE;
+ }
+}
+
+static inline void
isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
{
u_char *ptr;
@@ -512,6 +570,88 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
}
}
break;
+ case L1_MODE_FAX:
+ if (bcs->hw.isar.state != STFAX_ACTIV) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: not ACTIV");
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
+ break;
+ }
+ if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
+ rcv_mbox(cs, ireg, bcs->hw.isar.rcvbuf);
+ bcs->hw.isar.rcvidx = ireg->clsb +
+ dle_count(bcs->hw.isar.rcvbuf, ireg->clsb);
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)",
+ ireg->clsb, bcs->hw.isar.rcvidx);
+ if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
+ insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx),
+ bcs->hw.isar.rcvbuf, ireg->clsb);
+ skb_queue_tail(&bcs->rqueue, skb);
+ isar_sched_event(bcs, B_RCVBUFREADY);
+ if (ireg->cmsb & SART_NMD) { /* ABORT */
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: no more data");
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
+ send_DLE_ETX(bcs);
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
+ ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
+ 0, NULL);
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ isar_sched_event(bcs, B_LL_NOCARRIER);
+ }
+ } else {
+ printk(KERN_WARNING "HiSax: skb out of memory\n");
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ }
+ break;
+ }
+ if (bcs->hw.isar.cmd != PCTRL_CMD_FRH) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: unknown fax mode %x",
+ bcs->hw.isar.cmd);
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
+ break;
+ }
+ /* PCTRL_CMD_FRH */
+ if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: incoming packet too large");
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
+ } else if (ireg->cmsb & HDLC_ERROR) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar frame error %x len %d",
+ ireg->cmsb, ireg->clsb);
+ bcs->hw.isar.rcvidx = 0;
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ } else {
+ if (ireg->cmsb & HDLC_FSD)
+ bcs->hw.isar.rcvidx = 0;
+ ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
+ bcs->hw.isar.rcvidx += ireg->clsb;
+ rcv_mbox(cs, ireg, ptr);
+ if (ireg->cmsb & HDLC_FED) {
+ if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
+ printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n",
+ bcs->hw.isar.rcvidx);
+ } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
+ printk(KERN_WARNING "ISAR: receive out of memory\n");
+ } else {
+ memcpy(skb_put(skb, bcs->hw.isar.rcvidx),
+ bcs->hw.isar.rcvbuf,
+ bcs->hw.isar.rcvidx);
+ skb_queue_tail(&bcs->rqueue, skb);
+ isar_sched_event(bcs, B_RCVBUFREADY);
+ send_DLE_ETX(bcs);
+ isar_sched_event(bcs, B_LL_OK);
+ }
+ }
+ }
+ break;
default:
printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode);
cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
@@ -544,38 +684,57 @@ isar_fill_fifo(struct BCState *bcs)
count = bcs->tx_skb->len;
msb = HDLC_FED;
}
- if (!bcs->hw.isar.txcnt)
- msb |= HDLC_FST;
save_flags(flags);
cli();
ptr = bcs->tx_skb->data;
+ if (!bcs->hw.isar.txcnt) {
+ msb |= HDLC_FST;
+ if ((bcs->mode == L1_MODE_FAX) &&
+ (bcs->hw.isar.cmd == PCTRL_CMD_FTH)) {
+ if (bcs->tx_skb->len > 1) {
+ if ((ptr[0]== 0xff) && (ptr[1] == 0x13))
+ /* last frame */
+ test_and_set_bit(BC_FLG_LASTDATA,
+ &bcs->Flag);
+ }
+ }
+ }
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.isar.txcnt += count;
switch (bcs->mode) {
- case L1_MODE_NULL:
- 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)
- debugl1(cs, "isar bin data send dp%d failed",
- bcs->hw.isar.dpath);
- }
- break;
- case L1_MODE_HDLC:
- if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
- msb, count, ptr)) {
+ case L1_MODE_NULL:
+ printk(KERN_ERR"isar_fill_fifo wrong mode 0\n");
+ break;
+ case L1_MODE_TRANS:
+ case L1_MODE_V32:
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+ 0, count, ptr);
+ break;
+ case L1_MODE_HDLC:
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+ msb, count, ptr);
+ break;
+ case L1_MODE_FAX:
+ if (bcs->hw.isar.state != STFAX_ACTIV) {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_fill_fifo: not ACTIV");
+ } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+ msb, count, ptr);
+ } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) {
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+ 0, count, ptr);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_fill_fifo: not FTH/FTM");
+ }
+ break;
+ default:
if (cs->debug)
- debugl1(cs, "isar hdlc data send dp%d failed",
- bcs->hw.isar.dpath);
- }
- break;
- default:
- printk(KERN_ERR"isar_fill_fifo mode (%x)error\n", bcs->mode);
- break;
+ debugl1(cs, "isar_fill_fifo mode(%x) error", bcs->mode);
+ printk(KERN_ERR"isar_fill_fifo mode(%x) error\n", bcs->mode);
+ break;
}
restore_flags(flags);
}
@@ -603,6 +762,18 @@ 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);
+ if (bcs->mode == L1_MODE_FAX) {
+ if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
+ if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
+ test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag);
+ }
+ } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) {
+ if (test_bit(BC_FLG_DLEETX, &bcs->Flag)) {
+ test_and_set_bit(BC_FLG_LASTDATA, &bcs->Flag);
+ test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag);
+ }
+ }
+ }
dev_kfree_skb(bcs->tx_skb);
bcs->hw.isar.txcnt = 0;
bcs->tx_skb = NULL;
@@ -613,6 +784,18 @@ send_frames(struct BCState *bcs)
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
isar_fill_fifo(bcs);
} else {
+ if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) {
+ if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
+ if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) {
+ u_char dummy = 0;
+ sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) |
+ ISAR_HIS_SDATA, 0x01, 1, &dummy);
+ }
+ test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag);
+ } else {
+ isar_sched_event(bcs, B_LL_CONNECT);
+ }
+ }
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
isar_sched_event(bcs, B_XMTBUFREADY);
}
@@ -639,6 +822,7 @@ 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"};
@@ -700,7 +884,7 @@ isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) {
}
static void
-isar_pump_status_ev(struct BCState *bcs, u_char devt) {
+isar_pump_statev_modem(struct BCState *bcs, u_char devt) {
struct IsdnCardState *cs = bcs->cs;
u_char dps = SET_DPS(bcs->hw.isar.dpath);
@@ -769,6 +953,192 @@ isar_pump_status_ev(struct BCState *bcs, u_char devt) {
}
}
+static inline void
+ll_deliver_faxstat(struct BCState *bcs, u_char status)
+{
+ isdn_ctrl ic;
+ struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata;
+
+ if (bcs->cs->debug & L1_DEB_HSCX)
+ debugl1(bcs->cs, "HL->LL FAXIND %x", status);
+ ic.driver = bcs->cs->myid;
+ ic.command = ISDN_STAT_FAXIND;
+ ic.arg = chanp->chan;
+ ic.parm.aux.cmd = status;
+ bcs->cs->iif.statcallb(&ic);
+}
+
+static void
+isar_pump_statev_fax(struct BCState *bcs, u_char devt) {
+ struct IsdnCardState *cs = bcs->cs;
+ u_char dps = SET_DPS(bcs->hw.isar.dpath);
+ u_char p1;
+
+ switch(devt) {
+ case PSEV_10MS_TIMER:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev TIMER");
+ break;
+ case PSEV_RSP_READY:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_READY");
+ bcs->hw.isar.state = STFAX_READY;
+ l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL);
+ if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
+ isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FRH, 3);
+ } else {
+ isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FTH, 3);
+ }
+ break;
+ case PSEV_LINE_TX_H:
+ if (bcs->hw.isar.state == STFAX_LINE) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev LINE_TX_H");
+ bcs->hw.isar.state = STFAX_CONT;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "pump stev LINE_TX_H wrong st %x",
+ bcs->hw.isar.state);
+ }
+ break;
+ case PSEV_LINE_RX_H:
+ if (bcs->hw.isar.state == STFAX_LINE) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev LINE_RX_H");
+ bcs->hw.isar.state = STFAX_CONT;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "pump stev LINE_RX_H wrong st %x",
+ bcs->hw.isar.state);
+ }
+ break;
+ case PSEV_LINE_TX_B:
+ if (bcs->hw.isar.state == STFAX_LINE) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev LINE_TX_B");
+ bcs->hw.isar.state = STFAX_CONT;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "pump stev LINE_TX_B wrong st %x",
+ bcs->hw.isar.state);
+ }
+ break;
+ case PSEV_LINE_RX_B:
+ if (bcs->hw.isar.state == STFAX_LINE) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev LINE_RX_B");
+ bcs->hw.isar.state = STFAX_CONT;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "pump stev LINE_RX_B wrong st %x",
+ bcs->hw.isar.state);
+ }
+ break;
+ case PSEV_RSP_CONN:
+ if (bcs->hw.isar.state == STFAX_CONT) {
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_CONN");
+ bcs->hw.isar.state = STFAX_ACTIV;
+ test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags);
+ sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
+ /* 1s Flags before data */
+ if (test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag))
+ del_timer(&bcs->hw.isar.ftimer);
+ /* 1000 ms */
+ bcs->hw.isar.ftimer.expires =
+ jiffies + ((1000 * HZ)/1000);
+ test_and_set_bit(BC_FLG_LL_CONN,
+ &bcs->Flag);
+ add_timer(&bcs->hw.isar.ftimer);
+ } else {
+ isar_sched_event(bcs, B_LL_CONNECT);
+ }
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "pump stev RSP_CONN wrong st %x",
+ bcs->hw.isar.state);
+ }
+ break;
+ case PSEV_FLAGS_DET:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev FLAGS_DET");
+ break;
+ case PSEV_RSP_DISC:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_DISC");
+ if (bcs->hw.isar.state == STFAX_ESCAPE) {
+ switch(bcs->hw.isar.newcmd) {
+ case PCTRL_CMD_FTH:
+ case PCTRL_CMD_FTM:
+ p1 = 10;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_SILON, 1, &p1);
+ bcs->hw.isar.state = STFAX_SILDET;
+ break;
+ case PCTRL_CMD_FRH:
+ case PCTRL_CMD_FRM:
+ p1 = bcs->hw.isar.newmod;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
+ bcs->hw.isar.newcmd = 0;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+ bcs->hw.isar.cmd, 1, &p1);
+ bcs->hw.isar.state = STFAX_LINE;
+ break;
+ default:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "RSP_DISC unknown newcmd %x", bcs->hw.isar.newcmd);
+ break;
+ }
+ } else if (bcs->hw.isar.state == STFAX_ACTIV) {
+ if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) {
+ isar_sched_event(bcs, B_LL_OK);
+ } else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
+ send_DLE_ETX(bcs);
+ isar_sched_event(bcs, B_LL_NOCARRIER);
+ } else {
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
+ }
+ bcs->hw.isar.state = STFAX_READY;
+ } else {
+ bcs->hw.isar.state = STFAX_READY;
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
+ }
+ break;
+ case PSEV_RSP_SILDET:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_SILDET");
+ if (bcs->hw.isar.state == STFAX_SILDET) {
+ p1 = bcs->hw.isar.newmod;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
+ bcs->hw.isar.newcmd = 0;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+ bcs->hw.isar.cmd, 1, &p1);
+ bcs->hw.isar.state = STFAX_LINE;
+ }
+ break;
+ case PSEV_RSP_SILOFF:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_SILOFF");
+ break;
+ case PSEV_RSP_FCERR:
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_FCERR");
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
+ break;
+ default:
+ break;
+ }
+}
+
static char debbuf[128];
void
@@ -788,8 +1158,6 @@ isar_int_main(struct IsdnCardState *cs)
} else {
debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x",
ireg->iis, ireg->cmsb, ireg->clsb);
- printk(KERN_WARNING"isar spurious IIS_RDATA %x/%x/%x\n",
- ireg->iis, ireg->cmsb, ireg->clsb);
cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
}
break;
@@ -815,12 +1183,18 @@ isar_int_main(struct IsdnCardState *cs)
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);
+ if (bcs->mode == L1_MODE_V32) {
+ isar_pump_statev_modem(bcs, ireg->cmsb);
+ } else if (bcs->mode == L1_MODE_FAX) {
+ isar_pump_statev_fax(bcs, ireg->cmsb);
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar IIS_PSTEV pmode %d stat %x",
+ bcs->mode, 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;
@@ -831,8 +1205,6 @@ isar_int_main(struct IsdnCardState *cs)
} 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;
@@ -867,6 +1239,17 @@ isar_int_main(struct IsdnCardState *cs)
}
static void
+ftimer_handler(struct BCState *bcs) {
+ if (bcs->cs->debug)
+ debugl1(bcs->cs, "ftimer flags %04x",
+ bcs->Flag);
+ test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag);
+ if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
+ isar_sched_event(bcs, B_LL_CONNECT);
+ }
+}
+
+static void
setup_pump(struct BCState *bcs) {
struct IsdnCardState *cs = bcs->cs;
u_char dps = SET_DPS(bcs->hw.isar.dpath);
@@ -876,11 +1259,7 @@ setup_pump(struct BCState *bcs) {
case L1_MODE_NULL:
case L1_MODE_TRANS:
case L1_MODE_HDLC:
- if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL)) {
- if (cs->debug)
- debugl1(cs, "isar pump bypass cfg dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL);
break;
case L1_MODE_V32:
ctrl = PMOD_DATAMODEM;
@@ -896,11 +1275,7 @@ setup_pump(struct BCState *bcs) {
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);
- }
+ sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param);
break;
case L1_MODE_FAX:
ctrl = PMOD_FAX;
@@ -911,18 +1286,16 @@ setup_pump(struct BCState *bcs) {
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);
- }
+ sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
+ bcs->hw.isar.state = STFAX_NULL;
+ bcs->hw.isar.newcmd = 0;
+ bcs->hw.isar.newmod = 0;
+ test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag);
break;
}
- if (!sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL)) {
- if (cs->debug)
- debugl1(cs, "isar pump status req dp%d failed",
- bcs->hw.isar.dpath);
- }
+ udelay(1000);
+ sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ udelay(1000);
}
static void
@@ -933,44 +1306,30 @@ setup_sart(struct BCState *bcs) {
switch (bcs->mode) {
case L1_MODE_NULL:
- if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, NULL)) {
- if (cs->debug)
- debugl1(cs, "isar sart disable dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0,
+ NULL);
break;
case L1_MODE_TRANS:
- if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, "\0\0")) {
- if (cs->debug)
- debugl1(cs, "isar sart binary dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2,
+ "\0\0");
break;
case L1_MODE_HDLC:
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 hdlc dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1,
+ param);
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);
- }
+ sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2,
+ param);
break;
}
- if (!sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL)) {
- if (cs->debug)
- debugl1(cs, "isar buf stat req dp%d failed",
- bcs->hw.isar.dpath);
- }
+ udelay(1000);
+ sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
+ udelay(1000);
}
static void
@@ -995,15 +1354,10 @@ setup_iom2(struct BCState *bcs) {
cmsb |= IOM_CTRL_ALAW | IOM_CTRL_RCV;
break;
}
- if (!sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg)) {
- if (cs->debug)
- debugl1(cs, "isar iom2 dp%d failed", bcs->hw.isar.dpath);
- }
- if (!sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL)) {
- if (cs->debug)
- debugl1(cs, "isar IOM2 cfg req dp%d failed",
- bcs->hw.isar.dpath);
- }
+ sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg);
+ udelay(1000);
+ sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL);
+ udelay(1000);
}
int
@@ -1041,8 +1395,8 @@ modeisar(struct BCState *bcs, int mode, int bc)
&bcs->hw.isar.reg->Flags))
bcs->hw.isar.dpath = 1;
else {
- printk(KERN_WARNING"isar modeisar analog works only with DP1\n");
- debugl1(cs, "isar modeisar analog works only with DP1");
+ printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
+ debugl1(cs, "isar modeisar analog funktions only with DP1");
return(1);
}
break;
@@ -1066,6 +1420,107 @@ modeisar(struct BCState *bcs, int mode, int bc)
return(0);
}
+static void
+isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para)
+{
+ struct IsdnCardState *cs = bcs->cs;
+ u_char dps = SET_DPS(bcs->hw.isar.dpath);
+ u_char ctrl = 0, nom = 0, p1 = 0;
+
+ switch(cmd) {
+ case ISDN_FAX_CLASS1_FTM:
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FTM;
+ nom = 1;
+ bcs->hw.isar.state = STFAX_LINE;
+ bcs->hw.isar.cmd = ctrl;
+ bcs->hw.isar.mod = para;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.newcmd = 0;
+ } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+ (bcs->hw.isar.cmd == PCTRL_CMD_FTM) &&
+ (bcs->hw.isar.mod == para)) {
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+ } else {
+ bcs->hw.isar.newmod = para;
+ bcs->hw.isar.newcmd = PCTRL_CMD_FTM;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ }
+ break;
+ case ISDN_FAX_CLASS1_FTH:
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FTH;
+ nom = 1;
+ bcs->hw.isar.state = STFAX_LINE;
+ bcs->hw.isar.cmd = ctrl;
+ bcs->hw.isar.mod = para;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.newcmd = 0;
+ } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+ (bcs->hw.isar.cmd == PCTRL_CMD_FTH) &&
+ (bcs->hw.isar.mod == para)) {
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+ } else {
+ bcs->hw.isar.newmod = para;
+ bcs->hw.isar.newcmd = PCTRL_CMD_FTH;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ }
+ break;
+ case ISDN_FAX_CLASS1_FRM:
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FRM;
+ nom = 1;
+ bcs->hw.isar.state = STFAX_LINE;
+ bcs->hw.isar.cmd = ctrl;
+ bcs->hw.isar.mod = para;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.newcmd = 0;
+ } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+ (bcs->hw.isar.cmd == PCTRL_CMD_FRM) &&
+ (bcs->hw.isar.mod == para)) {
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+ } else {
+ bcs->hw.isar.newmod = para;
+ bcs->hw.isar.newcmd = PCTRL_CMD_FRM;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ }
+ break;
+ case ISDN_FAX_CLASS1_FRH:
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FRH;
+ nom = 1;
+ bcs->hw.isar.state = STFAX_LINE;
+ bcs->hw.isar.cmd = ctrl;
+ bcs->hw.isar.mod = para;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.newcmd = 0;
+ } else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+ (bcs->hw.isar.cmd == PCTRL_CMD_FRH) &&
+ (bcs->hw.isar.mod == para)) {
+ ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+ } else {
+ bcs->hw.isar.newmod = para;
+ bcs->hw.isar.newcmd = PCTRL_CMD_FRH;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ }
+ break;
+ }
+ if (ctrl)
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
+}
+
void
isar_setup(struct IsdnCardState *cs)
{
@@ -1076,11 +1531,8 @@ isar_setup(struct IsdnCardState *cs)
msg = 61;
for (i=0; i<2; i++) {
/* Buffer Config */
- if (!sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
- ISAR_HIS_P12CFG, 4, 1, &msg)) {
- if (cs->debug)
- debugl1(cs, "isar P%dCFG failed", i+1);
- }
+ sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
+ ISAR_HIS_P12CFG, 4, 1, &msg);
cs->bcs[i].hw.isar.mml = msg;
cs->bcs[i].mode = 0;
cs->bcs[i].hw.isar.dpath = i + 1;
@@ -1147,6 +1599,7 @@ isar_l2l1(struct PStack *st, int pr, void *arg)
l1_msg_b(st, PH_ACTIVATE | REQUEST, arg);
break;
case L1_MODE_V32:
+ case L1_MODE_FAX:
if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc))
l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
break;
@@ -1185,6 +1638,7 @@ close_isarstate(struct BCState *bcs)
debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY");
}
}
+ del_timer(&bcs->hw.isar.ftimer);
}
int
@@ -1206,6 +1660,9 @@ open_isarstate(struct IsdnCardState *cs, struct BCState *bcs)
bcs->event = 0;
bcs->hw.isar.rcvidx = 0;
bcs->tx_cnt = 0;
+ bcs->hw.isar.ftimer.function = (void *) ftimer_handler;
+ bcs->hw.isar.ftimer.data = (long) bcs;
+ init_timer(&bcs->hw.isar.ftimer);
return (0);
}
@@ -1226,15 +1683,66 @@ setstack_isar(struct PStack *st, struct BCState *bcs)
int
isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
u_long adr;
- int features;
+ int features, i;
+ struct BCState *bcs;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg);
switch (ic->command) {
+ case (ISDN_CMD_FAXCMD):
+ bcs = cs->channel[ic->arg].bcs;
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "isar_auxcmd cmd/subcmd %d/%d",
+ ic->parm.aux.cmd, ic->parm.aux.subcmd);
+ switch(ic->parm.aux.cmd) {
+ case ISDN_FAX_CLASS1_CTRL:
+ if (ic->parm.aux.subcmd == ETX)
+ test_and_set_bit(BC_FLG_DLEETX,
+ &bcs->Flag);
+ break;
+ case ISDN_FAX_CLASS1_FRM:
+ case ISDN_FAX_CLASS1_FRH:
+ case ISDN_FAX_CLASS1_FTM:
+ case ISDN_FAX_CLASS1_FTH:
+ if (ic->parm.aux.subcmd == AT_QUERY) {
+ sprintf(ic->parm.aux.para,
+ "%d", bcs->hw.isar.mod);
+ ic->command = ISDN_STAT_FAXIND;
+ ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+ cs->iif.statcallb(ic);
+ return(0);
+ } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
+ strcpy(ic->parm.aux.para, faxmodulation_s);
+ ic->command = ISDN_STAT_FAXIND;
+ ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+ cs->iif.statcallb(ic);
+ return(0);
+ } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+ for(i=0;i<FAXMODCNT;i++)
+ if (faxmodulation[i]==ic->parm.aux.para[0])
+ break;
+ if ((FAXMODCNT > i) &&
+ test_bit(BC_FLG_INIT, &bcs->Flag)) {
+ isar_pump_cmd(bcs,
+ ic->parm.aux.cmd,
+ ic->parm.aux.para[0]);
+ return(0);
+ }
+ }
+ /* wrong modulation or not activ */
+ /* fall through */
+ default:
+ ic->command = ISDN_STAT_FAXIND;
+ ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
+ cs->iif.statcallb(ic);
+ }
+ break;
case (ISDN_CMD_IOCTL):
switch (ic->arg) {
case (9): /* load firmware */
- features = ISDN_FEATURE_L2_MODEM;
+ features = ISDN_FEATURE_L2_MODEM |
+ ISDN_FEATURE_L2_FAX |
+ ISDN_FEATURE_L3_FCLASS1;
memcpy(&adr, ic->parm.num, sizeof(ulong));
if (isar_load_firmware(cs, (u_char *)adr))
return(1);
diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h
index f2bc4820a..ec3bff89e 100644
--- a/drivers/isdn/hisax/isar.h
+++ b/drivers/isdn/hisax/isar.h
@@ -1,10 +1,13 @@
-/* $Id: isar.h,v 1.6 1999/10/14 20:25:29 keil Exp $
+/* $Id: isar.h,v 1.7 2000/01/20 19:47:45 keil Exp $
* isar.h ISAR (Siemens PSB 7110) specific defines
*
* Author Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: isar.h,v $
+ * Revision 1.7 2000/01/20 19:47:45 keil
+ * Add Fax Class 1 support
+ *
* Revision 1.6 1999/10/14 20:25:29 keil
* add a statistic for error monitoring
*
@@ -145,6 +148,28 @@
#define PSEV_REM_REN 0xcd
#define PSEV_GSTN_CLR 0xd4
+#define PSEV_RSP_READY 0xbc
+#define PSEV_LINE_TX_H 0xb3
+#define PSEV_LINE_TX_B 0xb2
+#define PSEV_LINE_RX_H 0xb1
+#define PSEV_LINE_RX_B 0xb0
+#define PSEV_RSP_CONN 0xb5
+#define PSEV_RSP_DISC 0xb7
+#define PSEV_RSP_FCERR 0xb9
+#define PSEV_RSP_SILDET 0xbe
+#define PSEV_RSP_SILOFF 0xab
+#define PSEV_FLAGS_DET 0xba
+
+#define PCTRL_CMD_FTH 0xa7
+#define PCTRL_CMD_FRH 0xa5
+#define PCTRL_CMD_FTM 0xa8
+#define PCTRL_CMD_FRM 0xa6
+#define PCTRL_CMD_SILON 0xac
+#define PCTRL_CMD_CONT 0xa2
+#define PCTRL_CMD_ESC 0xa4
+#define PCTRL_CMD_SILOFF 0xab
+#define PCTRL_CMD_HALT 0xa9
+
#define PCTRL_LOC_RET 0xcf
#define PCTRL_LOC_REN 0xce
@@ -193,6 +218,15 @@
#define BSTEV_TBO 0x1f
#define BSTEV_RBO 0x2f
+/* FAX State Machine */
+#define STFAX_NULL 0
+#define STFAX_READY 1
+#define STFAX_LINE 2
+#define STFAX_CONT 3
+#define STFAX_ACTIV 4
+#define STFAX_ESCAPE 5
+#define STFAX_SILDET 6
+
extern int ISARVersion(struct IsdnCardState *cs, char *s);
extern void isar_int_main(struct IsdnCardState *cs);
extern void initisar(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index 768217025..7715991cb 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 2.36 1999/08/25 16:50:57 keil Exp $
+/* $Id: isdnl1.c,v 2.37 2000/01/20 19:51:46 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,10 @@
*
*
* $Log: isdnl1.c,v $
+ * Revision 2.37 2000/01/20 19:51:46 keil
+ * Fix AddTimer message
+ * Change CONFIG defines
+ *
* Revision 2.36 1999/08/25 16:50:57 keil
* Fix bugs which cause 2.3.14 hangs (waitqueue init)
*
@@ -138,7 +142,7 @@
*
*/
-const char *l1_revision = "$Revision: 2.36 $";
+const char *l1_revision = "$Revision: 2.37 $";
#define __NO_VERSION__
#include "hisax.h"
@@ -362,7 +366,8 @@ DChannel_proc_rcv(struct IsdnCardState *cs)
stptr = stptr->next;
if (!found)
dev_kfree_skb(skb);
- }
+ } else
+ dev_kfree_skb(skb);
}
}
@@ -559,11 +564,8 @@ l1_deact_req(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_F3);
-// if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) {
- FsmDelTimer(&st->l1.timer, 1);
- FsmAddTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
- test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
-// }
+ FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
+ test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
}
static void
@@ -574,8 +576,7 @@ l1_power_up(struct FsmInst *fi, int event, void *arg)
if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) {
FsmChangeState(fi, ST_L1_F4);
st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
- FsmDelTimer(&st->l1.timer, 1);
- FsmAddTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+ FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
} else
FsmChangeState(fi, ST_L1_F3);
@@ -614,7 +615,7 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg)
if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) {
if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags))
FsmDelTimer(&st->l1.timer, 3);
- FsmAddTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
+ FsmRestartTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
}
}
@@ -729,7 +730,7 @@ l1b_activate(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_WAIT_ACT);
- FsmAddTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2);
+ FsmRestartTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2);
}
static void
@@ -738,7 +739,7 @@ l1b_deactivate(struct FsmInst *fi, int event, void *arg)
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_WAIT_DEACT);
- FsmAddTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2);
+ FsmRestartTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2);
}
static void
diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
index 4ee5831fe..18a7cfc58 100644
--- a/drivers/isdn/hisax/isurf.c
+++ b/drivers/isdn/hisax/isurf.c
@@ -1,10 +1,14 @@
-/* $Id: isurf.c,v 1.7 1999/11/14 23:37:03 keil Exp $
+/* $Id: isurf.c,v 1.8 1999/12/19 13:09:42 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.8 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.7 1999/11/14 23:37:03 keil
* new ISA memory mapped IO
*
@@ -40,7 +44,7 @@
extern const char *CardType[];
-static const char *ISurf_revision = "$Revision: 1.7 $";
+static const char *ISurf_revision = "$Revision: 1.8 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -162,10 +166,10 @@ reset_isurf(struct IsdnCardState *cs, u_char chips)
byteout(cs->hw.isurf.reset, chips); /* Reset On */
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
index 31b25acdf..e6297bd94 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.9 1999/07/01 08:11:55 keil Exp $
+/* $Id: l3_1tr6.c,v 2.10 2000/01/20 19:42:01 keil Exp $
* German 1TR6 D-channel protocol
*
@@ -10,6 +10,9 @@
*
*
* $Log: l3_1tr6.c,v $
+ * Revision 2.10 2000/01/20 19:42:01 keil
+ * Fixed uninitialiesed location
+ *
* Revision 2.9 1999/07/01 08:11:55 keil
* Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
*
@@ -59,7 +62,7 @@
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.9 $";
+const char *l3_1tr6_revision = "$Revision: 2.10 $";
#define MsgHead(ptr, cref, mty, dis) \
*ptr++ = dis; \
@@ -699,6 +702,7 @@ 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->para.loc = 0;
pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
release_l3_process(pc);
}
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 035ee54ca..9fa10e326 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.20 1999/10/11 22:16:27 keil Exp $
+/* $Id: l3dss1.c,v 2.22 2000/01/20 19:44:20 keil Exp $
* EURO/DSS1 D-channel protocol
*
@@ -13,6 +13,16 @@
* Fritz Elfert
*
* $Log: l3dss1.c,v $
+ * Revision 2.22 2000/01/20 19:44:20 keil
+ * Fixed uninitialiesed location
+ * Fixed redirecting number IE in Setup
+ * Changes from certification
+ * option for disabling use of KEYPAD protocol
+ *
+ * Revision 2.21 1999/12/19 20:25:17 keil
+ * fixed LLC for outgoing analog calls
+ * IE Signal is valid on older local switches
+ *
* Revision 2.20 1999/10/11 22:16:27 keil
* Suspend/Resume is possible without explicit ID too
*
@@ -91,9 +101,10 @@
#include "isdnl3.h"
#include "l3dss1.h"
#include <linux/ctype.h>
+#include <linux/config.h>
extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.20 $";
+const char *dss1_revision = "$Revision: 2.22 $";
#define EXT_BEARER_CAPS 1
@@ -668,34 +679,36 @@ l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
}
static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
+ IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC,
+ IE_USER_USER, -1};
static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_CONNECT_PN,
- IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
-static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, -1};
+ IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL,
+ IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
+static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
- IE_PROGRESS, IE_DISPLAY, IE_USER_USER, -1};
-static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD,
+ IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
+static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
IE_CALLED_PN, -1};
static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
-static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, IE_USER_USER, -1};
+static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
+ IE_SIGNAL, IE_USER_USER, -1};
/* a RELEASE_COMPLETE with errors don't require special actions
-static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_USER_USER, -1};
+static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
*/
static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY,
IE_DISPLAY, -1};
static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY,
IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
- IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_CALLING_PN,
- IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_LLC, IE_HLC,
- IE_USER_USER, -1};
+ IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
+ IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
+ IE_LLC, IE_HLC, IE_USER_USER, -1};
static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
- IE_PROGRESS, IE_DISPLAY, -1};
+ IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
IE_MANDATORY, IE_DISPLAY, -1};
static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
@@ -1272,6 +1285,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;
@@ -1283,14 +1297,18 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
MsgHead(p, pc->callref, MT_SETUP);
teln = pc->para.setup.phone;
+#ifndef CONFIG_HISAX_NO_KEYPAD
send_keypad = (strchr(teln,'*') || strchr(teln,'#')) ? 1 : 0;
+#else
+ send_keypad = 0;
+#endif
+#ifndef CONFIG_HISAX_NO_SENDCOMPLETE
+ if (!send_keypad)
+ *p++ = 0xa1; /* complete indicator */
+#endif
/*
* Set Bearer Capability, Map info from 1TR6-convention to EDSS1
*/
-#if HISAX_EURO_SENDCOMPLETE
- if (!send_keypad)
- *p++ = 0xa1; /* complete indicator */
-#endif
if (!send_keypad)
switch (pc->para.setup.si1) {
case 1: /* Telephony */
@@ -1452,12 +1470,25 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
*p++ = 0x90;
*p++ = 0x21;
p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
-#if HISAX_SEND_STD_LLC_IE
+#ifndef CONFIG_HISAX_NO_LLC
} else {
- *p++ = 0x7c;
- *p++ = 0x02;
- *p++ = 0x88;
- *p++ = 0x90;
+ switch (pc->para.setup.si1) {
+ case 1: /* Telephony */
+ *p++ = 0x7c; /* BC-IE-code */
+ *p++ = 0x3; /* Length */
+ *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ *p++ = 0xa3; /* A-Law Audio */
+ break;
+ case 5: /* Datatransmission 64k, BTX */
+ case 7: /* Datatransmission 64k */
+ default:
+ *p++ = 0x7c; /* BC-IE-code */
+ *p++ = 0x2; /* Length */
+ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ break;
+ }
#endif
}
#endif
@@ -2738,6 +2769,7 @@ static void
l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
{
pc->para.cause = 0x29; /* Temporary failure */
+ pc->para.loc = 0;
l3dss1_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
}
@@ -2747,6 +2779,7 @@ l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg)
{
newl3state(pc, 0);
pc->para.cause = 0x1b; /* Destination out of order */
+ pc->para.loc = 0;
pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
release_l3_process(pc);
}
diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h
index 268b5376f..2acb95c01 100644
--- a/drivers/isdn/hisax/l3dss1.h
+++ b/drivers/isdn/hisax/l3dss1.h
@@ -1,8 +1,11 @@
-/* $Id: l3dss1.h,v 1.7 1999/07/01 08:12:02 keil Exp $
+/* $Id: l3dss1.h,v 1.8 2000/01/20 19:46:15 keil Exp $
*
* DSS1 (Euro) D-channel protocol defines
*
* $Log: l3dss1.h,v $
+ * Revision 1.8 2000/01/20 19:46:15 keil
+ * Changes from certification
+ *
* Revision 1.7 1999/07/01 08:12:02 keil
* Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
*
@@ -35,6 +38,8 @@
#define T304 30000
#define T305 30000
#define T308 4000
+/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
+/* This makes some tests easier and quicker */
#define T309 40000
#define T310 30000
#define T313 4000
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 3b502f7db..3855625bd 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -1,4 +1,4 @@
-/* $Id: netjet.c,v 1.16 1999/10/14 20:25:29 keil Exp $
+/* $Id: netjet.c,v 1.17 1999/12/19 13:09:42 keil Exp $
* netjet.c low level stuff for Traverse Technologie NETJet ISDN cards
*
@@ -7,6 +7,10 @@
* Thanks to Traverse Technologie Australia for documents and informations
*
* $Log: netjet.c,v $
+ * Revision 1.17 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.16 1999/10/14 20:25:29 keil
* add a statistic for error monitoring
*
@@ -81,7 +85,7 @@
extern const char *CardType[];
-const char *NETjet_revision = "$Revision: 1.16 $";
+const char *NETjet_revision = "$Revision: 1.17 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -1054,11 +1058,11 @@ reset_netjet(struct IsdnCardState *cs)
sti();
cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
restore_flags(flags);
cs->hw.njet.auxd = 0;
diff --git a/drivers/isdn/hisax/rawhdlc.c b/drivers/isdn/hisax/rawhdlc.c
index 17ac5c602..5a8b0591e 100644
--- a/drivers/isdn/hisax/rawhdlc.c
+++ b/drivers/isdn/hisax/rawhdlc.c
@@ -1,8 +1,8 @@
-/* $Id: rawhdlc.c,v 1.3 1998/06/17 19:51:21 he Exp $
+/* $Id: rawhdlc.c,v 1.4 1999/12/23 15:09:32 keil Exp $
* rawhdlc.c support routines for cards that don't support HDLC
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
* Brent Baccala <baccala@FreeSoft.org>
*
*
diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
index 955a9a4de..b642d759c 100644
--- a/drivers/isdn/hisax/saphir.c
+++ b/drivers/isdn/hisax/saphir.c
@@ -1,4 +1,4 @@
-/* $Id: saphir.c,v 1.4 1999/09/04 06:20:06 keil Exp $
+/* $Id: saphir.c,v 1.5 1999/12/19 13:09:42 keil Exp $
* saphir.c low level stuff for HST Saphir 1
*
@@ -8,6 +8,10 @@
*
*
* $Log: saphir.c,v $
+ * Revision 1.5 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.4 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -29,7 +33,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-static char *saphir_rev = "$Revision: 1.4 $";
+static char *saphir_rev = "$Revision: 1.5 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -237,10 +241,10 @@ saphir_reset(struct IsdnCardState *cs)
save_flags(flags);
sti();
byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000); /* Timeout 30ms */
byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000); /* Timeout 30ms */
restore_flags(flags);
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index b93895ea1..dd1c53d04 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -1,4 +1,4 @@
-/* $Id: sedlbauer.c,v 1.18 1999/11/13 21:25:03 keil Exp $
+/* $Id: sedlbauer.c,v 1.20 2000/01/20 19:47:45 keil Exp $
* sedlbauer.c low level stuff for Sedlbauer cards
* includes support for the Sedlbauer speed star (speed star II),
@@ -17,6 +17,13 @@
* Edgar Toernig
*
* $Log: sedlbauer.c,v $
+ * Revision 1.20 2000/01/20 19:47:45 keil
+ * Add Fax Class 1 support
+ *
+ * Revision 1.19 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.18 1999/11/13 21:25:03 keil
* Support for Speedfax+ PCI
*
@@ -110,7 +117,7 @@
extern const char *CardType[];
-const char *Sedlbauer_revision = "$Revision: 1.18 $";
+const char *Sedlbauer_revision = "$Revision: 1.20 $";
const char *Sedlbauer_Types[] =
{"None", "speed card/win", "speed star", "speed fax+",
@@ -490,10 +497,10 @@ reset_sedlbauer(struct IsdnCardState *cs)
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20);
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
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);
@@ -506,20 +513,20 @@ reset_sedlbauer(struct IsdnCardState *cs)
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
save_flags(flags);
sti();
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((20*HZ)/1000);
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((20*HZ)/1000);
restore_flags(flags);
} else {
byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
@@ -659,15 +666,13 @@ setup_sedlbauer(struct IsdnCard *card))
(sub_id == PCI_SUB_ID_SPEEDFAXP)) {
cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
cs->subtyp = SEDL_SPEEDFAX_PCI;
- cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_PCI_ISAR_RESET_ON;
- cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
- SEDL_ISAR_PCI_ISAR_RESET_OFF;
} else {
cs->hw.sedl.chip = SEDL_CHIP_IPAC;
cs->subtyp = SEDL_SPEED_PCI;
}
bytecnt = 256;
+ cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+ cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
byteout(cs->hw.sedl.cfg_reg, 0xff);
byteout(cs->hw.sedl.cfg_reg, 0x00);
byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
@@ -675,7 +680,7 @@ setup_sedlbauer(struct IsdnCard *card))
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
save_flags(flags);
sti();
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((10*HZ)/1000);
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
restore_flags(flags);
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
index 91a6a6ae1..03ecedb93 100644
--- a/drivers/isdn/hisax/sportster.c
+++ b/drivers/isdn/hisax/sportster.c
@@ -1,12 +1,19 @@
-/* $Id: sportster.c,v 1.10 1999/09/04 06:20:06 keil Exp $
+/* $Id: sportster.c,v 1.12 1999/12/23 15:09:32 keil Exp $
* sportster.c low level stuff for USR Sportster internal TA
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
* Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
*
* $Log: sportster.c,v $
+ * Revision 1.12 1999/12/23 15:09:32 keil
+ * change email
+ *
+ * Revision 1.11 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.10 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -46,7 +53,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *sportster_revision = "$Revision: 1.10 $";
+const char *sportster_revision = "$Revision: 1.12 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -180,11 +187,11 @@ reset_sportster(struct IsdnCardState *cs)
byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
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);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
index c34dc5613..bbf59316d 100644
--- a/drivers/isdn/hisax/teleint.c
+++ b/drivers/isdn/hisax/teleint.c
@@ -1,4 +1,4 @@
-/* $Id: teleint.c,v 1.11 1999/09/04 06:20:06 keil Exp $
+/* $Id: teleint.c,v 1.12 1999/12/19 13:09:42 keil Exp $
* teleint.c low level stuff for TeleInt isdn cards
*
@@ -6,6 +6,10 @@
*
*
* $Log: teleint.c,v $
+ * Revision 1.12 1999/12/19 13:09:42 keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
* Revision 1.11 1999/09/04 06:20:06 keil
* Changes from kernel set_current_state()
*
@@ -51,7 +55,7 @@
extern const char *CardType[];
-const char *TeleInt_revision = "$Revision: 1.11 $";
+const char *TeleInt_revision = "$Revision: 1.12 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -260,11 +264,11 @@ reset_TeleInt(struct IsdnCardState *cs)
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */
save_flags(flags);
sti();
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000);
cs->hw.hfc.cirm &= ~HFC_RESET;
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
index 8e8017bbb..c3a4a05eb 100644
--- a/drivers/isdn/hisax/teles0.c
+++ b/drivers/isdn/hisax/teles0.c
@@ -1,15 +1,18 @@
-/* $Id: teles0.c,v 2.10 1999/11/14 23:37:03 keil Exp $
+/* $Id: teles0.c,v 2.11 1999/12/23 15:09:32 keil Exp $
* teles0.c low level stuff for Teles Memory IO isdn cards
* based on the teles driver from Jan den Ouden
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
* Thanks to Jan den Ouden
* Fritz Elfert
* Beat Doebeli
*
* $Log: teles0.c,v $
+ * Revision 2.11 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 2.10 1999/11/14 23:37:03 keil
* new ISA memory mapped IO
*
@@ -61,7 +64,7 @@
extern const char *CardType[];
-const char *teles0_revision = "$Revision: 2.10 $";
+const char *teles0_revision = "$Revision: 2.11 $";
#define TELES_IOMEM_SIZE 0x400
#define byteout(addr,val) outb(val,addr)
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
index 0db245abc..171aeb07d 100644
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -1,16 +1,22 @@
-/* $Id: teles3.c,v 2.13 1999/08/30 12:01:28 keil Exp $
+/* $Id: teles3.c,v 2.15 2000/02/03 16:40:10 keil Exp $
* teles3.c low level stuff for Teles 16.3 & PNP isdn cards
*
* based on the teles driver from Jan den Ouden
*
- * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author Karsten Keil (keil@isdn4linux.de)
*
* Thanks to Jan den Ouden
* Fritz Elfert
* Beat Doebeli
*
* $Log: teles3.c,v $
+ * Revision 2.15 2000/02/03 16:40:10 keil
+ * Fix teles pcmcia
+ *
+ * Revision 2.14 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 2.13 1999/08/30 12:01:28 keil
* HW version v1.3 support
*
@@ -88,7 +94,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *teles3_revision = "$Revision: 2.13 $";
+const char *teles3_revision = "$Revision: 2.15 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -225,7 +231,7 @@ void
release_io_teles3(struct IsdnCardState *cs)
{
if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
- release_region(cs->hw.teles3.hscx[0], 97);
+ release_region(cs->hw.teles3.hscx[1], 96);
} else {
if (cs->hw.teles3.cfg_reg) {
if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
@@ -367,15 +373,15 @@ setup_teles3(struct IsdnCard *card))
cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
- if (check_region((cs->hw.teles3.hscx[0]), 97)) {
+ if (check_region((cs->hw.teles3.hscx[1]), 96 )) {
printk(KERN_WARNING
"HiSax: %s ports %x-%x already in use\n",
CardType[cs->typ],
- cs->hw.teles3.hscx[0],
- cs->hw.teles3.hscx[0] + 96);
+ cs->hw.teles3.hscx[1],
+ cs->hw.teles3.hscx[1] + 96);
return (0);
} else
- request_region(cs->hw.teles3.hscx[0], 97, "HiSax Teles PCMCIA");
+ request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA");
} else {
if (cs->hw.teles3.cfg_reg) {
if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index 3486b470a..e90510b35 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -1,12 +1,15 @@
-/* $Id: telespci.c,v 2.10 1999/11/15 14:20:05 keil Exp $
+/* $Id: telespci.c,v 2.11 1999/12/23 15:09:32 keil Exp $
* telespci.c low level stuff for Teles PCI isdn cards
*
* Author Ton van Rosmalen
- * Karsten Keil (keil@temic-ech.spacenet.de)
+ * Karsten Keil (keil@isdn4linux.de)
*
*
* $Log: telespci.c,v $
+ * Revision 2.11 1999/12/23 15:09:32 keil
+ * change email
+ *
* Revision 2.10 1999/11/15 14:20:05 keil
* 64Bit compatibility
*
@@ -47,7 +50,7 @@
#include <linux/pci.h>
extern const char *CardType[];
-const char *telespci_revision = "$Revision: 2.10 $";
+const char *telespci_revision = "$Revision: 2.11 $";
#define ZORAN_PO_RQ_PEN 0x02000000
#define ZORAN_PO_WR 0x00800000
diff --git a/drivers/isdn/hysdn/.cvsignore b/drivers/isdn/hysdn/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/isdn/hysdn/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile
new file mode 100644
index 000000000..626a6deaa
--- /dev/null
+++ b/drivers/isdn/hysdn/Makefile
@@ -0,0 +1,24 @@
+SUB_DIRS :=
+MOD_SUB_DIRS :=
+ALL_SUB_DIRS :=
+
+L_OBJS :=
+LX_OBJS :=
+M_OBJS :=
+MX_OBJS :=
+O_OBJS :=
+OX_OBJS :=
+L_TARGET :=
+O_TARGET :=
+
+ifeq ($(CONFIG_PROC_FS),y)
+ ifeq ($(CONFIG_HYSDN),y)
+ M_OBJS += hysdn.o
+ O_TARGET += hysdn.o
+ O_OBJS += hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o hysdn_sched.o hysdn_net.o
+ OX_OBJS += hysdn_init.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
+
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
new file mode 100644
index 000000000..578e4a14d
--- /dev/null
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -0,0 +1,467 @@
+/* $Id: boardergo.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+
+ * Linux driver for HYSDN cards, specific routines for ergo type boards.
+ *
+ * As all Linux supported cards Champ2, Ergo and Metro2/4 use the same
+ * DPRAM interface and layout with only minor differences all related
+ * stuff is done here, not in separate modules.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.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: boardergo.c,v $
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+
+#include "hysdn_defs.h"
+#include "boardergo.h"
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+/***************************************************/
+/* The cards interrupt handler. Called from system */
+/***************************************************/
+static void
+ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ hysdn_card *card = dev_id; /* parameter from irq */
+ tErgDpram *dpr;
+ ulong flags;
+ uchar volatile b;
+
+ if (!card)
+ return; /* error -> spurious interrupt */
+ if (!card->irq_enabled)
+ return; /* other device interrupting or irq switched off */
+
+ save_flags(flags);
+ cli(); /* no further irqs allowed */
+
+ if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) {
+ restore_flags(flags); /* restore old state */
+ return; /* no interrupt requested by E1 */
+ }
+ /* clear any pending ints on the board */
+ dpr = card->dpram;
+ b = dpr->ToPcInt; /* clear for ergo */
+ b |= dpr->ToPcIntMetro; /* same for metro */
+ b |= dpr->ToHyInt; /* and for champ */
+
+ /* start kernel task immediately after leaving all interrupts */
+ if (!card->hw_lock) {
+ queue_task(&card->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ restore_flags(flags);
+} /* ergo_interrupt */
+
+/******************************************************************************/
+/* ergo_irq_bh is the function called by the immediate kernel task list after */
+/* being activated with queue_task and no interrupts active. This task is the */
+/* only one handling data transfer from or to the card after booting. The task */
+/* may be queued from everywhere (interrupts included). */
+/******************************************************************************/
+static void
+ergo_irq_bh(hysdn_card * card)
+{
+ tErgDpram *dpr;
+ int again;
+ ulong flags;
+
+ if (card->state != CARD_STATE_RUN)
+ return; /* invalid call */
+
+ dpr = card->dpram; /* point to DPRAM */
+
+ save_flags(flags);
+ cli();
+ if (card->hw_lock) {
+ restore_flags(flags); /* hardware currently unavailable */
+ return;
+ }
+ card->hw_lock = 1; /* we now lock the hardware */
+
+ do {
+ sti(); /* reenable other ints */
+ again = 0; /* assume loop not to be repeated */
+
+ if (!dpr->ToHyFlag) {
+ /* we are able to send a buffer */
+
+ if (hysdn_sched_tx(card, dpr->ToHyBuf, &dpr->ToHySize, &dpr->ToHyChannel,
+ ERG_TO_HY_BUF_SIZE)) {
+ dpr->ToHyFlag = 1; /* enable tx */
+ again = 1; /* restart loop */
+ }
+ } /* we are able to send a buffer */
+ if (dpr->ToPcFlag) {
+ /* a message has arrived for us, handle it */
+
+ if (hysdn_sched_rx(card, dpr->ToPcBuf, dpr->ToPcSize, dpr->ToPcChannel)) {
+ dpr->ToPcFlag = 0; /* we worked the data */
+ again = 1; /* restart loop */
+ }
+ } /* a message has arrived for us */
+ cli(); /* no further ints */
+ if (again) {
+ dpr->ToHyInt = 1;
+ dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
+ } else
+ card->hw_lock = 0; /* free hardware again */
+ } while (again); /* until nothing more to do */
+
+ restore_flags(flags);
+} /* ergo_irq_bh */
+
+
+/*********************************************************/
+/* stop the card (hardware reset) and disable interrupts */
+/*********************************************************/
+static void
+ergo_stopcard(hysdn_card * card)
+{
+ ulong flags;
+ uchar val;
+
+ hysdn_net_release(card); /* first release the net device if existing */
+ save_flags(flags);
+ cli();
+ val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */
+ val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */
+ byteout(card->iobase + PCI9050_INTR_REG, val);
+ card->irq_enabled = 0;
+ byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET); /* reset E1 processor */
+ card->state = CARD_STATE_UNUSED;
+ card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */
+
+ restore_flags(flags);
+} /* ergo_stopcard */
+
+/**************************************************************************/
+/* enable or disable the cards error log. The event is queued if possible */
+/**************************************************************************/
+static void
+ergo_set_errlog_state(hysdn_card * card, int on)
+{
+ ulong flags;
+
+ if (card->state != CARD_STATE_RUN) {
+ card->err_log_state = ERRLOG_STATE_OFF; /* must be off */
+ return;
+ }
+ save_flags(flags);
+ cli();
+
+ if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) ||
+ ((card->err_log_state == ERRLOG_STATE_ON) && on)) {
+ restore_flags(flags);
+ return; /* nothing to do */
+ }
+ if (on)
+ card->err_log_state = ERRLOG_STATE_START; /* request start */
+ else
+ card->err_log_state = ERRLOG_STATE_STOP; /* request stop */
+
+ restore_flags(flags);
+ queue_task(&card->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+} /* ergo_set_errlog_state */
+
+/******************************************/
+/* test the cards RAM and return 0 if ok. */
+/******************************************/
+static const char TestText[36] = "This Message is filler, why read it";
+
+static int
+ergo_testram(hysdn_card * card)
+{
+ tErgDpram *dpr = card->dpram;
+
+ memset(dpr->TrapTable, 0, sizeof(dpr->TrapTable)); /* clear all Traps */
+ dpr->ToHyInt = 1; /* E1 INTR state forced */
+
+ memcpy(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
+ sizeof(TestText));
+ if (memcmp(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
+ sizeof(TestText)))
+ return (-1);
+
+ memcpy(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
+ sizeof(TestText));
+ if (memcmp(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
+ sizeof(TestText)))
+ return (-1);
+
+ return (0);
+} /* ergo_testram */
+
+/*****************************************************************************/
+/* this function is intended to write stage 1 boot image to the cards buffer */
+/* this is done in two steps. First the 1024 hi-words are written (offs=0), */
+/* then the 1024 lo-bytes are written. The remaining DPRAM is cleared, the */
+/* PCI-write-buffers flushed and the card is taken out of reset. */
+/* The function then waits for a reaction of the E1 processor or a timeout. */
+/* Negative return values are interpreted as errors. */
+/*****************************************************************************/
+static int
+ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs)
+{
+ uchar *dst;
+ tErgDpram *dpram;
+ int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */
+
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs);
+
+ dst = card->dpram; /* pointer to start of DPRAM */
+ dst += (offs + ERG_DPRAM_FILL_SIZE); /* offset in the DPRAM */
+ while (cnt--) {
+ *dst++ = *(buf + 1); /* high byte */
+ *dst++ = *buf; /* low byte */
+ dst += 2; /* point to next longword */
+ buf += 2; /* buffer only filled with words */
+ }
+
+ /* if low words (offs = 2) have been written, clear the rest of the DPRAM, */
+ /* flush the PCI-write-buffer and take the E1 out of reset */
+ if (offs) {
+ memset(card->dpram, 0, ERG_DPRAM_FILL_SIZE); /* fill the DPRAM still not cleared */
+ dpram = card->dpram; /* get pointer to dpram structure */
+ dpram->ToHyNoDpramErrLog = 0xFF; /* write a dpram register */
+ while (!dpram->ToHyNoDpramErrLog); /* reread volatile register to flush PCI */
+
+ byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */
+ /* the interrupts are still masked */
+
+ sti();
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+
+ if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) {
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: write bootldr no answer");
+ return (-ERR_BOOTIMG_FAIL);
+ }
+ } /* start_boot_img */
+ return (0); /* successfull */
+} /* ergo_writebootimg */
+
+/********************************************************************************/
+/* ergo_writebootseq writes the buffer containing len bytes to the E1 processor */
+/* using the boot spool mechanism. If everything works fine 0 is returned. In */
+/* case of errors a negative error value is returned. */
+/********************************************************************************/
+static int
+ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len)
+{
+ tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram;
+ uchar *dst;
+ uchar buflen;
+ int nr_write;
+ uchar tmp_rdptr;
+ uchar wr_mirror;
+ int i;
+
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: write boot seq len=%d ", len);
+
+ dst = sp->Data; /* point to data in spool structure */
+ buflen = sp->Len; /* maximum len of spooled data */
+ wr_mirror = sp->WrPtr; /* only once read */
+ sti();
+
+ /* try until all bytes written or error */
+ i = 0x1000; /* timeout value */
+ while (len) {
+
+ /* first determine the number of bytes that may be buffered */
+ do {
+ tmp_rdptr = sp->RdPtr; /* first read the pointer */
+ i--; /* decrement timeout */
+ } while (i && (tmp_rdptr != sp->RdPtr)); /* wait for stable pointer */
+
+ if (!i) {
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: write boot seq timeout");
+ return (-ERR_BOOTSEQ_FAIL); /* value not stable -> timeout */
+ }
+ if ((nr_write = tmp_rdptr - wr_mirror - 1) < 0)
+ nr_write += buflen; /* now we got number of free bytes - 1 in buffer */
+
+ if (!nr_write)
+ continue; /* no free bytes in buffer */
+
+ if (nr_write > len)
+ nr_write = len; /* limit if last few bytes */
+ i = 0x1000; /* reset timeout value */
+
+ /* now we know how much bytes we may put in the puffer */
+ len -= nr_write; /* we savely could adjust len before output */
+ while (nr_write--) {
+ *(dst + wr_mirror) = *buf++; /* output one byte */
+ if (++wr_mirror >= buflen)
+ wr_mirror = 0;
+ sp->WrPtr = wr_mirror; /* announce the next byte to E1 */
+ } /* while (nr_write) */
+
+ } /* while (len) */
+
+ return (0);
+} /* ergo_writebootseq */
+
+/***********************************************************************************/
+/* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */
+/* boot process. If the process has been successfull 0 is returned otherwise a */
+/* negative error code is returned. */
+/***********************************************************************************/
+static int
+ergo_waitpofready(struct HYSDN_CARD *card)
+{
+ tErgDpram *dpr = card->dpram; /* pointer to DPRAM structure */
+ int timecnt = 10000 / 50; /* timeout is 10 secs max. */
+ ulong flags;
+ int msg_size;
+ int i;
+
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: waiting for pof ready");
+
+ while (timecnt--) {
+ /* wait until timeout */
+
+ if (dpr->ToPcFlag) {
+ /* data has arrived */
+
+ if ((dpr->ToPcChannel != CHAN_SYSTEM) ||
+ (dpr->ToPcSize < MIN_RDY_MSG_SIZE) ||
+ (dpr->ToPcSize > MAX_RDY_MSG_SIZE) ||
+ ((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC))
+ break; /* an error occured */
+
+ /* Check for additional data delivered during SysReady */
+ msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE;
+ if (msg_size > 0)
+ if (EvalSysrTokData(card, dpr->ToPcBuf + RDY_MAGIC_SIZE, msg_size))
+ break;
+
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "ERGO: pof boot success");
+
+ save_flags(flags);
+ cli();
+
+ card->state = CARD_STATE_RUN; /* now card is running */
+ /* enable the cards interrupt */
+ byteout(card->iobase + PCI9050_INTR_REG,
+ bytein(card->iobase + PCI9050_INTR_REG) |
+ (PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1));
+ card->irq_enabled = 1; /* we are ready to receive interrupts */
+
+ dpr->ToPcFlag = 0; /* reset data indicator */
+ dpr->ToHyInt = 1;
+ dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
+
+ restore_flags(flags);
+ if ((i = hysdn_net_create(card))) {
+ ergo_stopcard(card);
+ card->state = CARD_STATE_BOOTERR;
+ return (i);
+ }
+ return (0); /* success */
+ } /* data has arrived */
+ sti();
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((50 * HZ) / 1000); /* Timeout 50ms */
+ } /* wait until timeout */
+
+ if (card->debug_flags & LOG_POF_CARD)
+ hysdn_addlog(card, "ERGO: pof boot ready timeout");
+ return (-ERR_POF_TIMEOUT);
+} /* ergo_waitpofready */
+
+
+
+/************************************************************************************/
+/* release the cards hardware. Before releasing do a interrupt disable and hardware */
+/* reset. Also unmap dpram. */
+/* Use only during module release. */
+/************************************************************************************/
+static void
+ergo_releasehardware(hysdn_card * card)
+{
+ ergo_stopcard(card); /* first stop the card if not already done */
+ free_irq(card->irq, card); /* release interrupt */
+ release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */
+ release_region(card->iobase + PCI9050_USER_IO, 1);
+ vfree(card->dpram);
+ card->dpram = NULL; /* release shared mem */
+} /* ergo_releasehardware */
+
+
+/*********************************************************************************/
+/* acquire the needed hardware ports and map dpram. If an error occurs a nonzero */
+/* value is returned. */
+/* Use only during module init. */
+/*********************************************************************************/
+int
+ergo_inithardware(hysdn_card * card)
+{
+ if (check_region(card->iobase + PCI9050_INTR_REG, 1) ||
+ check_region(card->iobase + PCI9050_USER_IO, 1))
+ return (-1); /* ports already in use */
+
+ card->memend = card->membase + ERG_DPRAM_PAGE_SIZE - 1;
+ if (!(card->dpram = ioremap(card->membase, ERG_DPRAM_PAGE_SIZE)))
+ return (-1);
+
+ request_region(card->iobase + PCI9050_INTR_REG, 1, "HYSDN");
+ request_region(card->iobase + PCI9050_USER_IO, 1, "HYSDN");
+ ergo_stopcard(card); /* disable interrupts */
+ if (request_irq(card->irq, ergo_interrupt, SA_SHIRQ, "HYSDN", card)) {
+ ergo_releasehardware(card); /* return the aquired hardware */
+ return (-1);
+ }
+ /* success, now setup the function pointers */
+ card->stopcard = ergo_stopcard;
+ card->releasehardware = ergo_releasehardware;
+ card->testram = ergo_testram;
+ card->writebootimg = ergo_writebootimg;
+ card->writebootseq = ergo_writebootseq;
+ card->waitpofready = ergo_waitpofready;
+ card->set_errlog_state = ergo_set_errlog_state;
+ card->irq_queue.next = 0;
+ card->irq_queue.sync = 0;
+ card->irq_queue.data = card; /* init task queue for interrupt */
+ card->irq_queue.routine = (void *) (void *) ergo_irq_bh;
+
+ return (0);
+} /* ergo_inithardware */
diff --git a/drivers/isdn/hysdn/boardergo.h b/drivers/isdn/hysdn/boardergo.h
new file mode 100644
index 000000000..0e2c3f678
--- /dev/null
+++ b/drivers/isdn/hysdn/boardergo.h
@@ -0,0 +1,117 @@
+/* $Id: boardergo.h,v 1.1 2000/02/10 19:44:30 werner Exp $
+
+ * Linux driver for HYSDN cards, definitions for ergo type boards (buffers..).
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.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: boardergo.h,v $
+ * Revision 1.1 2000/02/10 19:44:30 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+
+/************************************************/
+/* defines for the dual port memory of the card */
+/************************************************/
+#define ERG_DPRAM_PAGE_SIZE 0x2000 /* DPRAM occupies a 8K page */
+#define BOOT_IMG_SIZE 4096
+#define ERG_DPRAM_FILL_SIZE (ERG_DPRAM_PAGE_SIZE - BOOT_IMG_SIZE)
+
+#define ERG_TO_HY_BUF_SIZE 0x0E00 /* 3072 bytes buffer size to card */
+#define ERG_TO_PC_BUF_SIZE 0x0E00 /* 3072 bytes to PC, too */
+
+/* following DPRAM layout copied from OS2-driver boarderg.h */
+typedef struct ErgDpram_tag {
+/*0000 */ uchar ToHyBuf[ERG_TO_HY_BUF_SIZE];
+/*0E00 */ uchar ToPcBuf[ERG_TO_PC_BUF_SIZE];
+
+ /*1C00 */ uchar bSoftUart[SIZE_RSV_SOFT_UART];
+ /* size 0x1B0 */
+
+ /*1DB0 *//* tErrLogEntry */ uchar volatile ErrLogMsg[64];
+ /* size 64 bytes */
+ /*1DB0 ulong ulErrType; */
+ /*1DB4 ulong ulErrSubtype; */
+ /*1DB8 ulong ucTextSize; */
+ /*1DB9 ulong ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */
+ /*1DF0 */
+
+/*1DF0 */ word volatile ToHyChannel;
+/*1DF2 */ word volatile ToHySize;
+ /*1DF4 */ uchar volatile ToHyFlag;
+ /* !=0: msg for Hy waiting */
+ /*1DF5 */ uchar volatile ToPcFlag;
+ /* !=0: msg for PC waiting */
+/*1DF6 */ word volatile ToPcChannel;
+/*1DF8 */ word volatile ToPcSize;
+ /*1DFA */ uchar bRes1DBA[0x1E00 - 0x1DFA];
+ /* 6 bytes */
+
+/*1E00 */ uchar bRestOfEntryTbl[0x1F00 - 0x1E00];
+/*1F00 */ ulong TrapTable[62];
+ /*1FF8 */ uchar bRes1FF8[0x1FFB - 0x1FF8];
+ /* low part of reset vetor */
+/*1FFB */ uchar ToPcIntMetro;
+ /* notes:
+ * - metro has 32-bit boot ram - accessing
+ * ToPcInt and ToHyInt would be the same;
+ * so we moved ToPcInt to 1FFB.
+ * Because on the PC side both vars are
+ * readonly (reseting on int from E1 to PC),
+ * we can read both vars on both cards
+ * without destroying anything.
+ * - 1FFB is the high byte of the reset vector,
+ * so E1 side should NOT change this byte
+ * when writing!
+ */
+/*1FFC */ uchar volatile ToHyNoDpramErrLog;
+ /* note: ToHyNoDpramErrLog is used to inform
+ * boot loader, not to use DPRAM based
+ * ErrLog; when DOS driver is rewritten
+ * this becomes obsolete
+ */
+/*1FFD */ uchar bRes1FFD;
+ /*1FFE */ uchar ToPcInt;
+ /* E1_intclear; on CHAMP2: E1_intset */
+ /*1FFF */ uchar ToHyInt;
+ /* E1_intset; on CHAMP2: E1_intclear */
+} tErgDpram;
+
+/**********************************************/
+/* PCI9050 controller local register offsets: */
+/* copied from boarderg.c */
+/**********************************************/
+#define PCI9050_INTR_REG 0x4C /* Interrupt register */
+#define PCI9050_USER_IO 0x51 /* User I/O register */
+
+ /* bitmask for PCI9050_INTR_REG: */
+#define PCI9050_INTR_REG_EN1 0x01 /* 1= enable (def.), 0= disable */
+#define PCI9050_INTR_REG_POL1 0x02 /* 1= active high (def.), 0= active low */
+#define PCI9050_INTR_REG_STAT1 0x04 /* 1= intr. active, 0= intr. not active (def.) */
+#define PCI9050_INTR_REG_ENPCI 0x40 /* 1= PCI interrupts enable (def.) */
+
+ /* bitmask for PCI9050_USER_IO: */
+#define PCI9050_USER_IO_EN3 0x02 /* 1= disable , 0= enable (def.) */
+#define PCI9050_USER_IO_DIR3 0x04 /* 1= output (def.), 0= input */
+#define PCI9050_USER_IO_DAT3 0x08 /* 1= high (def.) , 0= low */
+
+#define PCI9050_E1_RESET ( PCI9050_USER_IO_DIR3) /* 0x04 */
+#define PCI9050_E1_RUN (PCI9050_USER_IO_DAT3|PCI9050_USER_IO_DIR3) /* 0x0C */
diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c
new file mode 100644
index 000000000..030c40de6
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_boot.c
@@ -0,0 +1,420 @@
+/* $Id: hysdn_boot.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+
+ * Linux driver for HYSDN cards, specific routines for booting and pof handling.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_boot.c,v $
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/malloc.h>
+#include <asm/uaccess.h>
+
+#include "hysdn_defs.h"
+#include "hysdn_pof.h"
+
+/********************************/
+/* defines for pof read handler */
+/********************************/
+#define POF_READ_FILE_HEAD 0
+#define POF_READ_TAG_HEAD 1
+#define POF_READ_TAG_DATA 2
+
+/************************************************************/
+/* definition of boot specific data area. This data is only */
+/* needed during boot and so allocated dynamically. */
+/************************************************************/
+struct boot_data {
+ word Cryptor; /* for use with Decrypt function */
+ word Nrecs; /* records remaining in file */
+ uchar pof_state; /* actual state of read handler */
+ uchar is_crypted; /* card data is crypted */
+ int BufSize; /* actual number of bytes bufferd */
+ int last_error; /* last occured error */
+ word pof_recid; /* actual pof recid */
+ ulong pof_reclen; /* total length of pof record data */
+ ulong pof_recoffset; /* actual offset inside pof record */
+ union {
+ uchar BootBuf[BOOT_BUF_SIZE]; /* buffer as byte count */
+ tPofRecHdr PofRecHdr; /* header for actual record/chunk */
+ tPofFileHdr PofFileHdr; /* header from POF file */
+ tPofTimeStamp PofTime; /* time information */
+ } buf;
+};
+
+/*****************************************************/
+/* start decryption of sucessive POF file chuncks. */
+/* */
+/* to be called at start of POF file reading, */
+/* before starting any decryption on any POF record. */
+/*****************************************************/
+void
+StartDecryption(struct boot_data *boot)
+{
+ boot->Cryptor = CRYPT_STARTTERM;
+} /* StartDecryption */
+
+
+/***************************************************************/
+/* decrypt complete BootBuf */
+/* NOTE: decryption must be applied to all or none boot tags - */
+/* to HI and LO boot loader and (all) seq tags, because */
+/* global Cryptor is started for whole POF. */
+/***************************************************************/
+void
+DecryptBuf(struct boot_data *boot, int cnt)
+{
+ uchar *bufp = boot->buf.BootBuf;
+
+ while (cnt--) {
+ boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0);
+ *bufp++ ^= (uchar) boot->Cryptor;
+ }
+} /* DecryptBuf */
+
+/********************************************************************************/
+/* pof_handle_data executes the required actions dependant on the active record */
+/* id. If successfull 0 is returned, a negative value shows an error. */
+/********************************************************************************/
+static int
+pof_handle_data(hysdn_card * card, int datlen)
+{
+ struct boot_data *boot = card->boot; /* pointer to boot specific data */
+ long l;
+ uchar *imgp;
+ int img_len;
+
+ /* handle the different record types */
+ switch (boot->pof_recid) {
+
+ case TAG_TIMESTMP:
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText);
+ break;
+
+ case TAG_CBOOTDTA:
+ DecryptBuf(boot, datlen); /* we need to encrypt the buffer */
+ case TAG_BOOTDTA:
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
+ (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA",
+ datlen, boot->pof_recoffset);
+
+ if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) {
+ boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */
+ return (boot->last_error);
+ }
+ imgp = boot->buf.BootBuf; /* start of buffer */
+ img_len = datlen; /* maximum length to transfer */
+
+ l = POF_BOOT_LOADER_OFF_IN_PAGE -
+ (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1));
+ if (l > 0) {
+ /* buffer needs to be truncated */
+ imgp += l; /* advance pointer */
+ img_len -= l; /* adjust len */
+ }
+ /* at this point no special handling for data wrapping over buffer */
+ /* is necessary, because the boot image always will be adjusted to */
+ /* match a page boundary inside the buffer. */
+ /* The buffer for the boot image on the card is filled in 2 cycles */
+ /* first the 1024 hi-words are put in the buffer, then the low 1024 */
+ /* word are handled in the same way with different offset. */
+
+ if (img_len > 0) {
+ /* data available for copy */
+ if ((boot->last_error =
+ card->writebootimg(card, imgp,
+ (boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0)
+ return (boot->last_error);
+ }
+ break; /* end of case boot image hi/lo */
+
+ case TAG_CABSDATA:
+ DecryptBuf(boot, datlen); /* we need to encrypt the buffer */
+ case TAG_ABSDATA:
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
+ (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA",
+ datlen, boot->pof_recoffset);
+
+ if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0))
+ return (boot->last_error); /* error writing data */
+
+ if (boot->pof_recoffset + datlen >= boot->pof_reclen)
+ return (card->waitpofready(card)); /* data completely spooled, wait for ready */
+
+ break; /* end of case boot seq data */
+
+ default:
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid,
+ datlen, boot->pof_recoffset);
+
+ break; /* simply skip record */
+ } /* switch boot->pof_recid */
+
+ return (0);
+} /* pof_handle_data */
+
+
+/******************************************************************************/
+/* pof_write_buffer is called when the buffer has been filled with the needed */
+/* number of data bytes. The number delivered is additionally supplied for */
+/* verification. The functions handles the data and returns the needed number */
+/* of bytes for the next action. If the returned value is 0 or less an error */
+/* occured and booting must be aborted. */
+/******************************************************************************/
+int
+pof_write_buffer(hysdn_card * card, int datlen)
+{
+ struct boot_data *boot = card->boot; /* pointer to boot specific data */
+
+ if (!boot)
+ return (-EFAULT); /* invalid call */
+ if (boot->last_error < 0)
+ return (boot->last_error); /* repeated error */
+
+ if (card->debug_flags & LOG_POF_WRITE)
+ hysdn_addlog(card, "POF write: got %d bytes ", datlen);
+
+ switch (boot->pof_state) {
+ case POF_READ_FILE_HEAD:
+ if (card->debug_flags & LOG_POF_WRITE)
+ hysdn_addlog(card, "POF write: checking file header");
+
+ if (datlen != sizeof(tPofFileHdr)) {
+ boot->last_error = -EPOF_INTERNAL;
+ break;
+ }
+ if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) {
+ boot->last_error = -EPOF_BAD_MAGIC;
+ break;
+ }
+ /* Setup the new state and vars */
+ boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */
+ boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
+ boot->last_error = sizeof(tPofRecHdr); /* new length */
+ break;
+
+ case POF_READ_TAG_HEAD:
+ if (card->debug_flags & LOG_POF_WRITE)
+ hysdn_addlog(card, "POF write: checking tag header");
+
+ if (datlen != sizeof(tPofRecHdr)) {
+ boot->last_error = -EPOF_INTERNAL;
+ break;
+ }
+ boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */
+ boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */
+ boot->pof_recoffset = 0; /* no starting offset */
+
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ",
+ boot->pof_recid, boot->pof_reclen);
+
+ boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */
+ if (boot->pof_reclen < BOOT_BUF_SIZE)
+ boot->last_error = boot->pof_reclen; /* limit size */
+ else
+ boot->last_error = BOOT_BUF_SIZE; /* maximum */
+
+ if (!boot->last_error) { /* no data inside record */
+ boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
+ boot->last_error = sizeof(tPofRecHdr); /* new length */
+ }
+ break;
+
+ case POF_READ_TAG_DATA:
+ if (card->debug_flags & LOG_POF_WRITE)
+ hysdn_addlog(card, "POF write: getting tag data");
+
+ if (datlen != boot->last_error) {
+ boot->last_error = -EPOF_INTERNAL;
+ break;
+ }
+ if ((boot->last_error = pof_handle_data(card, datlen)) < 0)
+ return (boot->last_error); /* an error occured */
+
+ boot->pof_recoffset += datlen;
+ if (boot->pof_recoffset >= boot->pof_reclen) {
+ boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
+ boot->last_error = sizeof(tPofRecHdr); /* new length */
+ } else {
+ if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE)
+ boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */
+ else
+ boot->last_error = BOOT_BUF_SIZE; /* maximum */
+ }
+ break;
+
+ default:
+ boot->last_error = -EPOF_INTERNAL; /* unknown state */
+ break;
+ } /* switch (boot->pof_state) */
+
+ return (boot->last_error);
+} /* pof_write_buffer */
+
+
+/*******************************************************************************/
+/* pof_write_open is called when an open for boot on the cardlog device occurs. */
+/* The function returns the needed number of bytes for the next operation. If */
+/* the returned number is less or equal 0 an error specified by this code */
+/* occurred. Additionally the pointer to the buffer data area is set on success */
+/*******************************************************************************/
+int
+pof_write_open(hysdn_card * card, uchar ** bufp)
+{
+ struct boot_data *boot; /* pointer to boot specific data */
+
+ if (card->boot) {
+ if (card->debug_flags & LOG_POF_OPEN)
+ hysdn_addlog(card, "POF open: already opened for boot");
+ return (-ERR_ALREADY_BOOT); /* boot already active */
+ }
+ /* error no mem available */
+ if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) {
+ if (card->debug_flags & LOG_MEM_ERR)
+ hysdn_addlog(card, "POF open: unable to allocate mem");
+ return (-EFAULT);
+ }
+ card->boot = boot;
+ card->state = CARD_STATE_BOOTING;
+ memset(boot, 0, sizeof(struct boot_data));
+
+ card->stopcard(card); /* first stop the card */
+ if (card->testram(card)) {
+ if (card->debug_flags & LOG_POF_OPEN)
+ hysdn_addlog(card, "POF open: DPRAM test failure");
+ boot->last_error = -ERR_BOARD_DPRAM;
+ card->state = CARD_STATE_BOOTERR; /* show boot error */
+ return (boot->last_error);
+ }
+ boot->BufSize = 0; /* Buffer is empty */
+ boot->pof_state = POF_READ_FILE_HEAD; /* read file header */
+ StartDecryption(boot); /* if POF File should be encrypted */
+
+ if (card->debug_flags & LOG_POF_OPEN)
+ hysdn_addlog(card, "POF open: success");
+
+ *bufp = boot->buf.BootBuf; /* point to buffer */
+ return (sizeof(tPofFileHdr));
+} /* pof_write_open */
+
+/********************************************************************************/
+/* pof_write_close is called when an close of boot on the cardlog device occurs. */
+/* The return value must be 0 if everything has happened as desired. */
+/********************************************************************************/
+int
+pof_write_close(hysdn_card * card)
+{
+ struct boot_data *boot = card->boot; /* pointer to boot specific data */
+
+ if (!boot)
+ return (-EFAULT); /* invalid call */
+
+ card->boot = NULL; /* no boot active */
+ kfree(boot);
+
+ if (card->state == CARD_STATE_RUN)
+ card->set_errlog_state(card, 1); /* activate error log */
+
+ if (card->debug_flags & LOG_POF_OPEN)
+ hysdn_addlog(card, "POF close: success");
+
+ return (0);
+} /* pof_write_close */
+
+/*********************************************************************************/
+/* EvalSysrTokData checks additional records delivered with the Sysready Message */
+/* when POF has been booted. A return value of 0 is used if no error occured. */
+/*********************************************************************************/
+int
+EvalSysrTokData(hysdn_card * card, uchar * cp, int len)
+{
+ u_char *p;
+ u_char crc;
+
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "SysReady Token data length %d", len);
+
+ if (len < 2) {
+ hysdn_addlog(card, "SysReady Token Data to short");
+ return (1);
+ }
+ for (p = cp, crc = 0; p < (cp + len - 2); p++)
+ if ((crc & 0x80))
+ crc = (((u_char) (crc << 1)) + 1) + *p;
+ else
+ crc = ((u_char) (crc << 1)) + *p;
+ crc = ~crc;
+ if (crc != *(cp + len - 1)) {
+ hysdn_addlog(card, "SysReady Token Data invalid CRC");
+ return (1);
+ }
+ len--; /* dont check CRC byte */
+ while (len > 0) {
+
+ if (*cp == SYSR_TOK_END)
+ return (0); /* End of Token stream */
+
+ if (len < (*(cp + 1) + 2)) {
+ hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1));
+ return (1);
+ }
+ switch (*cp) {
+ case SYSR_TOK_B_CHAN: /* 1 */
+ if (*(cp + 1) != 1)
+ return (1); /* length invalid */
+ card->bchans = *(cp + 2);
+ break;
+
+ case SYSR_TOK_FAX_CHAN: /* 2 */
+ if (*(cp + 1) != 1)
+ return (1); /* length invalid */
+ card->faxchans = *(cp + 2);
+ break;
+
+ case SYSR_TOK_MAC_ADDR: /* 3 */
+ if (*(cp + 1) != 6)
+ return (1); /* length invalid */
+ memcpy(card->mac_addr, cp + 2, 6);
+ break;
+
+ default:
+ hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1));
+ break;
+ }
+ len -= (*(cp + 1) + 2); /* adjust len */
+ cp += (*(cp + 1) + 2); /* and pointer */
+ }
+
+ hysdn_addlog(card, "no end token found");
+ return (1);
+} /* EvalSysrTokData */
diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
new file mode 100644
index 000000000..cac76cb26
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_defs.h
@@ -0,0 +1,229 @@
+/* $Id: hysdn_defs.h,v 1.1 2000/02/10 19:44:30 werner Exp $
+
+ * Linux driver for HYSDN cards, global definitions and exported vars and functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_defs.h,v $
+ * Revision 1.1 2000/02/10 19:44:30 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#include <linux/hysdn_if.h>
+#include <linux/interrupt.h>
+#include <linux/tqueue.h>
+#include <linux/skbuff.h>
+
+/****************************/
+/* storage type definitions */
+/****************************/
+#define uchar unsigned char
+#define uint unsigned int
+#define ulong unsigned long
+#define word unsigned short
+
+#include "ince1pc.h"
+
+/************************************************/
+/* constants and bits for debugging/log outputs */
+/************************************************/
+#define LOG_MAX_LINELEN 120
+#define DEB_OUT_SYSLOG 0x80000000 /* output to syslog instead of proc fs */
+#define LOG_MEM_ERR 0x00000001 /* log memory errors like kmalloc failure */
+#define LOG_POF_OPEN 0x00000010 /* log pof open and close activities */
+#define LOG_POF_RECORD 0x00000020 /* log pof record parser */
+#define LOG_POF_WRITE 0x00000040 /* log detailed pof write operation */
+#define LOG_POF_CARD 0x00000080 /* log pof related card functions */
+#define LOG_CNF_LINE 0x00000100 /* all conf lines are put to procfs */
+#define LOG_CNF_DATA 0x00000200 /* non comment conf lines are shown with channel */
+#define LOG_CNF_MISC 0x00000400 /* additional conf line debug outputs */
+#define LOG_SCHED_ASYN 0x00001000 /* debug schedulers async tx routines */
+#define LOG_PROC_OPEN 0x00100000 /* open and close from procfs are logged */
+#define LOG_PROC_ALL 0x00200000 /* all actions from procfs are logged */
+#define LOG_NET_INIT 0x00010000 /* network init and deinit logging */
+
+#define DEF_DEB_FLAGS 0x7fff000f /* everything is logged to procfs */
+
+/**********************************/
+/* proc filesystem name constants */
+/**********************************/
+#define PROC_SUBDIR_NAME "hysdn"
+#define PROC_CONF_BASENAME "cardconf"
+#define PROC_LOG_BASENAME "cardlog"
+
+/************************/
+/* PCI constant defines */
+/************************/
+#define PCI_VENDOR_ID_HYPERCOPE 0x1365
+#define PCI_DEVICE_ID_PLX 0x9050 /* all DPRAM cards use the same id */
+
+/*****************************/
+/* sub ids determining cards */
+/*****************************/
+#define PCI_SUB_ID_OLD_ERGO 0x0104
+#define PCI_SUB_ID_ERGO 0x0106
+#define PCI_SUB_ID_METRO 0x0107
+#define PCI_SUB_ID_CHAMP2 0x0108
+#define PCI_SUB_ID_PLEXUS 0x0109
+
+/***********************************/
+/* PCI 32 bit parms for IO and MEM */
+/***********************************/
+#define PCI_REG_PLX_MEM_BASE 0
+#define PCI_REG_PLX_IO_BASE 1
+#define PCI_REG_MEMORY_BASE 3
+
+/**************/
+/* card types */
+/**************/
+#define BD_NONE 0U
+#define BD_PERFORMANCE 1U
+#define BD_VALUE 2U
+#define BD_PCCARD 3U
+#define BD_ERGO 4U
+#define BD_METRO 5U
+#define BD_CHAMP2 6U
+#define BD_PLEXUS 7U
+
+/******************************************************/
+/* defined states for cards shown by reading cardconf */
+/******************************************************/
+#define CARD_STATE_UNUSED 0 /* never been used or booted */
+#define CARD_STATE_BOOTING 1 /* booting is in progress */
+#define CARD_STATE_BOOTERR 2 /* a previous boot was aborted */
+#define CARD_STATE_RUN 3 /* card is active */
+
+/*******************************/
+/* defines for error_log_state */
+/*******************************/
+#define ERRLOG_STATE_OFF 0 /* error log is switched off, nothing to do */
+#define ERRLOG_STATE_ON 1 /* error log is switched on, wait for data */
+#define ERRLOG_STATE_START 2 /* start error logging */
+#define ERRLOG_STATE_STOP 3 /* stop error logging */
+
+/*******************************/
+/* data structure for one card */
+/*******************************/
+typedef struct HYSDN_CARD {
+
+ /* general variables for the cards */
+ int myid; /* own driver card id */
+ uchar bus; /* pci bus the card is connected to */
+ uchar devfn; /* slot+function bit encoded */
+ word subsysid; /* PCI subsystem id */
+ uchar brdtype; /* type of card */
+ uint bchans; /* number of available B-channels */
+ uint faxchans; /* number of available fax-channels */
+ uchar mac_addr[6]; /* MAC Address read from card */
+ uint irq; /* interrupt number */
+ uint iobase; /* IO-port base address */
+ ulong plxbase; /* PLX memory base */
+ ulong membase; /* DPRAM memory base */
+ ulong memend; /* DPRAM memory end */
+ void *dpram; /* mapped dpram */
+ int state; /* actual state of card -> CARD_STATE_** */
+ struct HYSDN_CARD *next; /* pointer to next card */
+
+ /* data areas for the /proc file system */
+ void *proclog; /* pointer to proclog filesystem specific data */
+ void *procconf; /* pointer to procconf filesystem specific data */
+
+ /* debugging and logging */
+ uchar err_log_state; /* actual error log state of the card */
+ ulong debug_flags; /* tells what should be debugged and where */
+ void (*set_errlog_state) (struct HYSDN_CARD *, int);
+
+ /* interrupt handler + interrupt synchronisation */
+ struct tq_struct irq_queue; /* interrupt task queue */
+ uchar volatile irq_enabled; /* interrupt enabled if != 0 */
+ uchar volatile hw_lock; /* hardware is currently locked -> no access */
+
+ /* boot process */
+ void *boot; /* pointer to boot private data */
+ int (*writebootimg) (struct HYSDN_CARD *, uchar *, ulong);
+ int (*writebootseq) (struct HYSDN_CARD *, uchar *, int);
+ int (*waitpofready) (struct HYSDN_CARD *);
+ int (*testram) (struct HYSDN_CARD *);
+
+ /* scheduler for data transfer (only async parts) */
+ uchar async_data[256]; /* async data to be sent (normally for config) */
+ word volatile async_len; /* length of data to sent */
+ word volatile async_channel; /* channel number for async transfer */
+ int volatile async_busy; /* flag != 0 sending in progress */
+ int volatile net_tx_busy; /* a network packet tx is in progress */
+
+ /* network interface */
+ void *netif; /* pointer to network structure */
+
+ /* init and deinit stopcard for booting, too */
+ void (*stopcard) (struct HYSDN_CARD *);
+ void (*releasehardware) (struct HYSDN_CARD *);
+} hysdn_card;
+
+
+/*****************/
+/* exported vars */
+/*****************/
+extern int cardmax; /* number of found cards */
+extern hysdn_card *card_root; /* pointer to first card */
+
+
+
+/*************************/
+/* im/exported functions */
+/*************************/
+extern int printk(const char *fmt,...);
+extern char *hysdn_getrev(const char *);
+
+/* hysdn_procconf.c */
+extern int hysdn_procconf_init(void); /* init proc config filesys */
+extern void hysdn_procconf_release(void); /* deinit proc config filesys */
+
+/* hysdn_proclog.c */
+extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */
+extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */
+extern void put_log_buffer(hysdn_card *, char *); /* output log data */
+extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */
+extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */
+
+/* boardergo.c */
+extern int ergo_inithardware(hysdn_card * card); /* get hardware -> module init */
+
+/* hysdn_boot.c */
+extern int pof_write_close(hysdn_card *); /* close proc file after writing pof */
+extern int pof_write_open(hysdn_card *, uchar **); /* open proc file for writing pof */
+extern int pof_write_buffer(hysdn_card *, int); /* write boot data to card */
+extern int EvalSysrTokData(hysdn_card *, uchar *, int); /* Check Sysready Token Data */
+
+/* hysdn_sched.c */
+extern int hysdn_sched_tx(hysdn_card *, uchar *, word volatile *, word volatile *,
+ word);
+extern int hysdn_sched_rx(hysdn_card *, uchar *, word, word);
+extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word); /* send one cfg line */
+
+/* hysdn_net.c */
+extern char *hysdn_net_revision;
+extern int hysdn_net_create(hysdn_card *); /* create a new net device */
+extern int hysdn_net_release(hysdn_card *); /* delete the device */
+extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */
+extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */
+extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */
+extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
new file mode 100644
index 000000000..eb3fed4d3
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -0,0 +1,243 @@
+/* $Id: hysdn_init.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+
+ * Linux driver for HYSDN cards, init functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_init.c,v $
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/vmalloc.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+static char *hysdn_init_revision = "$Revision: 1.1 $";
+int cardmax; /* number of found cards */
+hysdn_card *card_root = NULL; /* pointer to first card */
+
+/**********************************************/
+/* table assigning PCI-sub ids to board types */
+/* the last entry contains all 0 */
+/**********************************************/
+static struct {
+ word subid; /* PCI sub id */
+ uchar cardtyp; /* card type assigned */
+} pci_subid_map[] = {
+
+ {
+ PCI_SUB_ID_METRO, BD_METRO
+ },
+ {
+ PCI_SUB_ID_CHAMP2, BD_CHAMP2
+ },
+ {
+ PCI_SUB_ID_ERGO, BD_ERGO
+ },
+ {
+ PCI_SUB_ID_OLD_ERGO, BD_ERGO
+ },
+ {
+ 0, 0
+ } /* terminating entry */
+};
+
+/*********************************************************************/
+/* search_cards searches for available cards in the pci config data. */
+/* If a card is found, the card structure is allocated and the cards */
+/* ressources are reserved. cardmax is incremented. */
+/*********************************************************************/
+static void
+search_cards(void)
+{
+ struct pci_dev *akt_pcidev = NULL;
+ hysdn_card *card, *card_last;
+ uchar irq;
+ int i;
+
+ card_root = NULL;
+ card_last = NULL;
+ while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_PLX,
+ akt_pcidev)) != NULL) {
+
+ if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+ printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
+ return;
+ }
+ memset(card, 0, sizeof(hysdn_card));
+ card->myid = cardmax; /* set own id */
+ card->bus = akt_pcidev->bus->number;
+ card->devfn = akt_pcidev->devfn; /* slot + function */
+ pcibios_read_config_word(card->bus, card->devfn, PCI_SUBSYSTEM_ID, &card->subsysid);
+ pcibios_read_config_byte(card->bus, card->devfn, PCI_INTERRUPT_LINE, &irq);
+ card->irq = irq;
+ card->iobase = akt_pcidev->resource[ PCI_REG_PLX_IO_BASE].start & PCI_BASE_ADDRESS_IO_MASK;
+ card->plxbase = akt_pcidev->resource[ PCI_REG_PLX_MEM_BASE].start;
+ card->membase = akt_pcidev->resource[ PCI_REG_MEMORY_BASE].start;
+ card->brdtype = BD_NONE; /* unknown */
+ card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
+ card->faxchans = 0; /* default no fax channels */
+ card->bchans = 2; /* and 2 b-channels */
+ for (i = 0; pci_subid_map[i].subid; i++)
+ if (pci_subid_map[i].subid == card->subsysid) {
+ card->brdtype = pci_subid_map[i].cardtyp;
+ break;
+ }
+ if (card->brdtype != BD_NONE) {
+ if (ergo_inithardware(card)) {
+ printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
+ kfree(card);
+ continue;
+ }
+ } else {
+ printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
+ kfree(card); /* release mem */
+ continue;
+ }
+ cardmax++;
+ card->next = NULL; /*end of chain */
+ if (card_last)
+ card_last->next = card; /* pointer to next card */
+ else
+ card_root = card;
+ card_last = card; /* new chain end */
+ } /* device found */
+} /* search_cards */
+
+/************************************************************************************/
+/* free_resources frees the acquired PCI resources and returns the allocated memory */
+/************************************************************************************/
+static void
+free_resources(void)
+{
+ hysdn_card *card;
+
+ while (card_root) {
+ card = card_root;
+ if (card->releasehardware)
+ card->releasehardware(card); /* free all hardware resources */
+ card_root = card_root->next; /* remove card from chain */
+ kfree(card); /* return mem */
+
+ } /* while card_root */
+} /* free_resources */
+
+/**************************************************************************/
+/* stop_cards disables (hardware resets) all cards and disables interrupt */
+/**************************************************************************/
+static void
+stop_cards(void)
+{
+ hysdn_card *card;
+
+ card = card_root; /* first in chain */
+ while (card) {
+ if (card->stopcard)
+ card->stopcard(card);
+ card = card->next; /* remove card from chain */
+ } /* while card */
+} /* stop_cards */
+
+
+/****************************************************************************/
+/* The module startup and shutdown code. Only compiled when used as module. */
+/* Using the driver as module is always advisable, because the booting */
+/* image becomes smaller and the driver code is only loaded when needed. */
+/* Additionally newer versions may be activated without rebooting. */
+/****************************************************************************/
+#ifdef CONFIG_MODULES
+
+/******************************************************/
+/* extract revision number from string for log output */
+/******************************************************/
+char *
+hysdn_getrev(const char *revision)
+{
+ char *rev;
+ char *p;
+
+ if ((p = strchr(revision, ':'))) {
+ rev = p + 2;
+ p = strchr(rev, '$');
+ *--p = 0;
+ } else
+ rev = "???";
+ return rev;
+}
+
+
+/****************************************************************************/
+/* init_module is called once when the module is loaded to do all necessary */
+/* things like autodetect... */
+/* If the return value of this function is 0 the init has been successfull */
+/* and the module is added to the list in /proc/modules, otherwise an error */
+/* is assumed and the module will not be kept in memory. */
+/****************************************************************************/
+int
+init_module(void)
+{
+ char tmp[50];
+
+ strcpy(tmp, hysdn_init_revision);
+ printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
+ strcpy(tmp, hysdn_net_revision);
+ printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
+ if (!pci_present()) {
+ printk(KERN_ERR "HYSDN: no PCI bus present, module not loaded\n");
+ return (-1);
+ }
+ search_cards();
+ printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
+
+ if (hysdn_procconf_init()) {
+ free_resources(); /* proc file_sys not created */
+ return (-1);
+ }
+ return (0); /* no error */
+} /* init_module */
+
+
+/***********************************************************************/
+/* cleanup_module is called when the module is released by the kernel. */
+/* The routine is only called if init_module has been successfull and */
+/* the module counter has a value of 0. Otherwise this function will */
+/* not be called. This function must release all resources still allo- */
+/* cated as after the return from this function the module code will */
+/* be removed from memory. */
+/***********************************************************************/
+void
+cleanup_module(void)
+{
+
+ stop_cards();
+ hysdn_procconf_release();
+ free_resources();
+ printk(KERN_NOTICE "HYSDN: module unloaded\n");
+} /* cleanup_module */
+
+#endif /* CONFIG_MODULES */
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
new file mode 100644
index 000000000..1a3d21012
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -0,0 +1,378 @@
+/* $Id: hysdn_net.c,v 1.3 2000/02/14 19:24:12 werner Exp $
+
+ * Linux driver for HYSDN cards, net (ethernet type) handling routines.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.de)
+ *
+ * This net module has been inspired by the skeleton driver from
+ * Donald Becker (becker@CESDIS.gsfc.nasa.gov)
+ *
+ * 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: hysdn_net.c,v $
+ * Revision 1.3 2000/02/14 19:24:12 werner
+ *
+ * Removed superflous file
+ *
+ * Revision 1.2 2000/02/13 17:32:19 werner
+ *
+ * Added support for new network layer of 2.3.43 and 44 kernels and tested driver.
+ *
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inetdevice.h>
+
+#include "hysdn_defs.h"
+
+/* store the actual version for log reporting */
+char *hysdn_net_revision = "$Revision: 1.3 $";
+
+#define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */
+
+/****************************************************************************/
+/* structure containing the complete network data. The structure is aligned */
+/* in a way that both, the device and statistics are kept inside it. */
+/* for proper access, the device structure MUST be the first var/struct */
+/* inside the definition. */
+/****************************************************************************/
+struct net_local {
+ struct net_device netdev; /* the network device */
+ struct net_device_stats stats;
+ /* additional vars may be added here */
+ char dev_name[9]; /* our own device name */
+
+ /* Tx control lock. This protects the transmit buffer ring
+ * state along with the "tx full" state of the driver. This
+ * means all netif_queue flow control actions are protected
+ * by this lock as well.
+ */
+ spinlock_t lock;
+ struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */
+ int in_idx, out_idx; /* indexes to buffer ring */
+ int sk_count; /* number of buffers currently in ring */
+
+ int is_open; /* flag controlling module locking */
+}; /* net_local */
+
+
+/*****************************************************/
+/* Get the current statistics for this card. */
+/* This may be called with the card open or closed ! */
+/*****************************************************/
+static struct net_device_stats *
+net_get_stats(struct net_device *dev)
+{
+ return (&((struct net_local *) dev)->stats);
+} /* net_device_stats */
+
+/*********************************************************************/
+/* Open/initialize the board. This is called (in the current kernel) */
+/* sometime after booting when the 'ifconfig' program is run. */
+/* This routine should set everything up anew at each open, even */
+/* registers that "should" only need to be set once at boot, so that */
+/* there is non-reboot way to recover if something goes wrong. */
+/*********************************************************************/
+static int
+net_open(struct net_device *dev)
+{
+ struct in_device *in_dev;
+ hysdn_card *card = dev->priv;
+ int i;
+
+ if (!((struct net_local *) dev)->is_open)
+ MOD_INC_USE_COUNT; /* increment only if interface is actually down */
+ ((struct net_local *) dev)->is_open = 1; /* device actually open */
+
+ netif_start_queue(dev); /* start tx-queueing */
+
+ /* Fill in the MAC-level header (if not already set) */
+ if (!card->mac_addr[0]) {
+ for (i = 0; i < ETH_ALEN - sizeof(ulong); i++)
+ dev->dev_addr[i] = 0xfc;
+ if ((in_dev = dev->ip_ptr) != NULL) {
+ struct in_ifaddr *ifa = in_dev->ifa_list;
+ if (ifa != NULL)
+ memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ulong)), &ifa->ifa_local, sizeof(ulong));
+ }
+ } else
+ memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
+
+ return (0);
+} /* net_open */
+
+/*******************************************/
+/* flush the currently occupied tx-buffers */
+/* must only be called when device closed */
+/*******************************************/
+static void
+flush_tx_buffers(struct net_local *nl)
+{
+
+ while (nl->sk_count) {
+ dev_kfree_skb(nl->skbs[nl->out_idx++]); /* free skb */
+ if (nl->out_idx >= MAX_SKB_BUFFERS)
+ nl->out_idx = 0; /* wrap around */
+ nl->sk_count--;
+ }
+} /* flush_tx_buffers */
+
+
+/*********************************************************************/
+/* close/decativate the device. The device is not removed, but only */
+/* deactivated. */
+/*********************************************************************/
+static int
+net_close(struct net_device *dev)
+{
+
+ netif_stop_queue(dev); /* disable queueing */
+
+ if (((struct net_local *) dev)->is_open)
+ MOD_DEC_USE_COUNT; /* adjust module counter */
+ ((struct net_local *) dev)->is_open = 0;
+ flush_tx_buffers((struct net_local *) dev);
+
+ return (0); /* success */
+} /* net_close */
+
+/************************************/
+/* send a packet on this interface. */
+/* new style for kernel >= 2.3.33 */
+/************************************/
+static int
+net_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *) dev;
+
+ spin_lock_irq(&lp->lock);
+
+ lp->skbs[lp->in_idx++] = skb; /* add to buffer list */
+ if (lp->in_idx >= MAX_SKB_BUFFERS)
+ lp->in_idx = 0; /* wrap around */
+ lp->sk_count++; /* adjust counter */
+ dev->trans_start = jiffies;
+
+ /* If we just used up the very last entry in the
+ * TX ring on this device, tell the queueing
+ * layer to send no more.
+ */
+ if (lp->sk_count >= MAX_SKB_BUFFERS)
+ netif_stop_queue(dev);
+
+ /* When the TX completion hw interrupt arrives, this
+ * is when the transmit statistics are updated.
+ */
+
+ spin_unlock_irq(&lp->lock);
+
+ if (lp->sk_count <= 3) {
+ queue_task(&((hysdn_card *) dev->priv)->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ return (0); /* success */
+} /* net_send_packet */
+
+
+
+/***********************************************************************/
+/* acknowlegde a packet send. The network layer will be informed about */
+/* completion */
+/***********************************************************************/
+void
+hysdn_tx_netack(hysdn_card * card)
+{
+ struct net_local *lp = card->netif;
+
+ if (!lp)
+ return; /* non existing device */
+
+
+ if (!lp->sk_count)
+ return; /* error condition */
+
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += lp->skbs[lp->out_idx]->len;
+
+ dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */
+ if (lp->out_idx >= MAX_SKB_BUFFERS)
+ lp->out_idx = 0; /* wrap around */
+
+ if (lp->sk_count-- == MAX_SKB_BUFFERS) /* dec usage count */
+ netif_start_queue((struct net_device *) lp);
+} /* hysdn_tx_netack */
+
+/*****************************************************/
+/* we got a packet from the network, go and queue it */
+/*****************************************************/
+void
+hysdn_rx_netpkt(hysdn_card * card, uchar * buf, word len)
+{
+ struct net_local *lp = card->netif;
+ struct sk_buff *skb;
+
+ if (!lp)
+ return; /* non existing device */
+
+ lp->stats.rx_bytes += len;
+
+ skb = dev_alloc_skb(len);
+ if (skb == NULL) {
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+ lp->netdev.name);
+ lp->stats.rx_dropped++;
+ return;
+ }
+ skb->dev = &lp->netdev;
+
+ /* copy the data */
+ memcpy(skb_put(skb, len), buf, len);
+
+ /* determine the used protocol */
+ skb->protocol = eth_type_trans(skb, &lp->netdev);
+
+ netif_rx(skb);
+ lp->stats.rx_packets++; /* adjust packet count */
+
+} /* hysdn_rx_netpkt */
+
+/*****************************************************/
+/* return the pointer to a network packet to be send */
+/*****************************************************/
+struct sk_buff *
+hysdn_tx_netget(hysdn_card * card)
+{
+ struct net_local *lp = card->netif;
+
+ if (!lp)
+ return (NULL); /* non existing device */
+
+ if (!lp->sk_count)
+ return (NULL); /* nothing available */
+
+ return (lp->skbs[lp->out_idx]); /* next packet to send */
+} /* hysdn_tx_netget */
+
+
+/*******************************************/
+/* init function called by register device */
+/*******************************************/
+static int
+net_init(struct net_device *dev)
+{
+ /* setup the function table */
+ dev->open = net_open;
+ dev->stop = net_close;
+ dev->hard_start_xmit = net_send_packet;
+ dev->get_stats = net_get_stats;
+
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+
+ return (0); /* success */
+} /* net_init */
+
+/*****************************************************************************/
+/* hysdn_net_create creates a new net device for the given card. If a device */
+/* already exists, it will be deleted and created a new one. The return value */
+/* 0 announces success, else a negative error code will be returned. */
+/*****************************************************************************/
+int
+hysdn_net_create(hysdn_card * card)
+{
+ struct net_device *dev;
+ int i;
+
+ hysdn_net_release(card); /* release an existing net device */
+ if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
+ printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
+ if (card->debug_flags & LOG_NET_INIT)
+ return (-ENOMEM);
+ }
+ memset(dev, 0, sizeof(struct net_local)); /* clean the structure */
+
+ spin_lock_init(&((struct net_local *) dev)->lock);
+
+ /* initialise necessary or informing fields */
+ dev->base_addr = card->iobase; /* IO address */
+ dev->irq = card->irq; /* irq */
+ dev->init = net_init; /* the init function of the device */
+ dev->name = ((struct net_local *) dev)->dev_name; /* device name */
+ if ((i = register_netdev(dev))) {
+ printk(KERN_WARNING "HYSDN: unable to create network device\n");
+ kfree(dev);
+ return (i);
+ }
+ dev->priv = card; /* remember pointer to own data structure */
+ card->netif = dev; /* setup the local pointer */
+
+ if (card->debug_flags & LOG_NET_INIT)
+ hysdn_addlog(card, "network device created");
+ return (0); /* and return success */
+} /* hysdn_net_create */
+
+/***************************************************************************/
+/* hysdn_net_release deletes the net device for the given card. The return */
+/* value 0 announces success, else a negative error code will be returned. */
+/***************************************************************************/
+int
+hysdn_net_release(hysdn_card * card)
+{
+ struct net_device *dev = card->netif;
+
+ if (!dev)
+ return (0); /* non existing */
+
+ card->netif = NULL; /* clear out pointer */
+ dev->stop(dev); /* close the device */
+
+ flush_tx_buffers((struct net_local *) dev); /* empty buffers */
+
+ unregister_netdev(dev); /* release the device */
+ kfree(dev); /* release the memory allocated */
+ if (card->debug_flags & LOG_NET_INIT)
+ hysdn_addlog(card, "network device deleted");
+
+ return (0); /* always successfull */
+} /* hysdn_net_release */
+
+/*****************************************************************************/
+/* hysdn_net_getname returns a pointer to the name of the network interface. */
+/* if the interface is not existing, a "-" is returned. */
+/*****************************************************************************/
+char *
+hysdn_net_getname(hysdn_card * card)
+{
+ struct net_device *dev = card->netif;
+
+ if (!dev)
+ return ("-"); /* non existing */
+
+ return (dev->name);
+} /* hysdn_net_getname */
diff --git a/drivers/isdn/hysdn/hysdn_pof.h b/drivers/isdn/hysdn/hysdn_pof.h
new file mode 100644
index 000000000..619c07897
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_pof.h
@@ -0,0 +1,95 @@
+/* $Id: hysdn_pof.h,v 1.1 2000/02/10 19:44:30 werner Exp $
+
+ * Linux driver for HYSDN cards, definitions used for handling pof-files.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_pof.h,v $
+ * Revision 1.1 2000/02/10 19:44:30 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+/************************/
+/* POF specific defines */
+/************************/
+#define BOOT_BUF_SIZE 0x1000 /* =4096, maybe moved to other h file */
+#define CRYPT_FEEDTERM 0x8142
+#define CRYPT_STARTTERM 0x81a5
+ /* max. timeout time in seconds
+ * from end of booting to POF is ready
+ */
+#define POF_READY_TIME_OUT_SEC 10
+
+/**********************************/
+/* defines for 1.stage boot image */
+/**********************************/
+
+/* the POF file record containing the boot loader image
+ * has 2 pages a 16KB:
+ * 1. page contains the high 16-bit part of the 32-bit E1 words
+ * 2. page contains the low 16-bit part of the 32-bit E1 words
+ *
+ * In each 16KB page we assume the start of the boot loader code
+ * in the highest 2KB part (at offset 0x3800);
+ * the rest (0x0000..0x37FF) is assumed to contain 0 bytes.
+ */
+
+#define POF_BOOT_LOADER_PAGE_SIZE 0x4000 /* =16384U */
+#define POF_BOOT_LOADER_TOTAL_SIZE (2U*POF_BOOT_LOADER_PAGE_SIZE)
+
+#define POF_BOOT_LOADER_CODE_SIZE 0x0800 /* =2KB =2048U */
+
+ /* offset in boot page, where loader code may start */
+ /* =0x3800= 14336U */
+#define POF_BOOT_LOADER_OFF_IN_PAGE (POF_BOOT_LOADER_PAGE_SIZE-POF_BOOT_LOADER_CODE_SIZE)
+
+
+/*--------------------------------------POF file record structs------------*/
+typedef struct PofFileHdr_tag { /* Pof file header */
+/*00 */ ulong Magic __attribute__((packed));
+/*04 */ ulong N_PofRecs __attribute__((packed));
+/*08 */
+} tPofFileHdr;
+
+typedef struct PofRecHdr_tag { /* Pof record header */
+/*00 */ word PofRecId __attribute__((packed));
+/*02 */ ulong PofRecDataLen __attribute__((packed));
+/*06 */
+} tPofRecHdr;
+
+typedef struct PofTimeStamp_tag {
+/*00 */ ulong UnixTime __attribute__((packed));
+ /*04 */ uchar DateTimeText[0x28] __attribute__((packed));
+ /* =40 */
+/*2C */
+} tPofTimeStamp;
+
+ /* tPofFileHdr.Magic value: */
+#define TAGFILEMAGIC 0x464F501AUL
+ /* tPofRecHdr.PofRecId values: */
+#define TAG_ABSDATA 0x1000 /* abs. data */
+#define TAG_BOOTDTA 0x1001 /* boot data */
+#define TAG_COMMENT 0x0020
+#define TAG_SYSCALL 0x0021
+#define TAG_FLOWCTRL 0x0022
+#define TAG_TIMESTMP 0x0010 /* date/time stamp of version */
+#define TAG_CABSDATA 0x1100 /* crypted abs. data */
+#define TAG_CBOOTDTA 0x1101 /* crypted boot data */
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
new file mode 100644
index 000000000..81e1b84f0
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -0,0 +1,485 @@
+/* $Id: hysdn_procconf.c,v 1.2 2000/02/14 19:23:03 werner Exp $
+
+ * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_procconf.c,v $
+ * Revision 1.2 2000/02/14 19:23:03 werner
+ *
+ * Changed handling of proc filesystem tables to a more portable version
+ *
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+static char *hysdn_procconf_revision = "$Revision: 1.2 $";
+
+#define INFO_OUT_LEN 80 /* length of info line including lf */
+
+/********************************************************/
+/* defines and data structure for conf write operations */
+/********************************************************/
+#define CONF_STATE_DETECT 0 /* waiting for detect */
+#define CONF_STATE_CONF 1 /* writing config data */
+#define CONF_STATE_POF 2 /* writing pof data */
+#define CONF_LINE_LEN 80 /* 80 chars max */
+
+struct conf_writedata {
+ hysdn_card *card; /* card the device is connected to */
+ int buf_size; /* actual number of bytes in the buffer */
+ int needed_size; /* needed size when reading pof */
+ int state; /* actual interface states from above constants */
+ uchar conf_line[CONF_LINE_LEN]; /* buffered conf line */
+ word channel; /* active channel number */
+ uchar *pof_buffer; /* buffer when writing pof */
+};
+
+/***********************************************************************/
+/* process_line parses one config line and transfers it to the card if */
+/* necessary. */
+/* if the return value is negative an error occured. */
+/***********************************************************************/
+static int
+process_line(struct conf_writedata *cnf)
+{
+ uchar *cp = cnf->conf_line;
+ int i;
+
+ if (cnf->card->debug_flags & LOG_CNF_LINE)
+ hysdn_addlog(cnf->card, "conf line: %s", cp);
+
+ if (*cp == '-') { /* option */
+ cp++; /* point to option char */
+
+ if (*cp++ != 'c')
+ return (0); /* option unknown or used */
+ i = 0; /* start value for channel */
+ while ((*cp <= '9') && (*cp >= '0'))
+ i = i * 10 + *cp++ - '0'; /* get decimal number */
+ if (i > 65535) {
+ if (cnf->card->debug_flags & LOG_CNF_MISC)
+ hysdn_addlog(cnf->card, "conf channel invalid %d", i);
+ return (-ERR_INV_CHAN); /* invalid channel */
+ }
+ cnf->channel = i & 0xFFFF; /* set new channel number */
+ return (0); /* success */
+ } /* option */
+ if (*cp == '*') { /* line to send */
+ if (cnf->card->debug_flags & LOG_CNF_DATA)
+ hysdn_addlog(cnf->card, "conf chan=%d %s", cnf->channel, cp);
+ return (hysdn_tx_cfgline(cnf->card, cnf->conf_line + 1,
+ cnf->channel)); /* send the line without * */
+ } /* line to send */
+ return (0);
+} /* process_line */
+
+/*************************/
+/* dummy file operations */
+/*************************/
+static loff_t
+hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
+{
+ return -ESPIPE;
+} /* hysdn_dummy_lseek */
+
+/***********************************/
+/* conf file operations and tables */
+/***********************************/
+
+/****************************************************/
+/* write conf file -> boot or send cfg line to card */
+/****************************************************/
+static ssize_t
+hysdn_conf_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+ struct conf_writedata *cnf;
+ int i;
+ uchar ch, *cp;
+
+ if (&file->f_pos != off) /* fs error check */
+ return (-ESPIPE);
+ if (!count)
+ return (0); /* nothing to handle */
+
+ if (!(cnf = file->private_data))
+ return (-EFAULT); /* should never happen */
+
+ if (cnf->state == CONF_STATE_DETECT) { /* auto detect cnf or pof data */
+ if (copy_from_user(&ch, buf, 1)) /* get first char for detect */
+ return (-EFAULT);
+
+ if (ch == 0x1A) {
+ /* we detected a pof file */
+ if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0)
+ return (cnf->needed_size); /* an error occured -> exit */
+ cnf->buf_size = 0; /* buffer is empty */
+ cnf->state = CONF_STATE_POF; /* new state */
+ } else {
+ /* conf data has been detected */
+ cnf->buf_size = 0; /* buffer is empty */
+ cnf->state = CONF_STATE_CONF; /* requested conf data write */
+ if (cnf->card->state != CARD_STATE_RUN)
+ return (-ERR_NOT_BOOTED);
+ cnf->conf_line[CONF_LINE_LEN - 1] = 0; /* limit string length */
+ cnf->channel = 4098; /* default channel for output */
+ }
+ } /* state was auto detect */
+ if (cnf->state == CONF_STATE_POF) { /* pof write active */
+ i = cnf->needed_size - cnf->buf_size; /* bytes still missing for write */
+ if (i <= 0)
+ return (-EINVAL); /* size error handling pof */
+
+ if (i < count)
+ count = i; /* limit requested number of bytes */
+ if (copy_from_user(cnf->pof_buffer + cnf->buf_size, buf, count))
+ return (-EFAULT); /* error while copying */
+ cnf->buf_size += count;
+
+ if (cnf->needed_size == cnf->buf_size) {
+ cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size); /* write data */
+ if (cnf->needed_size <= 0) {
+ cnf->card->state = CARD_STATE_BOOTERR; /* show boot error */
+ return (cnf->needed_size); /* an error occured */
+ }
+ cnf->buf_size = 0; /* buffer is empty again */
+ }
+ }
+ /* pof write active */
+ else { /* conf write active */
+
+ if (cnf->card->state != CARD_STATE_RUN) {
+ if (cnf->card->debug_flags & LOG_CNF_MISC)
+ hysdn_addlog(cnf->card, "cnf write denied -> not booted");
+ return (-ERR_NOT_BOOTED);
+ }
+ i = (CONF_LINE_LEN - 1) - cnf->buf_size; /* bytes available in buffer */
+ if (i > 0) {
+ /* copy remaining bytes into buffer */
+
+ if (count > i)
+ count = i; /* limit transfer */
+ if (copy_from_user(cnf->conf_line + cnf->buf_size, buf, count))
+ return (-EFAULT); /* error while copying */
+
+ i = count; /* number of chars in buffer */
+ cp = cnf->conf_line + cnf->buf_size;
+ while (i) {
+ /* search for end of line */
+ if ((*cp < ' ') && (*cp != 9))
+ break; /* end of line found */
+ cp++;
+ i--;
+ } /* search for end of line */
+
+ if (i) {
+ /* delimiter found */
+ *cp++ = 0; /* string termination */
+ count -= (i - 1); /* subtract remaining bytes from count */
+ while ((i) && (*cp < ' ') && (*cp != 9)) {
+ i--; /* discard next char */
+ count++; /* mark as read */
+ cp++; /* next char */
+ }
+ cnf->buf_size = 0; /* buffer is empty after transfer */
+ if ((i = process_line(cnf)) < 0) /* handle the line */
+ count = i; /* return the error */
+ }
+ /* delimiter found */
+ else {
+ cnf->buf_size += count; /* add chars to string */
+ if (cnf->buf_size >= CONF_LINE_LEN - 1) {
+ if (cnf->card->debug_flags & LOG_CNF_MISC)
+ hysdn_addlog(cnf->card, "cnf line too long %d chars pos %d", cnf->buf_size, count);
+ return (-ERR_CONF_LONG);
+ }
+ } /* not delimited */
+
+ }
+ /* copy remaining bytes into buffer */
+ else {
+ if (cnf->card->debug_flags & LOG_CNF_MISC)
+ hysdn_addlog(cnf->card, "cnf line too long");
+ return (-ERR_CONF_LONG);
+ }
+ } /* conf write active */
+
+ return (count);
+} /* hysdn_conf_write */
+
+/*******************************************/
+/* read conf file -> output card info data */
+/*******************************************/
+static ssize_t
+hysdn_conf_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+ char *cp;
+ int i;
+
+ if (off != &file->f_pos) /* fs error check */
+ return -ESPIPE;
+
+ if (file->f_mode & FMODE_READ) {
+ if (!(cp = file->private_data))
+ return (-EFAULT); /* should never happen */
+ i = strlen(cp); /* get total string length */
+ if (*off < i) {
+ /* still bytes to transfer */
+ cp += *off; /* point to desired data offset */
+ i -= *off; /* remaining length */
+ if (i > count)
+ i = count; /* limit length to transfer */
+ if (copy_to_user(buf, cp, i))
+ return (-EFAULT); /* copy error */
+ *off += i; /* adjust offset */
+ } else
+ return (0);
+ } else
+ return (-EPERM); /* no permission to read */
+
+ return (i);
+} /* hysdn_conf_read */
+
+/******************/
+/* open conf file */
+/******************/
+static int
+hysdn_conf_open(struct inode *ino, struct file *filep)
+{
+ hysdn_card *card;
+ struct proc_dir_entry *pd;
+ struct conf_writedata *cnf;
+ char *cp, *tmp;
+
+ MOD_INC_USE_COUNT; /* lock module */
+
+ /* now search the addressed card */
+ card = card_root;
+ while (card) {
+ pd = card->procconf;
+ if (pd->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
+ hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x",
+ filep->f_uid, filep->f_gid, filep->f_mode);
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write boot file or conf line */
+
+ if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return (-EFAULT);
+ }
+ cnf->card = card;
+ cnf->buf_size = 0; /* nothing buffered */
+ cnf->state = CONF_STATE_DETECT; /* start auto detect */
+ filep->private_data = cnf;
+
+ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+ /* read access -> output card info data */
+
+ if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return (-EFAULT); /* out of memory */
+ }
+ filep->private_data = tmp; /* start of string */
+
+ /* first output a headline */
+ sprintf(tmp, "id bus slot type irq iobase dp-mem b-chans fax-chans state device");
+ cp = tmp; /* start of string */
+ while (*cp)
+ cp++;
+ while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
+ *cp++ = ' ';
+ *cp++ = '\n';
+
+ /* and now the data */
+ sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x %7d %9d %3d %s",
+ card->myid,
+ card->bus,
+ PCI_SLOT(card->devfn),
+ card->brdtype,
+ card->irq,
+ card->iobase,
+ card->membase,
+ card->bchans,
+ card->faxchans,
+ card->state,
+ hysdn_net_getname(card));
+ while (*cp)
+ cp++;
+ while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
+ *cp++ = ' ';
+ *cp++ = '\n';
+ *cp = 0; /* end of string */
+ } else { /* simultaneous read/write access forbidden ! */
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-EPERM); /* no permission this time */
+ }
+ return (0);
+} /* hysdn_conf_open */
+
+/***************************/
+/* close a config file. */
+/***************************/
+static int
+hysdn_conf_close(struct inode *ino, struct file *filep)
+{
+ hysdn_card *card;
+ struct conf_writedata *cnf;
+ int retval = 0;
+ struct proc_dir_entry *pd;
+
+ /* search the addressed card */
+ card = card_root;
+ while (card) {
+ pd = card->procconf;
+ if (pd->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
+ hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x",
+ filep->f_uid, filep->f_gid, filep->f_mode);
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write boot file or conf line */
+ if (filep->private_data) {
+ cnf = filep->private_data;
+
+ if (cnf->state == CONF_STATE_POF)
+ retval = pof_write_close(cnf->card); /* close the pof write */
+ kfree(filep->private_data); /* free allocated memory for buffer */
+
+ } /* handle write private data */
+ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+ /* read access -> output card info data */
+
+ if (filep->private_data)
+ kfree(filep->private_data); /* release memory */
+ }
+ MOD_DEC_USE_COUNT; /* reduce usage count */
+ return (retval);
+} /* hysdn_conf_close */
+
+/******************************************************/
+/* table for conf filesystem functions defined above. */
+/******************************************************/
+static struct file_operations conf_fops =
+{
+ hysdn_dummy_lseek,
+ hysdn_conf_read,
+ hysdn_conf_write,
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ hysdn_conf_open,
+ NULL, /* flush */
+ hysdn_conf_close,
+ NULL /* fsync */
+};
+
+static struct inode_operations conf_inode_operations;
+
+/*****************************/
+/* hysdn subdir in /proc/net */
+/*****************************/
+struct proc_dir_entry *hysdn_proc_entry = NULL;
+
+/*******************************************************************************/
+/* hysdn_procconf_init is called when the module is loaded and after the cards */
+/* have been detected. The needed proc dir and card config files are created. */
+/* The log init is called at last. */
+/*******************************************************************************/
+int
+hysdn_procconf_init(void)
+{
+ hysdn_card *card;
+ uchar conf_name[20];
+
+ hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
+ if (!hysdn_proc_entry) {
+ printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
+ return (-1);
+ }
+ card = card_root; /* point to first card */
+ while (card) {
+
+ sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
+ if ((card->procconf = (void *) create_proc_entry(conf_name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ hysdn_proc_entry)) != NULL) {
+ memset(&conf_inode_operations, 0, sizeof(struct inode_operations));
+ conf_inode_operations.default_file_ops = &conf_fops;
+
+ ((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations;
+ hysdn_proclog_init(card); /* init the log file entry */
+ }
+ card = card->next; /* next entry */
+ }
+
+ printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision));
+ return (0);
+} /* hysdn_procconf_init */
+
+/*************************************************************************************/
+/* hysdn_procconf_release is called when the module is unloaded and before the cards */
+/* resources are released. The module counter is assumed to be 0 ! */
+/*************************************************************************************/
+void
+hysdn_procconf_release(void)
+{
+ hysdn_card *card;
+ uchar conf_name[20];
+
+ card = card_root; /* start with first card */
+ while (card) {
+
+ sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
+ if (card->procconf)
+ remove_proc_entry(conf_name, hysdn_proc_entry);
+
+ hysdn_proclog_release(card); /* init the log file entry */
+
+ card = card->next; /* point to next card */
+ }
+
+ remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
+} /* hysdn_procfs_release */
diff --git a/drivers/isdn/hysdn/hysdn_procfs.c b/drivers/isdn/hysdn/hysdn_procfs.c
new file mode 100644
index 000000000..d70d350e9
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_procfs.c
@@ -0,0 +1,502 @@
+/* $Id: hysdn_procfs.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+
+ * Linux driver for HYSDN cards, /proc/net filesystem log functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_procfs.c,v $
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+static char *hysdn_procfs_revision = "$Revision: 1.1 $";
+
+#define INFO_OUT_LEN 80 /* length of info line including lf */
+
+/*************************************************/
+/* structure keeping ascii log for device output */
+/*************************************************/
+struct log_data {
+ struct log_data *next;
+ ulong usage_cnt; /* number of files still to work */
+ void *proc_ctrl; /* pointer to own control procdata structure */
+ char log_start[2]; /* log string start (final len aligned by size) */
+};
+
+/**********************************************/
+/* structure holding proc entrys for one card */
+/**********************************************/
+struct procdata {
+ struct proc_dir_entry *log; /* log entry */
+ char log_name[15]; /* log filename */
+ struct log_data *log_head, *log_tail; /* head and tail for queue */
+ int if_used; /* open count for interface */
+ wait_queue_head_t rd_queue;
+};
+
+/********************************************/
+/* put an log buffer into the log queue. */
+/* This buffer will be kept until all files */
+/* opened for read got the contents. */
+/* Flushes buffers not longer in use. */
+/********************************************/
+void
+put_log_buffer(hysdn_card * card, char *cp)
+{
+ struct log_data *ib;
+ struct procdata *pd = card->procfs;
+ int flags;
+
+ if (!pd)
+ return;
+ if (!cp)
+ return;
+ if (!*cp)
+ return;
+ if (pd->if_used <= 0)
+ return; /* no open file for read */
+
+ if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
+ return; /* no memory */
+ strcpy(ib->log_start, cp); /* set output string */
+ ib->next = NULL;
+ ib->proc_ctrl = pd; /* point to own control structure */
+ save_flags(flags);
+ cli();
+ ib->usage_cnt = pd->if_used;
+ if (!pd->log_head)
+ pd->log_head = ib; /* new head */
+ else
+ pd->log_tail->next = ib; /* follows existing messages */
+ pd->log_tail = ib; /* new tail */
+ restore_flags(flags);
+
+ /* delete old entrys */
+ while (pd->log_head->next) {
+ if ((pd->log_head->usage_cnt <= 0) &&
+ (pd->log_head->next->usage_cnt <= 0)) {
+ ib = pd->log_head;
+ pd->log_head = pd->log_head->next;
+ kfree(ib);
+ } else
+ break;
+ } /* pd->log_head->next */
+ wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */
+} /* put_log_buffer */
+
+
+/*************************/
+/* dummy file operations */
+/*************************/
+static loff_t
+hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
+{
+ return -ESPIPE;
+} /* hysdn_dummy_lseek */
+
+/**********************************/
+/* log file operations and tables */
+/**********************************/
+
+/****************************************/
+/* write log file -> set log level bits */
+/****************************************/
+static ssize_t
+hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+ int retval;
+ hysdn_card *card = (hysdn_card *) file->private_data;
+
+ if (&file->f_pos != off) /* fs error check */
+ return (-ESPIPE);
+
+ if ((retval = pof_boot_write(card, buf, count)) < 0)
+ retval = -EFAULT; /* an error occured */
+
+ return (retval);
+} /* hysdn_log_write */
+
+/******************/
+/* read log file */
+/******************/
+static ssize_t
+hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+ struct log_data *inf;
+ int len;
+ word ino;
+ struct procdata *pd;
+ hysdn_card *card;
+
+ if (!*((struct log_data **) file->private_data)) {
+ if (file->f_flags & O_NONBLOCK)
+ return (-EAGAIN);
+
+ /* sorry, but we need to search the card */
+ ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
+ card = card_root;
+ while (card) {
+ pd = card->procfs;
+ if (pd->log->low_ino == ino)
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (card)
+ interruptible_sleep_on(&(pd->rd_queue));
+ else
+ return (-EAGAIN);
+
+ }
+ if (!(inf = *((struct log_data **) file->private_data)))
+ return (0);
+
+ inf->usage_cnt--; /* new usage count */
+ (struct log_data **) file->private_data = &inf->next; /* next structure */
+ if ((len = strlen(inf->log_start)) <= count) {
+ if (copy_to_user(buf, inf->log_start, len))
+ return -EFAULT;
+ file->f_pos += len;
+ return (len);
+ }
+ return (0);
+} /* hysdn_log_read */
+
+/******************/
+/* open log file */
+/******************/
+static int
+hysdn_log_open(struct inode *ino, struct file *filep)
+{
+ hysdn_card *card;
+ struct procdata *pd;
+ ulong flags;
+
+ MOD_INC_USE_COUNT; /* lock module */
+ card = card_root;
+ while (card) {
+ pd = card->procfs;
+ if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ filep->private_data = card; /* remember our own card */
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> boot pof data */
+ if (pof_boot_open(card)) {
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-EPERM); /* no permission this time */
+ }
+ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+
+ /* read access -> log/debug read */
+ save_flags(flags);
+ cli();
+ pd->if_used++;
+ if (pd->log_head)
+ (struct log_data **) filep->private_data = &(pd->log_tail->next);
+ else
+ (struct log_data **) filep->private_data = &(pd->log_head);
+ restore_flags(flags);
+
+ } else { /* simultaneous read/write access forbidden ! */
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-EPERM); /* no permission this time */
+ }
+ return (0);
+} /* hysdn_log_open */
+
+/*******************************************************************************/
+/* close a cardlog file. If the file has been opened for exclusive write it is */
+/* assumed as pof data input and the pof loader is noticed about. */
+/* Otherwise file is handled as log output. In this case the interface usage */
+/* count is decremented and all buffers are noticed of closing. If this file */
+/* was the last one to be closed, all buffers are freed. */
+/*******************************************************************************/
+static int
+hysdn_log_close(struct inode *ino, struct file *filep)
+{
+ struct log_data *inf;
+ struct procdata *pd;
+ hysdn_card *card;
+ int flags, retval = 0;
+
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write debug completely written */
+ retval = 0; /* success */
+ } else {
+ /* read access -> log/debug read, mark one further file as closed */
+
+ pd = NULL;
+ save_flags(flags);
+ cli();
+ inf = *((struct log_data **) filep->private_data); /* get first log entry */
+ if (inf)
+ pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
+ else {
+ /* no info available -> search card */
+ card = card_root;
+ while (card) {
+ pd = card->procfs;
+ if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (card)
+ pd = card->procfs; /* pointer to procfs ctrl */
+ }
+ if (pd)
+ pd->if_used--; /* decrement interface usage count by one */
+
+ while (inf) {
+ inf->usage_cnt--; /* decrement usage count for buffers */
+ inf = inf->next;
+ }
+ restore_flags(flags);
+
+ if (pd)
+ if (pd->if_used <= 0) /* delete buffers if last file closed */
+ while (pd->log_head) {
+ inf = pd->log_head;
+ pd->log_head = pd->log_head->next;
+ kfree(inf);
+ }
+ } /* read access */
+
+ MOD_DEC_USE_COUNT;
+ return (retval);
+} /* hysdn_log_close */
+
+/*************************************************/
+/* select/poll routine to be able using select() */
+/*************************************************/
+static unsigned int
+hysdn_log_poll(struct file *file, poll_table * wait)
+{
+ unsigned int mask = 0;
+ word ino;
+ hysdn_card *card;
+ struct procdata *pd;
+
+ if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
+ return (mask); /* no polling for write supported */
+
+ /* we need to search the card */
+ ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
+ card = card_root;
+ while (card) {
+ pd = card->procfs;
+ if (pd->log->low_ino == ino)
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card)
+ return (mask); /* card not found */
+
+ poll_wait(file, &(pd->rd_queue), wait);
+
+ if (*((struct log_data **) file->private_data))
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+} /* hysdn_log_poll */
+
+/**************************************************/
+/* table for log filesystem functions defined above. */
+/**************************************************/
+static struct file_operations log_fops =
+{
+ hysdn_dummy_lseek,
+ hysdn_log_read,
+ hysdn_log_write,
+ NULL, /* readdir */
+ hysdn_log_poll, /* poll */
+ NULL, /*hysdn_log_ioctl, *//* ioctl */
+ NULL, /* mmap */
+ hysdn_log_open,
+ NULL, /* flush */
+ hysdn_log_close,
+ NULL /* fsync */
+};
+
+struct inode_operations log_inode_operations =
+{
+ &log_fops, /* log proc 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 */
+};
+
+/*****************************************/
+/* Output info data to the cardinfo file */
+/*****************************************/
+static int
+info_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+ char tmp[INFO_OUT_LEN * 11 + 2];
+ int i;
+ char *cp;
+ hysdn_card *card;
+
+ sprintf(tmp, "id bus slot type irq iobase plx-mem dp-mem boot device");
+ cp = tmp; /* start of string */
+ while (*cp)
+ cp++;
+ while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
+ *cp++ = ' ';
+ *cp++ = '\n';
+
+ card = card_root; /* start of list */
+ while (card) {
+ sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x 0x%08x",
+ card->myid,
+ card->bus,
+ PCI_SLOT(card->devfn),
+ card->brdtype,
+ card->irq,
+ card->iobase,
+ card->plxbase,
+ card->membase);
+ card = card->next;
+ while (*cp)
+ cp++;
+ while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
+ *cp++ = ' ';
+ *cp++ = '\n';
+ }
+
+ i = cp - tmp;
+ *start = buffer;
+ if (offset + length > i) {
+ length = i - offset;
+ *eof = 1;
+ } else if (offset > i) {
+ length = 0;
+ *eof = 1;
+ }
+ cp = tmp + offset;
+
+ if (length > 0) {
+ /* start_bh_atomic(); */
+ memcpy(buffer, cp, length);
+ /* end_bh_atomic(); */
+ return length;
+ }
+ return 0;
+} /* info_read */
+
+/*****************************/
+/* hysdn subdir in /proc/net */
+/*****************************/
+static struct proc_dir_entry *hysdn_proc_entry = NULL;
+static struct proc_dir_entry *hysdn_info_entry = NULL;
+
+/***************************************************************************************/
+/* hysdn_procfs_init is called when the module is loaded and after the cards have been */
+/* detected. The needed proc dir and card entries are created. */
+/***************************************************************************************/
+int
+hysdn_procfs_init(void)
+{
+ struct procdata *pd;
+ hysdn_card *card;
+
+ hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
+ if (!hysdn_proc_entry) {
+ printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
+ return (-1);
+ }
+ hysdn_info_entry = create_proc_entry("cardinfo", 0, hysdn_proc_entry);
+ if (hysdn_info_entry)
+ hysdn_info_entry->read_proc = info_read; /* read info function */
+
+ /* create all cardlog proc entries */
+
+ card = card_root; /* start with first card */
+ while (card) {
+ if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
+ memset(pd, 0, sizeof(struct procdata));
+
+ sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
+ if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
+ pd->log->ops = &log_inode_operations; /* set new operations table */
+
+ init_waitqueue_head(&(pd->rd_queue));
+
+ card->procfs = (void *) pd; /* remember procfs structure */
+ }
+ card = card->next; /* point to next card */
+ }
+
+ printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procfs_revision));
+ return (0);
+} /* hysdn_procfs_init */
+
+/***************************************************************************************/
+/* hysdn_procfs_release is called when the module is unloaded and before the cards */
+/* resources are released. The module counter is assumed to be 0 ! */
+/***************************************************************************************/
+void
+hysdn_procfs_release(void)
+{
+ struct procdata *pd;
+ hysdn_card *card;
+
+ card = card_root; /* start with first card */
+ while (card) {
+ if ((pd = (struct procdata *) card->procfs) != NULL) {
+ if (pd->log)
+ remove_proc_entry(pd->log_name, hysdn_proc_entry);
+ kfree(pd); /* release memory */
+ }
+ card = card->next; /* point to next card */
+ }
+
+ remove_proc_entry("cardinfo", hysdn_proc_entry);
+ remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
+} /* hysdn_procfs_release */
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
new file mode 100644
index 000000000..aea6a96ad
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -0,0 +1,481 @@
+/* $Id: hysdn_proclog.c,v 1.2 2000/02/14 19:23:03 werner Exp $
+
+ * Linux driver for HYSDN cards, /proc/net filesystem log functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_proclog.c,v $
+ * Revision 1.2 2000/02/14 19:23:03 werner
+ *
+ * Changed handling of proc filesystem tables to a more portable version
+ *
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+static char *hysdn_proclog_revision = "$Revision: 1.2 $";
+
+/* the proc subdir for the interface is defined in the procconf module */
+extern struct proc_dir_entry *hysdn_proc_entry;
+
+/*************************************************/
+/* structure keeping ascii log for device output */
+/*************************************************/
+struct log_data {
+ struct log_data *next;
+ ulong usage_cnt; /* number of files still to work */
+ void *proc_ctrl; /* pointer to own control procdata structure */
+ char log_start[2]; /* log string start (final len aligned by size) */
+};
+
+/**********************************************/
+/* structure holding proc entrys for one card */
+/**********************************************/
+struct procdata {
+ struct proc_dir_entry *log; /* log entry */
+ char log_name[15]; /* log filename */
+ struct log_data *log_head, *log_tail; /* head and tail for queue */
+ int if_used; /* open count for interface */
+ int volatile del_lock; /* lock for delete operations */
+ uchar logtmp[LOG_MAX_LINELEN];
+ wait_queue_head_t rd_queue;
+};
+
+
+/**********************************************/
+/* log function for cards error log interface */
+/**********************************************/
+void
+hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize)
+{
+ char buf[ERRLOG_TEXT_SIZE + 40];
+
+ sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText);
+ put_log_buffer(card, buf); /* output the string */
+} /* hysdn_card_errlog */
+
+/***************************************************/
+/* Log function using format specifiers for output */
+/***************************************************/
+void
+hysdn_addlog(hysdn_card * card, char *fmt,...)
+{
+ struct procdata *pd = card->proclog;
+ char *cp;
+ va_list args;
+
+ if (!pd)
+ return; /* log structure non existent */
+
+ cp = pd->logtmp;
+ cp += sprintf(cp, "HYSDN: card %d ", card->myid);
+
+ va_start(args, fmt);
+ cp += vsprintf(cp, fmt, args);
+ va_end(args);
+ *cp++ = '\n';
+ *cp = 0;
+
+ if (card->debug_flags & DEB_OUT_SYSLOG)
+ printk(KERN_INFO "%s", pd->logtmp);
+ else
+ put_log_buffer(card, pd->logtmp);
+
+} /* hysdn_addlog */
+
+/********************************************/
+/* put an log buffer into the log queue. */
+/* This buffer will be kept until all files */
+/* opened for read got the contents. */
+/* Flushes buffers not longer in use. */
+/********************************************/
+void
+put_log_buffer(hysdn_card * card, char *cp)
+{
+ struct log_data *ib;
+ struct procdata *pd = card->proclog;
+ int i, flags;
+
+ if (!pd)
+ return;
+ if (!cp)
+ return;
+ if (!*cp)
+ return;
+ if (pd->if_used <= 0)
+ return; /* no open file for read */
+
+ if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
+ return; /* no memory */
+ strcpy(ib->log_start, cp); /* set output string */
+ ib->next = NULL;
+ ib->proc_ctrl = pd; /* point to own control structure */
+ save_flags(flags);
+ cli();
+ ib->usage_cnt = pd->if_used;
+ if (!pd->log_head)
+ pd->log_head = ib; /* new head */
+ else
+ pd->log_tail->next = ib; /* follows existing messages */
+ pd->log_tail = ib; /* new tail */
+ i = pd->del_lock++; /* get lock state */
+ restore_flags(flags);
+
+ /* delete old entrys */
+ if (!i)
+ while (pd->log_head->next) {
+ if ((pd->log_head->usage_cnt <= 0) &&
+ (pd->log_head->next->usage_cnt <= 0)) {
+ ib = pd->log_head;
+ pd->log_head = pd->log_head->next;
+ kfree(ib);
+ } else
+ break;
+ } /* pd->log_head->next */
+ pd->del_lock--; /* release lock level */
+ wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */
+} /* put_log_buffer */
+
+
+/*************************/
+/* dummy file operations */
+/*************************/
+static loff_t
+hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
+{
+ return -ESPIPE;
+} /* hysdn_dummy_lseek */
+
+/******************************/
+/* file operations and tables */
+/******************************/
+
+/****************************************/
+/* write log file -> set log level bits */
+/****************************************/
+static ssize_t
+hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+ ulong u = 0;
+ int found = 0;
+ uchar *cp, valbuf[128];
+ long base = 10;
+ hysdn_card *card = (hysdn_card *) file->private_data;
+
+ if (&file->f_pos != off) /* fs error check */
+ return (-ESPIPE);
+
+ if (count > (sizeof(valbuf) - 1))
+ count = sizeof(valbuf) - 1; /* limit length */
+ if (copy_from_user(valbuf, buf, count))
+ return (-EFAULT); /* copy failed */
+
+ valbuf[count] = 0; /* terminating 0 */
+ cp = valbuf;
+ if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) {
+ cp += 2; /* pointer after hex modifier */
+ base = 16;
+ }
+ /* scan the input for debug flags */
+ while (*cp) {
+ if ((*cp >= '0') && (*cp <= '9')) {
+ found = 1;
+ u *= base; /* adjust to next digit */
+ u += *cp++ - '0';
+ continue;
+ }
+ if (base != 16)
+ break; /* end of number */
+
+ if ((*cp >= 'a') && (*cp <= 'f')) {
+ found = 1;
+ u *= base; /* adjust to next digit */
+ u += *cp++ - 'a' + 10;
+ continue;
+ }
+ break; /* terminated */
+ }
+
+ if (found) {
+ card->debug_flags = u; /* remember debug flags */
+ hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
+ }
+ return (count);
+} /* hysdn_log_write */
+
+/******************/
+/* read log file */
+/******************/
+static ssize_t
+hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+ struct log_data *inf;
+ int len;
+ word ino;
+ struct procdata *pd;
+ hysdn_card *card;
+
+ if (!*((struct log_data **) file->private_data)) {
+ if (file->f_flags & O_NONBLOCK)
+ return (-EAGAIN);
+
+ /* sorry, but we need to search the card */
+ ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
+ card = card_root;
+ while (card) {
+ pd = card->proclog;
+ if (pd->log->low_ino == ino)
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (card)
+ interruptible_sleep_on(&(pd->rd_queue));
+ else
+ return (-EAGAIN);
+
+ }
+ if (!(inf = *((struct log_data **) file->private_data)))
+ return (0);
+
+ inf->usage_cnt--; /* new usage count */
+ (struct log_data **) file->private_data = &inf->next; /* next structure */
+ if ((len = strlen(inf->log_start)) <= count) {
+ if (copy_to_user(buf, inf->log_start, len))
+ return -EFAULT;
+ file->f_pos += len;
+ return (len);
+ }
+ return (0);
+} /* hysdn_log_read */
+
+/******************/
+/* open log file */
+/******************/
+static int
+hysdn_log_open(struct inode *ino, struct file *filep)
+{
+ hysdn_card *card;
+ struct procdata *pd;
+ ulong flags;
+
+ MOD_INC_USE_COUNT; /* lock module */
+ card = card_root;
+ while (card) {
+ pd = card->proclog;
+ if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ filep->private_data = card; /* remember our own card */
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write log level only */
+ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+
+ /* read access -> log/debug read */
+ save_flags(flags);
+ cli();
+ pd->if_used++;
+ if (pd->log_head)
+ (struct log_data **) filep->private_data = &(pd->log_tail->next);
+ else
+ (struct log_data **) filep->private_data = &(pd->log_head);
+ restore_flags(flags);
+ } else { /* simultaneous read/write access forbidden ! */
+ MOD_DEC_USE_COUNT; /* unlock module */
+ return (-EPERM); /* no permission this time */
+ }
+ return (0);
+} /* hysdn_log_open */
+
+/*******************************************************************************/
+/* close a cardlog file. If the file has been opened for exclusive write it is */
+/* assumed as pof data input and the pof loader is noticed about. */
+/* Otherwise file is handled as log output. In this case the interface usage */
+/* count is decremented and all buffers are noticed of closing. If this file */
+/* was the last one to be closed, all buffers are freed. */
+/*******************************************************************************/
+static int
+hysdn_log_close(struct inode *ino, struct file *filep)
+{
+ struct log_data *inf;
+ struct procdata *pd;
+ hysdn_card *card;
+ int flags, retval = 0;
+
+
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write debug level written */
+ retval = 0; /* success */
+ } else {
+ /* read access -> log/debug read, mark one further file as closed */
+
+ pd = NULL;
+ save_flags(flags);
+ cli();
+ inf = *((struct log_data **) filep->private_data); /* get first log entry */
+ if (inf)
+ pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
+ else {
+ /* no info available -> search card */
+ card = card_root;
+ while (card) {
+ pd = card->proclog;
+ if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (card)
+ pd = card->proclog; /* pointer to procfs log */
+ }
+ if (pd)
+ pd->if_used--; /* decrement interface usage count by one */
+
+ while (inf) {
+ inf->usage_cnt--; /* decrement usage count for buffers */
+ inf = inf->next;
+ }
+ restore_flags(flags);
+
+ if (pd)
+ if (pd->if_used <= 0) /* delete buffers if last file closed */
+ while (pd->log_head) {
+ inf = pd->log_head;
+ pd->log_head = pd->log_head->next;
+ kfree(inf);
+ }
+ } /* read access */
+
+ MOD_DEC_USE_COUNT;
+ return (retval);
+} /* hysdn_log_close */
+
+/*************************************************/
+/* select/poll routine to be able using select() */
+/*************************************************/
+static unsigned int
+hysdn_log_poll(struct file *file, poll_table * wait)
+{
+ unsigned int mask = 0;
+ word ino;
+ hysdn_card *card;
+ struct procdata *pd;
+
+ if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
+ return (mask); /* no polling for write supported */
+
+ /* we need to search the card */
+ ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
+ card = card_root;
+ while (card) {
+ pd = card->proclog;
+ if (pd->log->low_ino == ino)
+ break;
+ card = card->next; /* search next entry */
+ }
+ if (!card)
+ return (mask); /* card not found */
+
+ poll_wait(file, &(pd->rd_queue), wait);
+
+ if (*((struct log_data **) file->private_data))
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+} /* hysdn_log_poll */
+
+/**************************************************/
+/* table for log filesystem functions defined above. */
+/**************************************************/
+static struct file_operations log_fops =
+{
+ hysdn_dummy_lseek,
+ hysdn_log_read,
+ hysdn_log_write,
+ NULL, /* readdir */
+ hysdn_log_poll, /* poll */
+ NULL,
+ NULL, /* mmap */
+ hysdn_log_open,
+ NULL, /* flush */
+ hysdn_log_close,
+ NULL /* fsync */
+};
+
+struct inode_operations log_inode_operations;
+
+/***********************************************************************************/
+/* hysdn_proclog_init is called when the module is loaded after creating the cards */
+/* conf files. */
+/***********************************************************************************/
+int
+hysdn_proclog_init(hysdn_card * card)
+{
+ struct procdata *pd;
+
+ /* create a cardlog proc entry */
+
+ if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
+ memset(pd, 0, sizeof(struct procdata));
+ memset(&log_inode_operations, 0, sizeof(struct inode_operations));
+ log_inode_operations.default_file_ops = &log_fops;
+
+ sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
+ if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
+ pd->log->ops = &log_inode_operations; /* set new operations table */
+
+ init_waitqueue_head(&(pd->rd_queue));
+
+ card->proclog = (void *) pd; /* remember procfs structure */
+ }
+ return (0);
+} /* hysdn_proclog_init */
+
+/************************************************************************************/
+/* hysdn_proclog_release is called when the module is unloaded and before the cards */
+/* conf file is released */
+/* The module counter is assumed to be 0 ! */
+/************************************************************************************/
+void
+hysdn_proclog_release(hysdn_card * card)
+{
+ struct procdata *pd;
+
+ if ((pd = (struct procdata *) card->proclog) != NULL) {
+ if (pd->log)
+ remove_proc_entry(pd->log_name, hysdn_proc_entry);
+ kfree(pd); /* release memory */
+ card->proclog = NULL;
+ }
+} /* hysdn_proclog_release */
diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c
new file mode 100644
index 000000000..0e5f9e7ba
--- /dev/null
+++ b/drivers/isdn/hysdn/hysdn_sched.c
@@ -0,0 +1,202 @@
+/* $Id: hysdn_sched.c,v 1.1 2000/02/10 19:45:18 werner Exp $
+
+ * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_sched.c,v $
+ * Revision 1.1 2000/02/10 19:45:18 werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+
+#include "hysdn_defs.h"
+
+/*****************************************************************************/
+/* hysdn_sched_rx is called from the cards handler to announce new data is */
+/* available from the card. The routine has to handle the data and return */
+/* with a nonzero code if the data could be worked (or even thrown away), if */
+/* no room to buffer the data is available a zero return tells the card */
+/* to keep the data until later. */
+/*****************************************************************************/
+int
+hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan)
+{
+
+ switch (chan) {
+ case CHAN_NDIS_DATA:
+ hysdn_rx_netpkt(card, buf, len); /* give packet to network handler */
+ break;
+
+ case CHAN_ERRLOG:
+ hysdn_card_errlog(card, (tErrLogEntry *) buf, len);
+ if (card->err_log_state == ERRLOG_STATE_ON)
+ card->err_log_state = ERRLOG_STATE_START; /* start new fetch */
+ break;
+
+ default:
+ printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len);
+ break;
+
+ } /* switch rx channel */
+
+ return (1); /* always handled */
+} /* hysdn_sched_rx */
+
+/*****************************************************************************/
+/* hysdn_sched_tx is called from the cards handler to announce that there is */
+/* room in the tx-buffer to the card and data may be sent if needed. */
+/* If the routine wants to send data it must fill buf, len and chan with the */
+/* appropriate data and return a nonzero value. With a zero return no new */
+/* data to send is assumed. maxlen specifies the buffer size available for */
+/* sending. */
+/*****************************************************************************/
+int
+hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile *chan, word maxlen)
+{
+ struct sk_buff *skb;
+
+ if (card->net_tx_busy) {
+ card->net_tx_busy = 0; /* reset flag */
+ hysdn_tx_netack(card); /* acknowledge packet send */
+ } /* a network packet has completely been transferred */
+ /* first of all async requests are handled */
+ if (card->async_busy) {
+ if (card->async_len <= maxlen) {
+ memcpy(buf, card->async_data, card->async_len);
+ *len = card->async_len;
+ *chan = card->async_channel;
+ card->async_busy = 0; /* reset request */
+ return (1);
+ }
+ card->async_busy = 0; /* in case of length error */
+ } /* async request */
+ if ((card->err_log_state == ERRLOG_STATE_START) &&
+ (maxlen >= ERRLOG_CMD_REQ_SIZE)) {
+ strcpy(buf, ERRLOG_CMD_REQ); /* copy the command */
+ *len = ERRLOG_CMD_REQ_SIZE; /* buffer length */
+ *chan = CHAN_ERRLOG; /* and channel */
+ card->err_log_state = ERRLOG_STATE_ON; /* new state is on */
+ return (1); /* tell that data should be send */
+ } /* error log start and able to send */
+ if ((card->err_log_state == ERRLOG_STATE_STOP) &&
+ (maxlen >= ERRLOG_CMD_STOP_SIZE)) {
+ strcpy(buf, ERRLOG_CMD_STOP); /* copy the command */
+ *len = ERRLOG_CMD_STOP_SIZE; /* buffer length */
+ *chan = CHAN_ERRLOG; /* and channel */
+ card->err_log_state = ERRLOG_STATE_OFF; /* new state is off */
+ return (1); /* tell that data should be send */
+ } /* error log start and able to send */
+ /* now handle network interface packets */
+ if ((skb = hysdn_tx_netget(card)) != NULL) {
+ if (skb->len <= maxlen) {
+ memcpy(buf, skb->data, skb->len); /* copy the packet to the buffer */
+ *len = skb->len;
+ *chan = CHAN_NDIS_DATA;
+ card->net_tx_busy = 1; /* we are busy sending network data */
+ return (1); /* go and send the data */
+ } else
+ hysdn_tx_netack(card); /* aknowledge packet -> throw away */
+ } /* send a network packet if available */
+ return (0); /* nothing to send */
+} /* hysdn_sched_tx */
+
+
+/*****************************************************************************/
+/* send one config line to the card and return 0 if successfull, otherwise a */
+/* negative error code. */
+/* The function works with timeouts perhaps not giving the greatest speed */
+/* sending the line, but this should be meaningless beacuse only some lines */
+/* are to be sent and this happens very seldom. */
+/*****************************************************************************/
+int
+hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan)
+{
+ int cnt = 50; /* timeout intervalls */
+ ulong flags;
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
+
+ save_flags(flags);
+ cli();
+ while (card->async_busy) {
+ sti();
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg delayed");
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+ if (!--cnt) {
+ restore_flags(flags);
+ return (-ERR_ASYNC_TIME); /* timed out */
+ }
+ cli();
+ } /* wait for buffer to become free */
+
+ strcpy(card->async_data, line);
+ card->async_len = strlen(line) + 1;
+ card->async_channel = chan;
+ card->async_busy = 1; /* request transfer */
+
+ /* now queue the task */
+ queue_task(&card->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ sti();
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg data queued");
+
+ cnt++; /* short delay */
+ cli();
+
+ while (card->async_busy) {
+ sti();
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+ if (!--cnt) {
+ restore_flags(flags);
+ return (-ERR_ASYNC_TIME); /* timed out */
+ }
+ cli();
+ } /* wait for buffer to become free again */
+
+ restore_flags(flags);
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg data send");
+
+ return (0); /* line send correctly */
+} /* hysdn_tx_cfgline */
diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/isdn/hysdn/ince1pc.h
new file mode 100644
index 000000000..c22974d85
--- /dev/null
+++ b/drivers/isdn/hysdn/ince1pc.h
@@ -0,0 +1,132 @@
+#ifndef __INCE1PC_H__
+#define __INCE1PC_H__
+
+/****************************************************************************
+
+ FILE: ince1pc.h
+
+ AUTHOR: M.Steinkopf
+
+ PURPOSE: common definitions for both sides of the bus:
+ - conventions both spoolers must know
+ - channel numbers agreed upon
+
+*****************************************************************************/
+
+/* basic scalar definitions have same meanning,
+ * but their declaration location depends on environment
+ */
+
+/*--------------------------------------channel numbers---------------------*/
+#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */
+#define CHAN_ERRLOG 0x0005 /* error logger */
+#define CHAN_CAPI 0x0064 /* CAPI interface */
+#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */
+
+/*--------------------------------------POF ready msg-----------------------*/
+ /* NOTE: after booting POF sends system ready message to PC: */
+#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */
+#define RDY_MAGIC_SIZE 4 /* size in bytes */
+
+#define MAX_N_TOK_BYTES 255
+
+#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE
+#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
+
+#define SYSR_TOK_END 0
+#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */
+#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */
+#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */
+#define SYSR_TOK_ESC 255 /* undefined data size yet */
+ /* default values, if not corrected by token: */
+#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */
+#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */
+
+/* syntax of new SYSR token stream:
+ * channel: CHAN_SYSTEM
+ * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE
+ * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
+ * msg : 0 1 2 3 {4 5 6 ..}
+ * S Y S R MAX_N_TOK_BYTES bytes of TokenStream
+ *
+ * TokenStream := empty
+ * | {NonEndTokenChunk} EndToken RotlCRC
+ * NonEndTokenChunk:= NonEndTokenId DataLen [Data]
+ * NonEndTokenId := 0x01 .. 0xFE 1 BYTE
+ * DataLen := 0x00 .. 0xFF 1 BYTE
+ * Data := DataLen bytes
+ * EndToken := 0x00
+ * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes
+ * s. RotlCRC algorithm
+ *
+ * RotlCRC algorithm:
+ * ucSum= 0 1 uchar
+ * for all NonEndTokenChunk bytes:
+ * ROTL(ucSum,1) rotate left by 1
+ * ucSum += Char; add current byte with swap around
+ * RotlCRC= ~ucSum; invert all bits for result
+ *
+ * note:
+ * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes!
+ */
+
+/*--------------------------------------error logger------------------------*/
+ /* note: pof needs final 0 ! */
+#define ERRLOG_CMD_REQ "ERRLOG ON"
+#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */
+#define ERRLOG_CMD_STOP "ERRLOG OFF"
+#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */
+
+#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */
+ /* remaining text size = 55 */
+#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1)
+
+typedef struct ErrLogEntry_tag {
+
+/*00 */ ulong ulErrType;
+
+/*04 */ ulong ulErrSubtype;
+
+/*08 */ uchar ucTextSize;
+
+ /*09 */ uchar ucText[ERRLOG_TEXT_SIZE];
+ /* ASCIIZ of len ucTextSize-1 */
+
+/*40 */
+} tErrLogEntry;
+
+
+#if defined(__TURBOC__)
+#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE
+#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE
+#endif /* */
+#endif /* */
+
+/*--------------------------------------DPRAM boot spooler------------------*/
+ /* this is the struture used between pc and
+ * hyperstone to exchange boot data
+ */
+#define DPRAM_SPOOLER_DATA_SIZE 0x20
+typedef struct DpramBootSpooler_tag {
+
+/*00 */ uchar Len;
+
+/*01 */ volatile uchar RdPtr;
+
+/*02 */ uchar WrPtr;
+
+/*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE];
+
+/*23 */
+} tDpramBootSpooler;
+
+
+#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */
+#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */
+
+/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/
+ /* at DPRAM offset 0x1C00: */
+#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */
+
+
+#endif /* __INCE1PC_H__ */
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index 1626fa4e9..f1df11f55 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.93 1999/11/04 13:11:36 keil Exp $
+/* $Id: isdn_common.c,v 1.97 2000/01/23 18:45:37 keil Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -21,6 +21,32 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.97 2000/01/23 18:45:37 keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
+ * Revision 1.96 2000/01/20 19:55:33 keil
+ * Add FAX Class 1 support
+ *
+ * Revision 1.95 2000/01/09 20:43:13 detabc
+ * exand logical bind-group's for both call's (in and out).
+ * add first part of kernel-config-help for abc-extension.
+ *
+ * Revision 1.94 1999/11/20 22:14:13 detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * to many connection's in short time.
+ * config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * or remote side.
+ * wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
* Revision 1.93 1999/11/04 13:11:36 keil
* Reinit of v110 structs
*
@@ -410,13 +436,14 @@
#endif CONFIG_ISDN_DIVERSION
#include "isdn_v110.h"
#include "isdn_cards.h"
+#include <linux/devfs_fs_kernel.h>
/* Debugflags */
#undef ISDN_DEBUG_STATCALLB
isdn_dev *dev = (isdn_dev *) 0;
-static char *isdn_revision = "$Revision: 1.93 $";
+static char *isdn_revision = "$Revision: 1.97 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
@@ -438,6 +465,9 @@ isdn_divert_if *divert_if = NULL; /* interface to diversion module */
static int isdn_writebuf_stub(int, int, const u_char *, int, int);
+static void set_global_features(void);
+static void isdn_register_devfs(int);
+static void isdn_unregister_devfs(int);
void
isdn_MOD_INC_USE_COUNT(void)
@@ -720,29 +750,33 @@ isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
int
isdn_command(isdn_ctrl *cmd)
{
+ if (cmd->driver == -1) {
+ printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
+ return(1);
+ }
if (cmd->command == ISDN_CMD_SETL2) {
- int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
- unsigned long l2prot = (cmd->arg >> 8) & 255;
- unsigned long features = (dev->drv[cmd->driver]->interface->features
- >> ISDN_FEATURE_L2_SHIFT) &
- ISDN_FEATURE_L2_MASK;
- unsigned long l2_feature = (1 << l2prot);
-
- switch (l2prot) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- /* If V.110 requested, but not supported by
- * HL-driver, set emulator-flag and change
- * Layer-2 to transparent
- */
- if (!(features & l2_feature)) {
- dev->v110emu[idx] = l2prot;
- cmd->arg = (cmd->arg & 255) |
- (ISDN_PROTO_L2_TRANS << 8);
- } else
- dev->v110emu[idx] = 0;
- }
+ int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
+ unsigned long l2prot = (cmd->arg >> 8) & 255;
+ unsigned long features = (dev->drv[cmd->driver]->interface->features
+ >> ISDN_FEATURE_L2_SHIFT) &
+ ISDN_FEATURE_L2_MASK;
+ unsigned long l2_feature = (1 << l2prot);
+
+ switch (l2prot) {
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
+ /* If V.110 requested, but not supported by
+ * HL-driver, set emulator-flag and change
+ * Layer-2 to transparent
+ */
+ if (!(features & l2_feature)) {
+ dev->v110emu[idx] = l2prot;
+ cmd->arg = (cmd->arg & 255) |
+ (ISDN_PROTO_L2_TRANS << 8);
+ } else
+ dev->v110emu[idx] = 0;
+ }
}
return dev->drv[cmd->driver]->interface->command(cmd);
}
@@ -822,6 +856,7 @@ isdn_status_callback(isdn_ctrl * c)
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (dev->drvmap[i] == di)
isdn_all_eaz(di, dev->chanmap[i]);
+ set_global_features();
break;
case ISDN_STAT_STOP:
dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
@@ -1065,6 +1100,7 @@ isdn_status_callback(isdn_ctrl * c)
dev->drvmap[i] = -1;
dev->chanmap[i] = -1;
dev->usage[i] &= ~ISDN_USAGE_DISABLED;
+ isdn_unregister_devfs(i);
}
dev->drivers--;
dev->channels -= dev->drv[di]->channels;
@@ -1078,6 +1114,7 @@ isdn_status_callback(isdn_ctrl * c)
dev->drv[di] = NULL;
dev->drvid[di][0] = '\0';
isdn_info_update();
+ set_global_features();
restore_flags(flags);
return 0;
case ISDN_STAT_L1ERR:
@@ -1563,6 +1600,9 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
* are serialized by means of a semaphore.
*/
switch (cmd) {
+ case IIOCNETDWRSET:
+ printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
+ return(-EINVAL);
case IIOCNETLCR:
printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
return -ENODEV;
@@ -1854,7 +1894,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
for (i = 0; i < 10; i++) {
sprintf(bname, "%s%s",
strlen(dev->drv[drvidx]->msn2eaz[i]) ?
- dev->drv[drvidx]->msn2eaz[i] : "-",
+ dev->drv[drvidx]->msn2eaz[i] : "_",
(i < 9) ? "," : "\0");
if (copy_to_user(p, bname, strlen(bname) + 1))
return -EFAULT;
@@ -2024,13 +2064,17 @@ isdn_close(struct inode *ino, struct file *filep)
static struct file_operations isdn_fops =
{
- llseek: isdn_lseek,
- read: isdn_read,
- write: isdn_write,
- poll: isdn_poll,
- ioctl: isdn_ioctl,
- open: isdn_open,
- release: isdn_close,
+ isdn_lseek,
+ isdn_read,
+ isdn_write,
+ NULL, /* isdn_readdir */
+ isdn_poll, /* isdn_poll */
+ isdn_ioctl, /* isdn_ioctl */
+ NULL, /* isdn_mmap */
+ isdn_open,
+ NULL, /* flush */
+ isdn_close,
+ NULL /* fsync */
};
char *
@@ -2056,7 +2100,7 @@ isdn_map_eaz2msn(char *msn, int di)
int
isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
- ,int pre_chan)
+ ,int pre_chan, char *msn)
{
int i;
ulong flags;
@@ -2079,6 +2123,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 (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
+ continue;
if (dev->usage[i] & ISDN_USAGE_DISABLED)
continue; /* usage not allowed */
if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
@@ -2349,6 +2395,7 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
if (dev->chanmap[k] < 0) {
dev->chanmap[k] = j;
dev->drvmap[k] = drvidx;
+ isdn_register_devfs(k);
break;
}
restore_flags(flags);
@@ -2360,6 +2407,19 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
* Low-level-driver registration
*/
+static void
+set_global_features(void)
+{
+ int drvidx;
+
+ dev->global_features = 0;
+ for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
+ if (!dev->drv[drvidx])
+ continue;
+ if (dev->drv[drvidx]->interface)
+ dev->global_features |= dev->drv[drvidx]->interface->features;
+ }
+}
#ifdef CONFIG_ISDN_DIVERSION
extern isdn_divert_if *divert_if;
@@ -2473,6 +2533,7 @@ register_isdn(isdn_if * i)
strcpy(dev->drvid[drvidx], i->id);
isdn_info_update();
dev->drivers++;
+ set_global_features();
restore_flags(flags);
return 1;
}
@@ -2504,6 +2565,96 @@ isdn_getrev(const char *revision)
return rev;
}
+#ifdef CONFIG_DEVFS_FS
+
+static devfs_handle_t devfs_handle = NULL;
+
+static void isdn_register_devfs(int k)
+{
+ char buf[11];
+
+ sprintf (buf, "isdn%d", k);
+ dev->devfs_handle_isdnX[k] =
+ devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_B + k,0600 | S_IFCHR, 0, 0,
+ &isdn_fops, NULL);
+ sprintf (buf, "isdnctrl%d", k);
+ dev->devfs_handle_isdnctrlX[k] =
+ devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_CTRL + k, 0600 | S_IFCHR,
+ 0, 0, &isdn_fops, NULL);
+}
+
+static void isdn_unregister_devfs(int k)
+{
+ devfs_unregister (dev->devfs_handle_isdnX[k]);
+ devfs_unregister (dev->devfs_handle_isdnctrlX[k]);
+}
+
+static void isdn_init_devfs(void)
+{
+# ifdef CONFIG_ISDN_PPP
+ int i;
+# endif
+
+ devfs_handle = devfs_mk_dir (NULL, "isdn", 4, NULL);
+# ifdef CONFIG_ISDN_PPP
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ char buf[8];
+
+ sprintf (buf, "ippp%d", i);
+ dev->devfs_handle_ipppX[i] =
+ devfs_register (devfs_handle, buf, 0, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_PPP + i,
+ 0600 | S_IFCHR, 0, 0, &isdn_fops, NULL);
+ }
+# endif
+
+ dev->devfs_handle_isdninfo =
+ devfs_register (devfs_handle, "isdninfo", 0, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_STATUS, 0600 | S_IFCHR,
+ 0, 0, &isdn_fops, NULL);
+ dev->devfs_handle_isdnctrl =
+ devfs_register (devfs_handle, "isdnctrl", 0, DEVFS_FL_DEFAULT,
+ ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, 0, 0,
+ &isdn_fops, NULL);
+}
+
+static void isdn_cleanup_devfs(void)
+{
+# ifdef CONFIG_ISDN_PPP
+ int i;
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ devfs_unregister (dev->devfs_handle_ipppX[i]);
+# endif
+ devfs_unregister (dev->devfs_handle_isdninfo);
+ devfs_unregister (dev->devfs_handle_isdnctrl);
+ devfs_unregister (devfs_handle);
+}
+
+#else /* CONFIG_DEVFS_FS */
+static void isdn_register_devfs(int dummy)
+{
+ return;
+}
+
+static void isdn_unregister_devfs(int dummy)
+{
+ return;
+}
+
+static void isdn_init_devfs(void)
+{
+ return;
+}
+
+static void isdn_cleanup_devfs(void)
+{
+ return;
+}
+
+#endif /* CONFIG_DEVFS_FS */
+
/*
* Allocate and initialize all data, register modem-devices
*/
@@ -2530,11 +2681,12 @@ isdn_init(void)
init_waitqueue_head(&dev->mdm.info[i].open_wait);
init_waitqueue_head(&dev->mdm.info[i].close_wait);
}
- if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
+ if (devfs_register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
printk(KERN_WARNING "isdn: Could not register control devices\n");
vfree(dev);
return -EIO;
}
+ isdn_init_devfs();
if ((i = isdn_tty_modem_init()) < 0) {
printk(KERN_WARNING "isdn: Could not register tty devices\n");
if (i == -3)
@@ -2542,7 +2694,8 @@ isdn_init(void)
if (i <= -2)
tty_unregister_driver(&dev->mdm.tty_modem);
vfree(dev);
- unregister_chrdev(ISDN_MAJOR, "isdn");
+ isdn_cleanup_devfs();
+ devfs_unregister_chrdev(ISDN_MAJOR, "isdn");
return -EIO;
}
#ifdef CONFIG_ISDN_PPP
@@ -2552,7 +2705,8 @@ isdn_init(void)
tty_unregister_driver(&dev->mdm.cua_modem);
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
kfree(dev->mdm.info[i].xmit_buf - 4);
- unregister_chrdev(ISDN_MAJOR, "isdn");
+ isdn_cleanup_devfs();
+ devfs_unregister_chrdev(ISDN_MAJOR, "isdn");
vfree(dev);
return -EIO;
}
@@ -2618,9 +2772,10 @@ cleanup_module(void)
kfree(dev->mdm.info[i].fax);
#endif
}
- if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
+ if (devfs_unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
} else {
+ isdn_cleanup_devfs();
del_timer(&dev->timer);
vfree(dev);
printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
diff --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h
index 3c60d7c80..c45dd5202 100644
--- a/drivers/isdn/isdn_common.h
+++ b/drivers/isdn/isdn_common.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.h,v 1.17 1999/10/27 21:21:17 detabc Exp $
+/* $Id: isdn_common.h,v 1.18 2000/01/23 18:45:37 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.18 2000/01/23 18:45:37 keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
* Revision 1.17 1999/10/27 21:21:17 detabc
* Added support for building logically-bind-group's per interface.
* usefull for outgoing call's with more then one isdn-card.
@@ -128,7 +131,7 @@ extern void isdn_timer_ctrl(int tf, int onoff);
extern void isdn_unexclusive_channel(int di, int ch);
extern int isdn_getnum(char **);
extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
-extern int isdn_get_free_channel(int, int, int, int, int);
+extern int isdn_get_free_channel(int, int, int, int, int, char *);
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
extern int register_isdn(isdn_if * i);
extern int isdn_wildmat(char *, char *);
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index e1c7cb75d..592d20ed9 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.95 1999/10/27 21:21:17 detabc Exp $
+/* $Id: isdn_net.c,v 1.107 2000/02/13 09:52:05 kai Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -21,6 +21,66 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.107 2000/02/13 09:52:05 kai
+ * increased TX_TIMEOUT to 20sec
+ *
+ * Revision 1.106 2000/02/12 19:26:55 kai
+ * adopted to latest 2.3 softnet changes.
+ *
+ * tested with PPP and MPPP, it works here.
+ * can somebody check raw-ip?
+ *
+ * also changed std2kern, stddiff for bash-1 compatibility,
+ * hope this doesn't break anything.
+ *
+ * Revision 1.105 2000/02/12 11:43:26 he
+ * SOFTNET related changes, first try. Compatible with linux 2.2.x, but
+ * not tested for kernels with softnet (>= 2.3.43) yet.
+ *
+ * Revision 1.104 2000/02/06 21:49:59 detabc
+ * add rewriting of socket's and frame's saddr for udp-ipv4 dynip-connections.
+ * Include checksum-recompute of ip- and udp-header's.
+ *
+ * Revision 1.103 2000/01/23 18:45:37 keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
+ * Revision 1.102 2000/01/09 20:43:14 detabc
+ * exand logical bind-group's for both call's (in and out).
+ * add first part of kernel-config-help for abc-extension.
+ *
+ * Revision 1.101 1999/12/05 16:06:08 detabc
+ * add resethandling for rawip-compression.
+ * at now all B2-Protocols are usable with rawip-compression
+ *
+ * Revision 1.100 1999/12/04 15:05:25 detabc
+ * bugfix abc-rawip-bsdcompress with channel-bundeling
+ *
+ * Revision 1.99 1999/11/30 11:29:06 detabc
+ * add a on the fly frame-counter and limit
+ *
+ * Revision 1.98 1999/11/28 14:49:07 detabc
+ * In case of rawip-compress adjust dev[x]->ibytes/obytes to reflect the
+ * uncompressed size.
+ *
+ * Revision 1.97 1999/11/26 15:54:59 detabc
+ * added compression (isdn_bsdcompress) for rawip interfaces with x75i B2-protocol.
+ *
+ * Revision 1.96 1999/11/20 22:14:13 detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * to many connection's in short time.
+ * config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * or remote side.
+ * wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
* Revision 1.95 1999/10/27 21:21:17 detabc
* Added support for building logically-bind-group's per interface.
* usefull for outgoing call's with more then one isdn-card.
@@ -393,10 +453,6 @@
#endif
-#ifndef ISDN_NEW_TBUSY
-#define ISDN_NEW_TBUSY
-#endif
-#ifdef ISDN_NEW_TBUSY
/*
* Outline of new tbusy handling:
*
@@ -413,29 +469,60 @@
*/
/*
- * Tell upper layers that the network device is ready to xmit more frames.
+ * About SOFTNET:
+ * Most of the changes were pretty obvious and basically done by HE already.
+ *
+ * One problem of the isdn net device code is that is uses struct net_device
+ * for masters and slaves. However, only master interface are registered to
+ * the network layer, and therefore, it only makes sense to call netif_*
+ * functions on them.
+ *
+ * The old code abused the slaves dev->start to remember the corresponding
+ * master's interface state (ifup'ed or not). This does not work with SOFTNET
+ * any more, because there's now dev->start anymore.
+ * Instead I chose to add isdn_net_started() which gives the state of the
+ * master in case of slaves.
+ * I'm still not sure if this is how it's supposed to be done this way
+ * because it uses netif_running(dev) which might be
+ * considered private to the network layer. However, it works for now.
+ * Alternative: set a flag in _open() and clear it in _close()
+ *
+ * I left some dead code around in #if 0 which I'm not absolutely sure about.
+ * If no problems turn up, it should be removed later
+ *
+ * --KG
*/
-static void __inline__ isdn_net_dev_xon(struct net_device * dev)
-{
- dev->tbusy = 0;
- mark_bh(NET_BH);
-}
-static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
+/*
+ * Find out if the netdevice has been ifup-ed yet.
+ * For slaves, look at the corresponding master.
+ */
+static int __inline__ isdn_net_started(isdn_net_dev *n)
{
- lp->netdev->dev.tbusy = 0;
- if(lp->master) lp->master->tbusy = 0;
- mark_bh(NET_BH);
+ isdn_net_local *lp = n->local;
+ struct net_device *dev;
+
+ if (lp->master)
+ dev = lp->master;
+ else
+ dev = &n->dev;
+ return netif_running(dev);
}
/*
- * Ask upper layers to temporarily cease passing us more xmit frames.
+ * wake up the network -> net_device queue.
+ * For slaves, wake the corresponding master interface.
*/
-static void __inline__ isdn_net_dev_xoff(struct net_device * dev)
+static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
{
- dev->tbusy = 1;
+ if (lp->master)
+ netif_wake_queue(lp->master);
+ else
+ netif_wake_queue(&lp->netdev->dev);
}
-#endif
+
+
+#define ISDN_NET_TX_TIMEOUT (20*HZ)
/* Prototypes */
@@ -443,7 +530,7 @@ int isdn_net_force_dial_lp(isdn_net_local *);
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.95 $";
+char *isdn_net_revision = "$Revision: 1.107 $";
/*
* Code for raw-networking over ISDN
@@ -482,14 +569,9 @@ isdn_net_reset(struct net_device *dev)
#endif
ulong flags;
+ /* not sure if the cli() is needed at all --KG */
save_flags(flags);
cli(); /* Avoid glitch on writes to CMD regs */
- dev->interrupt = 0;
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xon(dev);
-#else
- dev->tbusy = 0;
-#endif
#ifdef CONFIG_ISDN_X25
if( cprot && cprot -> pops && dops )
cprot -> pops -> restart ( cprot, dev, dops );
@@ -505,8 +587,12 @@ isdn_net_open(struct net_device *dev)
struct net_device *p;
struct in_device *in_dev;
+ /* moved here from isdn_net_reset, because only the master has an
+ interface associated which is supposed to be started. BTW:
+ we need to call netif_start_queue, not netif_wake_queue here */
+ netif_start_queue(dev);
+
isdn_net_reset(dev);
- dev->start = 1;
/* Fill in the MAC-level header (not needed, but for compatibility... */
for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
dev->dev_addr[i] = 0xfc;
@@ -524,7 +610,6 @@ isdn_net_open(struct net_device *dev)
if ((p = (((isdn_net_local *) dev->priv)->slave))) {
while (p) {
isdn_net_reset(p);
- p->start = 1;
p = (((isdn_net_local *) p->priv)->slave);
}
}
@@ -703,19 +788,11 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
mdev = &lp->netdev->dev;
if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
lp->sav_skb = NULL;
-#ifndef ISDN_NEW_TBUSY
- mark_bh(NET_BH);
-#endif
} else {
return 1;
}
}
-#ifdef ISDN_NEW_TBUSY
isdn_net_lp_xon(lp);
-#else
- if (test_and_clear_bit(0, (void *) &(p->dev.tbusy)))
- mark_bh(NET_BH);
-#endif
}
return 1;
case ISDN_STAT_DCONN:
@@ -814,18 +891,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
lp->first_skb = NULL;
}
-#ifdef ISDN_NEW_TBUSY
if(! lp->first_skb) isdn_net_lp_xon(lp);
-#else
- else {
- /*
- * dev.tbusy is usually cleared implicitly by isdn_net_xmit(,,lp->first_skb).
- * With an empty lp->first_skb, we need to do this ourselves
- */
- lp->netdev->dev.tbusy = 0;
- mark_bh(NET_BH);
- }
-#endif /* ISDN_NEW_TBUSY */
return 1;
}
break;
@@ -1259,14 +1325,16 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
strcpy(addinfo, " IDP");
break;
}
- printk(KERN_INFO "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
+ printk(KERN_INFO
+ "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
p[12], p[13], p[14], p[15],
p[16], p[17], p[18], p[19],
addinfo);
break;
case ETH_P_ARP:
- printk(KERN_INFO "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
+ printk(KERN_INFO
+ "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
p[14], p[15], p[16], p[17],
p[24], p[25], p[26], p[27]);
break;
@@ -1280,14 +1348,8 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
*
* Return: 0 on success, !0 on failure.
*/
-#ifndef ISDN_NEW_TBUSY
-/*
- * Side-effects: ndev->tbusy is cleared on success.
- */
-#endif
-int
-isdn_net_send_skb(struct net_device *ndev, isdn_net_local * lp,
- struct sk_buff *skb)
+int isdn_net_send_skb
+ (struct net_device *ndev, isdn_net_local * lp,struct sk_buff *skb)
{
int ret;
int len = skb->len; /* save len */
@@ -1295,17 +1357,11 @@ isdn_net_send_skb(struct net_device *ndev, isdn_net_local * lp,
ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
if (ret == len) {
lp->transcount += len;
-#ifndef ISDN_NEW_TBUSY
- clear_bit(0, (void *) &(ndev->tbusy));
-#endif
return 0;
}
if (ret < 0) {
dev_kfree_skb(skb);
lp->stats.tx_errors++;
-#ifndef ISDN_NEW_TBUSY
- clear_bit(0, (void *) &(ndev->tbusy));
-#endif
return 0;
}
return 1;
@@ -1351,11 +1407,7 @@ isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb)
if (lp->srobin == ndev)
ret = isdn_net_send_skb(ndev, lp, skb);
else
-#ifdef ISDN_NEW_TBUSY
ret = isdn_net_start_xmit(skb, lp->srobin);
-#else
- ret = ndev->tbusy = isdn_net_start_xmit(skb, lp->srobin);
-#endif
lp->srobin = (slp->slave) ? slp->slave : ndev;
slp = (isdn_net_local *) (lp->srobin->priv);
if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0)))
@@ -1397,6 +1449,35 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
}
}
+
+void isdn_net_tx_timeout(struct net_device * ndev)
+{
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+
+ printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
+ if (!lp->dialstate){
+ lp->stats.tx_errors++;
+ /*
+ * There is a certain probability that this currently
+ * works at all because if we always wake up the interface,
+ * then upper layer will try to send the next packet
+ * immediately. And then, the old clean_up logic in the
+ * driver will hopefully continue to work as it used to do.
+ *
+ * This is rather primitive right know, we better should
+ * clean internal queues here, in particular for multilink and
+ * ppp, and reset HL driver's channel, too. --HE
+ *
+ * actually, this may not matter at all, because ISDN hardware
+ * should not see transmitter hangs at all IMO
+ * changed KERN_DEBUG to KERN_WARNING to find out if this is
+ * ever called
+ */
+ }
+ ndev->trans_start = jiffies;
+ netif_wake_queue(ndev);
+}
+
/*
* Try sending a packet.
* If this interface isn't connected to a ISDN-Channel, find a free channel,
@@ -1409,19 +1490,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = lp -> netdev -> cprot;
#endif
- if (ndev->tbusy) {
- if (jiffies - ndev->trans_start < (2 * HZ))
- return 1;
- if (!lp->dialstate)
- lp->stats.tx_errors++;
- ndev->trans_start = jiffies;
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xon(ndev);
-#endif
- }
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */
-#endif
#ifdef CONFIG_ISDN_X25
/* At this point hard_start_xmit() passes control to the encapsulation
protocol (if present).
@@ -1436,9 +1504,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
if( cprot ) {
int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
-#ifdef ISDN_NEW_TBUSY
- if(ret) isdn_net_dev_xoff(ndev);
-#endif
+ if(ret) netif_stop_queue(ndev);
return ret;
} else
#endif
@@ -1458,9 +1524,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
return 0;
}
if (lp->phone[1]) {
@@ -1476,15 +1539,11 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if(jiffies < lp->dialwait_timer) {
isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
restore_flags(flags);
return 0;
} else
lp->dialwait_timer = 0;
}
-
/* Grab a free ISDN-Channel */
if (((chi =
isdn_get_free_channel(
@@ -1492,7 +1551,8 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
lp->l2_proto,
lp->l3_proto,
lp->pre_device,
- lp->pre_channel)
+ lp->pre_channel,
+ lp->msn)
) < 0) &&
((chi =
isdn_get_free_channel(
@@ -1500,15 +1560,13 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
lp->l2_proto,
lp->l3_proto,
lp->pre_device,
- lp->pre_channel^1)
+ lp->pre_channel^1,
+ lp->msn)
) < 0)) {
restore_flags(flags);
isdn_net_unreachable(ndev, skb,
"No channel");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
return 0;
}
/* Log packet, which triggered dialing */
@@ -1528,9 +1586,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
restore_flags(flags);
isdn_net_dial(); /* Initiate dialing */
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xoff(ndev);
-#endif
+ netif_stop_queue(ndev);
return 1; /* let upper layer requeue skb packet */
}
#endif
@@ -1544,9 +1600,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
lp->first_skb = skb;
/* Initiate dialing */
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
restore_flags(flags);
isdn_net_dial();
return 0;
@@ -1554,9 +1607,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
isdn_net_unreachable(ndev, skb,
"No phone number");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
return 0;
}
} else {
@@ -1567,24 +1617,16 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
int ret;
if (lp->first_skb) {
if (isdn_net_xmit(ndev, lp, lp->first_skb)){
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xoff(ndev);
-#endif
+ netif_stop_queue(ndev);
return 1;
}
lp->first_skb = NULL;
}
ret = (isdn_net_xmit(ndev, lp, skb));
-#ifdef ISDN_NEW_TBUSY
- if(ret) isdn_net_dev_xoff(ndev);
-#endif
+ if(ret) netif_stop_queue(ndev);
return ret;
} else
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xoff(ndev);
-#else
- ndev->tbusy = 1;
-#endif
+ netif_stop_queue(ndev);
}
}
return 1;
@@ -1606,8 +1648,7 @@ isdn_net_close(struct net_device *dev)
#ifdef CONFIG_ISDN_X25
if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
#endif
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
if ((p = (((isdn_net_local *) dev->priv)->slave))) {
/* If this interface has slaves, stop them also */
while (p) {
@@ -1618,8 +1659,6 @@ isdn_net_close(struct net_device *dev)
cprot -> pops -> close( cprot );
#endif
isdn_net_hangup(p);
- p->tbusy = 1;
- p->start = 0;
p = (((isdn_net_local *) p->priv)->slave);
}
}
@@ -2360,7 +2399,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
* Is the interface up?
* If not, reject the call actively.
*/
- if (!p->dev.start) {
+ if (!isdn_net_started(p)) {
restore_flags(flags);
printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
lp->name);
@@ -2389,7 +2428,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
p = (isdn_net_dev *) p->next;
continue;
}
- }
+ }
if (lp->flags & ISDN_NET_CALLBACK) {
int chi;
/*
@@ -2411,9 +2450,10 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
isdn_get_free_channel(
ISDN_USAGE_NET,
lp->l2_proto,
- lp->l3_proto,
+ lp->l3_proto,
lp->pre_device,
- lp->pre_channel)
+ lp->pre_channel,
+ lp->msn)
) < 0) {
printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
@@ -2528,7 +2568,8 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
lp->l2_proto,
lp->l3_proto,
lp->pre_device,
- lp->pre_channel)
+ lp->pre_channel,
+ lp->msn)
) < 0) {
printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
restore_flags(flags);
@@ -2626,11 +2667,13 @@ isdn_net_new(char *name, struct net_device *master)
p = (((isdn_net_local *) p->priv)->slave);
}
((isdn_net_local *) q->priv)->slave = &(netdev->dev);
- q->interrupt = 0;
- q->tbusy = 0;
- q->start = master->start;
} else {
/* Device shall be a master */
+ /*
+ * Watchdog timer (currently) for master only.
+ */
+ netdev->dev.tx_timeout = isdn_net_tx_timeout;
+ netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
if (register_netdev(&netdev->dev) != 0) {
printk(KERN_WARNING "isdn_net: Could not register net-device\n");
kfree(netdev->local);
@@ -2701,7 +2744,7 @@ isdn_net_newslave(char *parm)
if (n->local->master)
return NULL;
/* Master must not be started yet */
- if (n->dev.start)
+ if (isdn_net_started(n))
return NULL;
return (isdn_net_new(newname, &(n->dev)));
}
@@ -2744,9 +2787,8 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = p -> cprot;
#endif
- if (p->dev.start) {
- printk(KERN_WARNING
- "%s: cannot change encap when if is up\n",
+ if (isdn_net_started(p)) {
+ printk(KERN_WARNING "%s: cannot change encap when if is up\n",
lp->name);
return -EBUSY;
}
@@ -2837,10 +2879,9 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
/* If binding is exclusive, try to grab the channel */
save_flags(flags);
- if ((i = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
- lp->l3_proto,
- drvidx,
- chidx)) < 0) {
+ if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
+ lp->l2_proto, lp->l3_proto, drvidx,
+ chidx, lp->msn)) < 0) {
/* Grab failed, because desired channel is in use */
lp->exclusive = -1;
restore_flags(flags);
@@ -3181,14 +3222,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
save_flags(flags);
cli();
- if (p->local->master) {
- /* If it's a slave, it may be removed even if it is busy. However
- * it has to be hung up first.
- */
- isdn_net_hangup(&p->dev);
- p->dev.start = 0;
- }
- if (p->dev.start) {
+ if (isdn_net_started(p)) {
restore_flags(flags);
return -EBUSY;
}
diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c
index 06c2d83ad..2551dc344 100644
--- a/drivers/isdn/isdn_ppp.c
+++ b/drivers/isdn/isdn_ppp.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.60 1999/11/04 20:29:55 he Exp $
+/* $Id: isdn_ppp.c,v 1.62 2000/02/12 19:26:55 kai Exp $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -19,6 +19,31 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.c,v $
+ * Revision 1.62 2000/02/12 19:26:55 kai
+ * adopted to latest 2.3 softnet changes.
+ *
+ * tested with PPP and MPPP, it works here.
+ * can somebody check raw-ip?
+ *
+ * also changed std2kern, stddiff for bash-1 compatibility,
+ * hope this doesn't break anything.
+ *
+ * Revision 1.61 1999/11/20 22:14:14 detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * to many connection's in short time.
+ * config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * or remote side.
+ * wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
* Revision 1.60 1999/11/04 20:29:55 he
* applied Andre Beck's reset_free fix
*
@@ -306,7 +331,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.60 $";
+char *isdn_ppp_revision = "$Revision: 1.62 $";
static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
@@ -699,7 +724,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
case PPPIOCGIFNAME:
if(!lp)
return -EINVAL;
- if ((r = set_arg((void *) arg, lp->name,strlen(lp->name))))
+ if ((r = set_arg((void *) arg, lp->name, strlen(lp->name))))
return r;
break;
case PPPIOCGMPFLAGS: /* get configuration flags */
@@ -721,8 +746,8 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
}
if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
if (lp) {
- lp->netdev->dev.tbusy = 0;
- mark_bh(NET_BH); /* OK .. we are ready to send buffers */
+ /* OK .. we are ready to send buffers */
+ netif_wake_queue(&lp->netdev->dev);
}
}
is->pppcfg = val;
diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c
index 5b301adb9..0503c67a2 100644
--- a/drivers/isdn/isdn_tty.c
+++ b/drivers/isdn/isdn_tty.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.80 1999/11/07 13:34:30 armin Exp $
+/* $Id: isdn_tty.c,v 1.82 2000/01/23 18:45:37 keil Exp $
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
@@ -20,6 +20,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.c,v $
+ * Revision 1.82 2000/01/23 18:45:37 keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
+ * Revision 1.81 2000/01/20 19:55:33 keil
+ * Add FAX Class 1 support
+ *
* Revision 1.80 1999/11/07 13:34:30 armin
* Fixed AT command line editor
*
@@ -348,6 +354,7 @@
#endif
#define FIX_FILE_TRANSFER
+#define DUMMY_HAYES_AT
/* Prototypes */
@@ -372,7 +379,7 @@ static int bit2si[8] =
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.80 $";
+char *isdn_tty_revision = "$Revision: 1.82 $";
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -976,7 +983,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
isdn_tty_modem_result(6, info);
@@ -1187,7 +1194,7 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
isdn_tty_modem_result(6, info);
@@ -1281,7 +1288,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
isdn_tty_modem_result(6, info);
@@ -1555,6 +1562,23 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
}
}
} else
+ if (TTY_IS_FCLASS1(info)) {
+ int cc = isdn_tty_handleDLEdown(info, m, c);
+
+ if (info->vonline & 4) { /* ETX seen */
+ isdn_ctrl c;
+
+ c.command = ISDN_CMD_FAXCMD;
+ c.driver = info->isdn_driver;
+ c.arg = info->isdn_channel;
+ c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL;
+ c.parm.aux.subcmd = ETX;
+ isdn_command(&c);
+ }
+ info->vonline = 0;
+ printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc,c);
+ info->xmit_count += cc;
+ } else
#endif
info->xmit_count += c;
} else {
@@ -2567,7 +2591,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
int
-isdn_tty_stat_callback(int i, isdn_ctrl * c)
+isdn_tty_stat_callback(int i, isdn_ctrl *c)
{
int mi;
modem_info *info;
@@ -2668,8 +2692,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
strcpy(info->emu.connmsg, c->parm.num);
isdn_tty_modem_result(1, info);
- }
- else
+ } else
isdn_tty_modem_result(5, info);
}
if (USG_VOICE(dev->usage[i]))
@@ -2720,7 +2743,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
#ifdef CONFIG_ISDN_TTY_FAX
case ISDN_STAT_FAXIND:
if (TTY_IS_ACTIVE(info)) {
- isdn_tty_fax_command(info);
+ isdn_tty_fax_command(info, c);
}
break;
#endif
@@ -3247,8 +3270,22 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
info->xmit_size /= 10;
}
break;
+ case 'C':
+ /* &C - DCD Status */
+ p[0]++;
+ switch (isdn_getnum(p)) {
+ case 0:
+ m->mdmreg[REG_DCD] &= ~BIT_DCD;
+ break;
+ case 1:
+ m->mdmreg[REG_DCD] |= BIT_DCD;
+ break;
+ default:
+ PARSE_ERROR1
+ }
+ break;
case 'D':
- /* &D - Set DCD-Low-behavior */
+ /* &D - Set DTR-Low-behavior */
p[0]++;
switch (isdn_getnum(p)) {
case 0:
@@ -3280,6 +3317,14 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
isdn_tty_reset_profile(m);
isdn_tty_modem_reset_regs(info, 1);
break;
+#ifdef DUMMY_HAYES_AT
+ case 'K':
+ /* only for be compilant with common scripts */
+ /* &K Flowcontrol - no function */
+ p[0]++;
+ isdn_getnum(p);
+ break;
+#endif
case 'L':
/* &L -Set Numbers to listen on */
p[0]++;
@@ -3565,8 +3610,10 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
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");
+ if (TTY_IS_FCLASS2(info))
+ sprintf(rs, "\r\n2");
+ else if (TTY_IS_FCLASS1(info))
+ sprintf(rs, "\r\n1");
#endif
isdn_tty_at_cout(rs, info);
break;
@@ -3582,11 +3629,25 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
m->mdmreg[REG_PSIZE] * 16;
break;
#ifdef CONFIG_ISDN_TTY_FAX
+ case '1':
+ p[0]++;
+ if (!(dev->global_features &
+ ISDN_FEATURE_L3_FCLASS1))
+ PARSE_ERROR1;
+ m->mdmreg[REG_SI1] = 1;
+ m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
+ m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1;
+ info->xmit_size =
+ m->mdmreg[REG_PSIZE] * 16;
+ break;
case '2':
p[0]++;
+ if (!(dev->global_features &
+ ISDN_FEATURE_L3_FCLASS2))
+ PARSE_ERROR1;
m->mdmreg[REG_SI1] = 1;
m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FAX;
+ m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2;
info->xmit_size =
m->mdmreg[REG_PSIZE] * 16;
break;
@@ -3601,11 +3662,17 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
break;
case '?':
p[0]++;
+ strcpy(rs, "\r\n0,");
#ifdef CONFIG_ISDN_TTY_FAX
- isdn_tty_at_cout("\r\n0,2,8", info);
-#else
- isdn_tty_at_cout("\r\n0,8", info);
+ if (dev->global_features &
+ ISDN_FEATURE_L3_FCLASS1)
+ strcat(rs, "1,");
+ if (dev->global_features &
+ ISDN_FEATURE_L3_FCLASS2)
+ strcat(rs, "2,");
#endif
+ strcat(rs, "8");
+ isdn_tty_at_cout(rs, info);
break;
default:
PARSE_ERROR1;
@@ -3995,6 +4062,15 @@ isdn_tty_parse_at(modem_info * info)
default:
}
break;
+#ifdef DUMMY_HAYES_AT
+ case 'L':
+ case 'M':
+ /* only for be compilant with common scripts */
+ /* no function */
+ p++;
+ isdn_getnum(&p);
+ break;
+#endif
case 'O':
/* O - Go online */
p++;
diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h
index 1c27b8300..ff7e479f0 100644
--- a/drivers/isdn/isdn_tty.h
+++ b/drivers/isdn/isdn_tty.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.h,v 1.17 1999/09/21 19:00:35 armin Exp $
+/* $Id: isdn_tty.h,v 1.18 2000/01/20 19:55:33 keil Exp $
* header for Linux ISDN subsystem, tty related functions (linklevel).
*
@@ -20,6 +20,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.h,v $
+ * Revision 1.18 2000/01/20 19:55:33 keil
+ * Add FAX Class 1 support
+ *
* Revision 1.17 1999/09/21 19:00:35 armin
* Extended FCON message with added CPN
* can now be activated with Bit 1 of Reg 23.
@@ -160,6 +163,13 @@
#define BIT_CPN 1
#define BIT_CPNFCON 2
+#define TTY_IS_FCLASS1(info) \
+ ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
+ (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
+#define TTY_IS_FCLASS2(info) \
+ ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
+ (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
+
extern void isdn_tty_modem_escape(void);
extern void isdn_tty_modem_ring(void);
extern void isdn_tty_carrier_timeout(void);
@@ -175,6 +185,6 @@ 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 int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
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
index 9b7268b32..33f67ff4b 100644
--- a/drivers/isdn/isdn_ttyfax.c
+++ b/drivers/isdn/isdn_ttyfax.c
@@ -1,9 +1,9 @@
-/* $Id: isdn_ttyfax.c,v 1.4 1999/09/21 19:00:35 armin Exp $
+/* $Id: isdn_ttyfax.c,v 1.6 2000/01/26 00:41:13 keil 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
+ * 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
@@ -20,6 +20,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ttyfax.c,v $
+ * Revision 1.6 2000/01/26 00:41:13 keil
+ * add "00" as dummy msn in isdn_get_free_channel call
+ *
+ * Revision 1.5 2000/01/20 19:55:33 keil
+ * Add FAX Class 1 support
+ *
* Revision 1.4 1999/09/21 19:00:35 armin
* Extended FCON message with added CPN
* can now be activated with Bit 1 of Reg 23.
@@ -50,31 +56,32 @@
#include "isdn_ttyfax.h"
-static char *isdn_tty_fax_revision = "$Revision: 1.4 $";
+static char *isdn_tty_fax_revision = "$Revision: 1.6 $";
#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
static char *
isdn_getrev(const char *revision)
{
- char *rev;
- char *p;
+ char *rev;
+ char *p;
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
+ 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)
+
+static void
+isdn_tty_fax_modem_result(int code, modem_info * info)
{
atemu *m = &info->emu;
T30_s *f = info->fax;
@@ -85,7 +92,7 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info)
static char *msg[] =
{"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:",
"+FHNG:", "+FDCS:", "CONNECT", "+FTSI:",
- "+FCFR", "+FPTS:", "+FET:" };
+ "+FCFR", "+FPTS:", "+FET:"};
isdn_tty_at_cout("\r\n", info);
@@ -115,12 +122,12 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info)
case 3: /* +FCSI */
case 8: /* +FTSI */
sprintf(rs, "\"%s\"", f->r_id);
- isdn_tty_at_cout(rs, info);
+ isdn_tty_at_cout(rs, info);
break;
case 4: /* +FDIS */
rs[0] = 0;
rp = &f->r_resolution;
- for(i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++) {
sprintf(rss, "%c%s", rp[i] + 48,
(i < 7) ? "," : "");
strcat(rs, rss);
@@ -128,18 +135,18 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info)
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);
+ rs, info->line);
#endif
break;
case 5: /* +FHNG */
sprintf(rs, "%d", f->code);
- isdn_tty_at_cout(rs, info);
+ 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++) {
+ for (i = 0; i < 8; i++) {
sprintf(rss, "%c%s", rp[i] + 48,
(i < 7) ? "," : "");
strcat(rs, rss);
@@ -147,127 +154,169 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info)
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);
+ rs, info->line);
#endif
break;
case 7: /* CONNECT */
info->faxonline |= 2;
break;
- case 9: /* FCFR */
+ case 9: /* FCFR */
break;
- case 10: /* FPTS */
+ case 10: /* FPTS */
isdn_tty_at_cout("1", info);
break;
- case 11: /* FET */
+ case 11: /* FET */
sprintf(rs, "%d", f->fet);
- isdn_tty_at_cout(rs, info);
+ isdn_tty_at_cout(rs, info);
break;
}
isdn_tty_at_cout("\r\n", info);
switch (code) {
- case 7: /* CONNECT */
+ case 7: /* CONNECT */
info->online = 2;
if (info->faxonline & 1) {
sprintf(rs, "%c", XON);
- isdn_tty_at_cout(rs, info);
+ isdn_tty_at_cout(rs, info);
+ }
+ break;
+ }
+}
+
+int
+isdn_tty_fax_command1(modem_info * info, isdn_ctrl * c)
+{
+ static char *msg[] =
+ {"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"};
+
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd);
+#endif
+ if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) {
+ if (info->online)
+ info->online = 1;
+ isdn_tty_at_cout("\r\n", info);
+ isdn_tty_at_cout(msg[c->parm.aux.cmd], info);
+ isdn_tty_at_cout("\r\n", info);
+ }
+ switch (c->parm.aux.cmd) {
+ case ISDN_FAX_CLASS1_CONNECT:
+ info->online = 2;
+ break;
+ case ISDN_FAX_CLASS1_OK:
+ case ISDN_FAX_CLASS1_FCERROR:
+ case ISDN_FAX_CLASS1_ERROR:
+ case ISDN_FAX_CLASS1_NOCARR:
+ break;
+ case ISDN_FAX_CLASS1_QUERY:
+ isdn_tty_at_cout("\r\n", info);
+ if (!c->parm.aux.para[0]) {
+ isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info);
+ isdn_tty_at_cout("\r\n", info);
+ } else {
+ isdn_tty_at_cout(c->parm.aux.para, info);
+ isdn_tty_at_cout("\r\nOK\r\n", info);
}
break;
}
+ return (0);
}
int
-isdn_tty_fax_command(modem_info * info)
+isdn_tty_fax_command(modem_info * info, isdn_ctrl * c)
{
T30_s *f = info->fax;
char rs[10];
+ if (TTY_IS_FCLASS1(info))
+ return (isdn_tty_fax_command1(info, c));
+
#ifdef ISDN_TTY_FAX_CMD_DEBUG
printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n",
- f->r_code, info->line);
+ f->r_code, info->line);
#endif
- switch(f->r_code) {
+ switch (f->r_code) {
case ISDN_TTY_FAX_FCON:
info->faxonline = 1;
- isdn_tty_fax_modem_result(2, info); /* +FCON */
- return(0);
+ 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);
+ 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 */
+ isdn_tty_fax_modem_result(3, info); /* +FCSI */
if (info->faxonline & 16)
- isdn_tty_fax_modem_result(8, info); /* +FTSI */
- return(0);
+ 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);
+ 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);
+ isdn_tty_at_cout(rs, info);
} else {
sprintf(rs, "%c", 0x18);
- isdn_tty_at_cout(rs, info);
+ isdn_tty_at_cout(rs, info);
}
- info->faxonline &= ~2; /* leave data mode */
+ 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);
+ 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 */
+ isdn_tty_fax_modem_result(6, info); /* +FDCS */
+ isdn_tty_fax_modem_result(7, info); /* CONNECT */
f->phase = ISDN_FAX_PHASE_C;
- return(0);
+ 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);
+ 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);
+ 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);
+ 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 */
+ 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);
+ return (0);
case ISDN_TTY_FAX_PTS:
- isdn_tty_fax_modem_result(10, info); /* +FPTS */
+ 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 */
+ isdn_tty_fax_modem_result(0, info); /* OK */
}
- return(0);
+ return (0);
case ISDN_TTY_FAX_EOP:
- info->faxonline &= ~2; /* leave data mode */
+ info->faxonline &= ~2; /* leave data mode */
info->online = 1;
f->phase = ISDN_FAX_PHASE_D;
- return(0);
+ return (0);
}
- return(-1);
+ return (-1);
}
void
-isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
+isdn_tty_fax_bitorder(modem_info * info, struct sk_buff *skb)
{
__u8 LeftMask;
__u8 RightMask;
@@ -276,13 +325,13 @@ isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
int i;
if (!info->fax->bor) {
- for(i = 0; i < skb->len; i++) {
+ for (i = 0; i < skb->len; i++) {
Data = skb->data[i];
for (
- LeftMask = 0x80, RightMask = 0x01;
- LeftMask > RightMask;
- LeftMask >>= 1, RightMask <<= 1
- ) {
+ LeftMask = 0x80, RightMask = 0x01;
+ LeftMask > RightMask;
+ LeftMask >>= 1, RightMask <<= 1
+ ) {
fBit = (Data & LeftMask);
if (Data & RightMask)
Data |= LeftMask;
@@ -300,10 +349,103 @@ isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
}
/*
+ * Parse AT+F.. FAX class 1 commands
+ */
+
+int
+isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
+{
+ static char *cmd[] =
+ {"AE", "TS", "RS", "TM", "RM", "TH", "RH"};
+ isdn_ctrl c;
+ int par, i;
+ long flags;
+
+ for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
+ if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2))
+ break;
+
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd);
+#endif
+ if (c.parm.aux.cmd == 7)
+ PARSE_ERROR1;
+
+ p[0] += 2;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ c.parm.aux.subcmd = AT_QUERY;
+ break;
+ case '=':
+ p[0]++;
+ if (*p[0] == '?') {
+ p[0]++;
+ c.parm.aux.subcmd = AT_EQ_QUERY;
+ } else {
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ c.parm.aux.subcmd = AT_EQ_VALUE;
+ c.parm.aux.para[0] = par;
+ }
+ break;
+ case 0:
+ c.parm.aux.subcmd = AT_COMMAND;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ c.command = ISDN_CMD_FAXCMD;
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
+ c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
+#endif
+ if (info->isdn_driver < 0) {
+ save_flags(flags);
+ cli();
+ if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
+ (c.parm.aux.subcmd == AT_COMMAND)) {
+ restore_flags(flags);
+ PARSE_ERROR1;
+ }
+ /* get a temporary connection to the first free fax driver */
+ i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
+ ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
+ if (i < 0) {
+ restore_flags(flags);
+ PARSE_ERROR1;
+ }
+ info->isdn_driver = dev->drvmap[i];
+ info->isdn_channel = dev->chanmap[i];
+ info->drv_index = i;
+ dev->m_idx[i] = info->line;
+ c.driver = info->isdn_driver;
+ c.arg = info->isdn_channel;
+ isdn_command(&c);
+ isdn_free_channel(info->isdn_driver, info->isdn_channel,
+ ISDN_USAGE_FAX);
+ info->isdn_driver = -1;
+ info->isdn_channel = -1;
+ if (info->drv_index >= 0) {
+ dev->m_idx[info->drv_index] = -1;
+ info->drv_index = -1;
+ }
+ restore_flags(flags);
+ } else {
+ c.driver = info->isdn_driver;
+ c.arg = info->isdn_channel;
+ isdn_command(&c);
+ }
+ return 1;
+}
+
+/*
* Parse AT+F.. FAX class 2 commands
*/
-int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
+int
+isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
{
atemu *m = &info->emu;
T30_s *f = info->fax;
@@ -311,10 +453,11 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
int par;
char rs[50];
char rss[50];
- int maxdccval[]={1,5,2,2,3,2,0,7};
+ int maxdccval[] =
+ {1, 5, 2, 2, 3, 2, 0, 7};
/* FAA still unchanged */
- if (!strncmp(p[0], "AA", 2)) { /* TODO */
+ if (!strncmp(p[0], "AA", 2)) { /* TODO */
p[0] += 2;
switch (*p[0]) {
case '?':
@@ -332,399 +475,363 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
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;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
- PARSE_ERROR1;
+ PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* BADMUL=value - dummy 0=disable errorchk disabled (treshold multiplier) */
- if (!strncmp(p[0], "BADMUL", 6)){
- p[0] +=6;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* BOR=n - Phase C bit order, 0=direct, 1=reverse */
- if (!strncmp(p[0], "BOR", 3)){
- p[0] +=3;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
/* NBC=n - No Best Capabilities */
- if (!strncmp(p[0], "NBC", 3)){
- p[0] +=3;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
/* BUF? - Readonly buffersize readout */
- if (!strncmp(p[0], "BUF?", 4)) {
- p[0] += 4;
+ 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]));
+ 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;
- }
-
+ 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)) {
+ if (!strncmp(p[0], "CIG", 3)) {
int i, r;
- p[0] += 3;
+ p[0] += 3;
switch (*p[0]) {
case '?':
p[0]++;
sprintf(rs, "\r\n\"%s\"", f->pollid);
- isdn_tty_at_cout(rs, info);
- break;
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ 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;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ 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;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* CTCRTY=value - ECM retry count */
- if (!strncmp(p[0], "CTCRTY", 6)){
- p[0] +=6;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */
- if (!strncmp(p[0], "DCC", 3)) {
+ if (!strncmp(p[0], "DCC", 3)) {
char *rp = &f->resolution;
int i;
- p[0] += 3;
- switch(*p[0]) {
+ 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);
+ 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++) {
+ 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] == ',')
+ if (*p[0] == ',')
p[0]++;
- } else 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]);
+ 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;
- }
-
+ return 0;
+ }
/* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */
- if (!strncmp(p[0], "DIS", 3)) {
+ if (!strncmp(p[0], "DIS", 3)) {
char *rp = &f->resolution;
int i;
- p[0] += 3;
- switch(*p[0]) {
+ 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);
+ 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++) {
+ 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] == ',')
+ if (*p[0] == ',')
p[0]++;
- } else 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]);
+ 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;
+ 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))) {
+ ((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
@@ -735,11 +842,11 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
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) {
+ } 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 */
+ isdn_tty_fax_modem_result(7, info); /* CONNECT */
break;
case 1: /* next doc will be received */
f->phase = ISDN_FAX_PHASE_B;
@@ -747,35 +854,36 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
case 2: /* fax session is terminating */
f->phase = ISDN_FAX_PHASE_E;
break;
- default:
+ default:
PARSE_ERROR1;
}
}
} else {
PARSE_ERROR1;
}
- return 1;
+ 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};
+ 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 */
+ 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++) {
+ 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] == ',')
+ if (*p[0] == ',')
p[0]++;
- } else 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",
@@ -789,48 +897,43 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
isdn_command(&cmd);
if (f->phase == ISDN_FAX_PHASE_D) {
f->phase = ISDN_FAX_PHASE_C;
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
+ isdn_tty_fax_modem_result(7, info); /* CONNECT */
}
} else {
PARSE_ERROR1;
}
- return 1;
- }
-
+ 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;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* ET=n - End of page or document */
if (!strncmp(p[0], "ET=", 3)) {
p[0] += 3;
@@ -857,7 +960,6 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
}
return 0;
}
-
/* K - terminate */
if (!strncmp(p[0], "K", 1)) {
p[0] += 1;
@@ -866,205 +968,191 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
isdn_tty_modem_hup(info, 1);
return 1;
}
-
/* LID=string - local fax ID */
- if (!strncmp(p[0], "LID", 3)) {
+ if (!strncmp(p[0], "LID", 3)) {
int i, r;
- p[0] += 3;
+ p[0] += 3;
switch (*p[0]) {
case '?':
p[0]++;
sprintf(rs, "\r\n\"%s\"", f->id);
- isdn_tty_at_cout(rs, info);
- break;
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* MDL? - DCE Model */
- if (!strncmp(p[0], "MDL?", 4)) {
- p[0] += 4;
+ if (!strncmp(p[0], "MDL?", 4)) {
+ p[0] += 4;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FMDL?\n");
+ printk(KERN_DEBUG "isdn_tty: FMDL?\n");
#endif
- isdn_tty_at_cout("\r\nisdn4linux", info);
- return 0;
- }
-
+ isdn_tty_at_cout("\r\nisdn4linux", info);
+ return 0;
+ }
/* MFR? - DCE Manufacturer */
- if (!strncmp(p[0], "MFR?", 4)) {
- p[0] += 4;
+ if (!strncmp(p[0], "MFR?", 4)) {
+ p[0] += 4;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FMFR?\n");
+ printk(KERN_DEBUG "isdn_tty: FMFR?\n");
#endif
- isdn_tty_at_cout("\r\nisdn4linux", info);
- return 0;
- }
-
+ 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;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* PHCTO=value - DTE phase C timeout */
- if (!strncmp(p[0], "PHCTO", 5)){
- p[0] +=5;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* REL=n - Phase C received EOL alignment */
- if (!strncmp(p[0], "REL", 3)) {
- p[0] += 3;
+ 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);
+ 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;
+ 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);
+ printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
#endif
- }
- break;
+ }
+ break;
default:
PARSE_ERROR1;
}
- return 0;
- }
-
+ return 0;
+ }
/* REV? - DCE Revision */
- if (!strncmp(p[0], "REV?", 4)) {
- p[0] += 4;
+ if (!strncmp(p[0], "REV?", 4)) {
+ p[0] += 4;
#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FREV?\n");
+ 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;
- }
-
+ isdn_tty_at_cout(rs, info);
+ return 0;
+ }
/* Phase C Transmit Data Block Size */
- if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */
+ 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]);
+ 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;
+ 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]);
+ printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
PARSE_ERROR1;
}
+int
+isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
+{
+ if (TTY_IS_FCLASS2(info))
+ return (isdn_tty_cmd_FCLASS2(p, info));
+ else if (TTY_IS_FCLASS1(info))
+ return (isdn_tty_cmd_FCLASS1(p, info));
+ PARSE_ERROR1;
+}