[Pkg-voip-commits] r3754 - / misdn-kernel misdn-kernel/trunk misdn-kernel/trunk/config misdn-kernel/trunk/debian misdn-kernel/trunk/drivers misdn-kernel/trunk/drivers/isdn misdn-kernel/trunk/drivers/isdn/hardware misdn-kernel/trunk/drivers/isdn/hardware/mISDN misdn-kernel/trunk/include misdn-kernel/trunk/include/linux

bradley-guest at alioth.debian.org bradley-guest at alioth.debian.org
Tue Jul 17 14:12:37 UTC 2007


Author: bradley-guest
Date: 2007-07-17 14:12:37 +0000 (Tue, 17 Jul 2007)
New Revision: 3754

Added:
   misdn-kernel/
   misdn-kernel/trunk/
   misdn-kernel/trunk/CHANGES
   misdn-kernel/trunk/Makefile
   misdn-kernel/trunk/Makefile.module
   misdn-kernel/trunk/Makefile.standalone
   misdn-kernel/trunk/README.misdn-init
   misdn-kernel/trunk/Rules.make.ext
   misdn-kernel/trunk/VERSION
   misdn-kernel/trunk/add.config
   misdn-kernel/trunk/config/
   misdn-kernel/trunk/config/Makefile
   misdn-kernel/trunk/config/README.mISDN
   misdn-kernel/trunk/config/mISDN
   misdn-kernel/trunk/config/mISDN.conf
   misdn-kernel/trunk/config/mISDN.conf.bnx.xsl
   misdn-kernel/trunk/config/mISDN.conf.hfcmulti.xsl
   misdn-kernel/trunk/config/mISDN.conf.inc.xsl
   misdn-kernel/trunk/config/mISDN.conf.l1oip.xsl
   misdn-kernel/trunk/config/mISDN.conf.mISDN_debugtool.xsl
   misdn-kernel/trunk/config/mISDN.conf.mISDN_dsp.xsl
   misdn-kernel/trunk/config/mISDN.conf.singlepci.xsl
   misdn-kernel/trunk/config/mISDN.conf.xsl
   misdn-kernel/trunk/debian/
   misdn-kernel/trunk/debian/README.Debian
   misdn-kernel/trunk/debian/changelog
   misdn-kernel/trunk/debian/compat
   misdn-kernel/trunk/debian/control
   misdn-kernel/trunk/debian/control.modules.in
   misdn-kernel/trunk/debian/copyright
   misdn-kernel/trunk/debian/dirs
   misdn-kernel/trunk/debian/docs
   misdn-kernel/trunk/debian/misdn-headers.install
   misdn-kernel/trunk/debian/misdn-modules.modules
   misdn-kernel/trunk/debian/misdn.dirs
   misdn-kernel/trunk/debian/misdn.init
   misdn-kernel/trunk/debian/misdn.install
   misdn-kernel/trunk/debian/misdn.postinst
   misdn-kernel/trunk/debian/rules
   misdn-kernel/trunk/debian/rules.modules
   misdn-kernel/trunk/drivers/
   misdn-kernel/trunk/drivers/isdn/
   misdn-kernel/trunk/drivers/isdn/Config.in.v2.4
   misdn-kernel/trunk/drivers/isdn/Makefile.v2.4
   misdn-kernel/trunk/drivers/isdn/hardware/
   misdn-kernel/trunk/drivers/isdn/hardware/Kconfig.v2.6
   misdn-kernel/trunk/drivers/isdn/hardware/Makefile.v2.6
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/.tmp_versions/
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Kconfig.v2.6
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile.v2.4
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile.v2.6
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Module.symvers
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Rules.mISDN.v2.4
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/app_plci.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/appl.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/arcofi.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/arcofi.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_address.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_address.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_aoc.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_aoc.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_basic_service.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_basic_service.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_comp.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_comp.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_diversion.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_diversion.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_enc.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_enc.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_generic.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_generic.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/avm_fritz.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/capi.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/capi_enc.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/channel.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/channel.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/contr.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/core.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/core.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debug.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debug.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debugtool.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_arith.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_audio.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_biquad.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_blowfish.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_cancel.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_cmx.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_core.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_dtmf.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_ecdis.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_kb1ec.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_kb1ec_const.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mec2.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mec2_const.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mg2ec.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mg2ec_const.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_tones.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dss1.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dtmf.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/faxl3.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/fsm.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/fsm.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/helper.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/helper.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_multi.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_multi.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_pci.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_pci.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_mini.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_mini.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_usb.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_usb.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcsmcc.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/i4l_mISDN.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isac.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isac.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isar.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isar.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l1oip.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l3_udss1.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l3helper.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/lapd.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer1.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer1.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer2.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer2.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer3.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer3.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/listen.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/loop.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/loop.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/mISDNManufacturer.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/m_capi.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/memdbg.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/memdbg.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/ncci.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netdev.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netjet.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netjet.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/plci.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sedl_fax.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/socket.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/socket.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/stack.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/supp_serv.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_inst.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_obj.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_st.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/tei.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/udevice.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/w6692.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/w6692.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_dte.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_l3.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_l3.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc24succ.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_pci2pi.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_pci2pi.h
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_su.c
   misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_su.h
   misdn-kernel/trunk/include/
   misdn-kernel/trunk/include/linux/
   misdn-kernel/trunk/include/linux/isdn_compat.h
   misdn-kernel/trunk/include/linux/mISDNdebugtool.h
   misdn-kernel/trunk/include/linux/mISDNif.h
   misdn-kernel/trunk/km_mISDN.spec
   misdn-kernel/trunk/mISDN.modprobe.d
   misdn-kernel/trunk/misdn-init
   misdn-kernel/trunk/std2kern
   misdn-kernel/trunk/stddiff
Removed:
   misdn-kernel-1.1.5/
   misdn-kernel/CHANGES
   misdn-kernel/Makefile
   misdn-kernel/Makefile.module
   misdn-kernel/Makefile.standalone
   misdn-kernel/README.misdn-init
   misdn-kernel/Rules.make.ext
   misdn-kernel/VERSION
   misdn-kernel/add.config
   misdn-kernel/config/
   misdn-kernel/debian/
   misdn-kernel/drivers/
   misdn-kernel/include/
   misdn-kernel/km_mISDN.spec
   misdn-kernel/mISDN.modprobe.d
   misdn-kernel/misdn-init
   misdn-kernel/std2kern
   misdn-kernel/stddiff
Log:
Fix incorrect layout of misdn-kernel

Copied: misdn-kernel (from rev 3753, misdn-kernel-1.1.5)

Deleted: misdn-kernel/CHANGES
===================================================================
--- misdn-kernel-1.1.5/CHANGES	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/CHANGES	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,5 +0,0 @@
-mISDN-1-1-2:
-	- added a workaround that fixes a kernel panic when bridging is done after already a few 
-	  voice frames where transceived on both legs (like when you transfer a call from SIP 2 ISDN)
-	- jollys mail has changed
-	- minor tweaks to misdn-init and to the Kernel-Patch script

Deleted: misdn-kernel/Makefile
===================================================================
--- misdn-kernel-1.1.5/Makefile	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/Makefile	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,125 +0,0 @@
-BASEDIR=$(shell pwd)
-
-MAJOR=1
-MINOR=1
-SUBMINOR=5
-
-INSTALL_PREFIX := /
-export INSTALL_PREFIX
-
-#PATH to linux source/headers
-#LINUX=/usr/src/linux
-
-ifndef KVERS
-KVERS:=$(shell uname -r)
-endif
-
-MODS=/lib/modules/$(KVERS)
-LINUX=$(MODS)/build
-LINUX_SOURCE=$(MODS)/source
-UPDATE_MODULES=$(shell which update-modules)
-MODULES_UPDATE=$(shell which modules-update)
-DEPMOD=$(shell which depmod)
-
-
-MISDNDIR=$(BASEDIR)
-MISDN_SRC=$(MISDNDIR)/drivers/isdn/hardware/mISDN
-
-########################################
-# USER CONFIGS END
-########################################
-
-CONFIGS+=CONFIG_MISDN_DRV=m 
-CONFIGS+=CONFIG_MISDN_DSP=m 
-CONFIGS+=CONFIG_MISDN_HFCMULTI=m 
-CONFIGS+=CONFIG_MISDN_HFCPCI=m
-CONFIGS+=CONFIG_MISDN_HFCUSB=m
-CONFIGS+=CONFIG_MISDN_XHFC=m
-CONFIGS+=CONFIG_MISDN_HFCMINI=m
-CONFIGS+=CONFIG_MISDN_W6692=m
-CONFIGS+=CONFIG_MISDN_SPEEDFAX=m
-CONFIGS+=CONFIG_MISDN_AVM_FRITZ=m
-CONFIGS+=CONFIG_MISDN_NETJET=m
-CONFIGS+=CONFIG_MISDN_DEBUGTOOL=m 
-
-#CONFIGS+=CONFIG_MISDN_NETDEV=y
-
-MISDNVERSION=$(shell cat VERSION)
-
-MINCLUDES+=-I$(MISDNDIR)/include
-
-all: VERSION test_old_misdn
-	cp $(MISDNDIR)/drivers/isdn/hardware/mISDN/Makefile.v2.6 $(MISDNDIR)/drivers/isdn/hardware/mISDN/Makefile
-	export MINCLUDES=$(MISDNDIR)/include ; export MISDNVERSION=$(MISDNVERSION); make -C $(LINUX) SUBDIRS=$(MISDN_SRC) modules $(CONFIGS)  
-
-install: all modules-install misdn-init
-	$(DEPMOD) 
-	$(UPDATE_MODULES)
-	$(MODULES_UPDATE)
-	make -C config install
-
-modules-install:
-	cd $(LINUX) ; make INSTALL_MOD_PATH=$(INSTALL_PREFIX) SUBDIRS=$(MISDN_SRC) modules_install 
-	mkdir -p $(INSTALL_PREFIX)/usr/include/linux/
-	cp $(MISDNDIR)/include/linux/*.h $(INSTALL_PREFIX)/usr/include/linux/
-	if [ -e $(INSTALL_PREFIX)/usr/include/linux/mISDNdsp.h ]; then rm -f $(INSTALL_PREFIX)/usr/include/linux/mISDNdsp.h; fi
-
-misdn-init:
-	mkdir -p $(INSTALL_PREFIX)/usr/sbin/
-	install -m755 misdn-init $(INSTALL_PREFIX)/usr/sbin/
-	if [ -d $(INSTALL_PREFIX)/etc/init.d ]; then \
-		if [ -e $(INSTALL_PREFIX)/etc/init.d/misdn-init ]; then rm -rf $(INSTALL_PREFIX)/etc/init.d/misdn-init; fi; \
-		ln -s $(INSTALL_PREFIX)/usr/sbin/misdn-init $(INSTALL_PREFIX)/etc/init.d/misdn-init; \
-	fi
-	mkdir -p $(INSTALL_PREFIX)/etc/modprobe.d
-	cp mISDN.modprobe.d $(INSTALL_PREFIX)/etc/modprobe.d/mISDN
-	mkdir -p $(INSTALL_PREFIX)/etc/modules.d
-	cp mISDN.modprobe.d $(INSTALL_PREFIX)/etc/modules.d/mISDN
-
-test_old_misdn:
-	@if echo -ne "#include <linux/mISDNif.h>" | gcc -C -E - 2>/dev/null 1>/dev/null  ; then \
-		if ! echo -ne "#include <linux/mISDNif.h>\n#if MISDN_MAJOR_VERSION < 4\n#error old mISDNif.h\n#endif\n" | gcc -C -E - 2>/dev/null 1>/dev/null ; then \
-			echo -ne "\n!!You should remove the following files:\n\n$(LINUX)/include/linux/mISDNif.h\n$(LINUX)/include/linux/isdn_compat.h\n/usr/include/linux/mISDNif.h\n/usr/include/linux/isdn_compat.h\n\nIn order to upgrade to the mqueue branch\n\n"; \
-			echo -ne "I can do that for you, just type: make force\n\n" ; \
-			exit 1; \
-		fi ;\
-	fi
-
-
-
-.PHONY: modules-install install all clean misdn-init VERSION
-
-force:
-	rm -f $(LINUX)/include/linux/mISDNif.h
-	rm -f $(LINUX)/include/linux/isdn_compat.h
-	rm -f /usr/include/linux/mISDNif.h
-	rm -f /usr/include/linux/isdn_compat.h
-
-clean:
-	rm -rf drivers/isdn/hardware/mISDN/*.o
-	rm -rf drivers/isdn/hardware/mISDN/*.ko
-	rm -rf *~
-	find . -iname ".*.cmd" -exec rm -rf {} \;
-	find . -iname ".*.d" -exec rm -rf {} \;
-	find . -iname "*.mod.c" -exec rm -rf {} \;
-	find . -iname "*.mod" -exec rm -rf {} \;
-
-VERSION:
-	echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION ; \
-
-snapshot: clean
-	DIR=mISDN-$$(date +"20%y_%m_%d") ; \
-	echo $(MAJOR)_$(MINOR)_$(SUBMINOR)-$$(date +"20%y_%m_%d" | sed -e "s/\//_/g") > VERSION ; \
-	mkdir -p /tmp/$$DIR ; \
-	cp -a * /tmp/$$DIR ; \
-	cd /tmp/; \
-	tar czf $$DIR.tar.gz $$DIR
-
-release: clean
-	DIR=mISDN-$(MAJOR)_$(MINOR)_$(SUBMINOR) ; \
-	echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION ; \
-	mkdir -p /tmp/$$DIR ; \
-	cp -a * /tmp/$$DIR ; \
-	cd /tmp/; \
-	tar czf $$DIR.tar.gz $$DIR
-

Deleted: misdn-kernel/Makefile.module
===================================================================
--- misdn-kernel-1.1.5/Makefile.module	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/Makefile.module	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,49 +0,0 @@
-# Master Makefile for the ipppcomp
-# (c) 03/2001 Karsten Keil <kkeil at suse.de>
-# adapted from Kurt Garloffs <garloff at suse.de> SecuMod package
-
-DESTDIR = 
-KDIR := /usr/src/linux
-
-TARGET := mISDN
-TARGETS := Rules.make arch scripts .config include $(TARGET)
-TARGETDIR := drivers/isdn/hardware/mISDN
-
-default: $(TARGETS)
-
-all: $(TARGETS)
-
-Rules.make: $(KDIR)/Rules.make Rules.make.ext
-	cp -pf $(KDIR)/Rules.make .
-	cat Rules.make.ext >> Rules.make
-
-.config: $(KDIR)/.config
-	cp -pf $(KDIR)/.config .
-	cat add.config >> .config
-
-arch: $(KDIR)/arch
-	rm -f arch
-	ln -s $(KDIR)/arch .
-
-scripts: $(KDIR)/scripts
-	rm -f scripts
-	ln -s $(KDIR)/scripts
-
-include: $(KDIR)/include
-	rm -f include
-	ln -s $(KDIR)/include
-
-clean:
-	rm -f $(TARGETS) $(TARGETDIR)/.*.flags $(TARGETDIR)/*.o $(TARGETDIR)/.depend
-	rm -f $(TARGETDIR)/*~ newinclude/linux/*~ *~ .kversion
-	rm -f -r modules .depend .hdepend
-	
-$(TARGET):
-	$(MAKE) -f Makefile KDIR=$(KDIR) TARGETDIR=$(TARGETDIR) $(TARGET)
-
-install: $(TARGETS)
-	$(MAKE) -f Makefile KDIR=$(KDIR) TARGETDIR=$(TARGETDIR) install_mod
-	install newinclude/linux/mISDNif.h /usr/include/linux
-
-modlist:
-	$(MAKE) -f Makefile KDIR=$(KDIR) TARGETDIR=$(TARGETDIR) modlist

Deleted: misdn-kernel/Makefile.standalone
===================================================================
--- misdn-kernel-1.1.5/Makefile.standalone	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/Makefile.standalone	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,76 +0,0 @@
-# km_mISDN slave Makefile
-# (c) 10/2001 Karsten Keil <kkeil at suse.de>
-#
-KDIR = /usr/src/linux
-
-DESTDIR =
-TARGET = 
-TARGETS := $(TARGET)
-
-default: $(TARGETS)
-
-all: $(TARGETS)
-
-MYDIR := $(PWD)
-
-TOPDIR := $(KDIR)
-include $(KDIR)/.config
-include $(KDIR)/Makefile
-
-CFLAGS := -I. -I $(KDIR)/drivers/isdn/avmb1 $(CFLAGS) -I $(MYDIR)/newinclude -DLINUX
-CC := $(filter-out -I$(HPATH), $(CC)) -I $(MYDIR)/newinclude -I $(HPATH)
-
-ifdef CONFIG_MODVERSIONS
-CFLAGS := -DMODULE -DMODVERSIONS -include $(MODVERFILE) $(CFLAGS)
-else
-CFLAGS := -DMODULE $(CFLAGS)
-endif
-
-FINDHPATH += $(MYDIR)/newinclude/linux
-
-MODLIB := $(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
-
-mISDN: $(TARGETDIR) depend mISDN_mod 
-	$(MAKE) -C $(TARGETDIR) CFLAGS="$(CFLAGS)" MAKING_MODULES=1 modules
-
-dep-files: scripts/mkdep archdep include/linux/version.h
-	scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
-	$(MAKE) $(patsubst %,_sfdep_%,$(TARGETDIR)) _FASTDEP_ALL_SUB_DIRS="$(TARGETDIR)"
-ifdef CONFIG_MODVERSIONS
-	$(MAKE) update-modverfile
-endif
-
-depend dep: dep-files
-
-ifeq ($(PATCHLEVEL), 2)
-
-TARGETMODDIR = misc
-
-install: install_mod
-
-install_mod: modules_install
-
-mISDN_mod:
-	echo patchlevel $(PATCHLEVEL)
-	mkdir -p modules
-
-else
-
-TARGETMODDIR = ../misc
-
-mISDN_mod:
-	echo patchlevel $(PATCHLEVEL)
-
-install: install_mod
-
-install_mod: $(MODLIB)/$(TARGETMODDIR)
-	$(MAKE) -C $(TARGETDIR) MOD_DESTDIR=$(TARGETMODDIR) modules_install
-
-$(MODLIB)/$(TARGETMODDIR):
-	mkdir -p $(MODLIB)/$(TARGETMODDIR) 
-
-endif
-
-modlist: $(MODLIB)/$(TARGETMODDIR)
-	$(MAKE) -C $(TARGETDIR) MOD_DESTDIR=$(TARGETMODDIR) mod_list
-

Deleted: misdn-kernel/README.misdn-init
===================================================================
--- misdn-kernel-1.1.5/README.misdn-init	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/README.misdn-init	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,55 +0,0 @@
-misdn-init: init-script to auto-configure and load the mISDN kernel drivers
-===========================================================================
-
-This script makes it easy to configure and activate mISDN compatible 
-adapter cards. It scans an eyecandy config file named misdn-init.conf
-for your card and port settings, then it loads the driver modules properly.
-The misdn-init.conf can also be autogenerated by the misdn-init script.
-
----------------------------------------------------------------------------
-Usage: /usr/sbin/misdn-init start|stop|restart|config|scan|help
-
-  --start      scan /etc/misdn-init.conf and load the mISDN drivers
-  --stop       unload the mISDN drivers
-  --restart    see stop, then start
-  --config     scan your PCI bus for mISDN compatible hardware and generate
-               a /etc/misdn-init.conf
-  --scan       scan your PCI bus for mISDN compatible hardware and print
-               the results to the console
-  --help       print the usage info
----------------------------------------------------------------------------
-
-
-* Here is a quick overview on how to use misdn-init:
-
-1) Get and install misdn-init:
-   $ wget http://www.beronet.com/downloads/chan_misdn/stable/chan_misdn.tar.gz
-   $ tar zxf chan_misdn.tar.gz
-   $ (as root) cp chan_misdn/misdn-init /usr/sbin/misdn-init
-   
-2) Let misdn-init scan your PCI bus for mISDN compatible hardware and write
-   the results into /etc/misdn-init.conf:
-   $ (as root) /usr/sbin/misdn-init config
- 
-3) (optional) Edit /etc/misdn-init.conf and set everything the way you want it.
-   This file is heavily commented, hence it should be self-explaining.
-
-4) (optional, but recommended) Add misdn-init to your run level.
-   This is distribution dependend. Here an example for a debian system:
-   ATTENTION: If you have services in your runlevels that depend
-              on mISDN, make sure that misdn-init starts before, and
-              stops after them (this is done by changing the values
-              that are set to 60 in this example, more info: read the 
-              manpage for update-rc.d).
-   $ (as root) update-rc.d misdn-init start 60 2 3 4 5 . stop 60 0 1 6 .
-
-5) Run the following to start mISDN:
-   $ (as root) /usr/sbin/misdn-init start
-
-
-
----------------------------------------------------------------------------
-* Report Bugs:
-If you experience any bugs or have a feature request, please visit:
-www.isdn4linux.de/mantis
-

Deleted: misdn-kernel/Rules.make.ext
===================================================================
--- misdn-kernel-1.1.5/Rules.make.ext	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/Rules.make.ext	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,5 +0,0 @@
-
-mod_list: $(obj-m)
-	rm -f $(TOPDIR)/files.mod
-	for i in $(obj-m) ; do echo $(MODLIB)/misc/$$i>>$(TOPDIR)/files.mod; done
-

Deleted: misdn-kernel/VERSION
===================================================================
--- misdn-kernel-1.1.5/VERSION	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/VERSION	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1 +0,0 @@
-1_1_5

Deleted: misdn-kernel/add.config
===================================================================
--- misdn-kernel-1.1.5/add.config	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/add.config	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,10 +0,0 @@
-#
-# Modular ISDN driver
-#
-CONFIG_MISDN_DRV=m
-CONFIG_MISDN_AVM_FRITZ=y
-CONFIG_MISDN_HFCPCI=y
-CONFIG_MISDN_SPEEDFAX=y
-CONFIG_MISDN_W6692=y
-CONFIG_MISDN_DSP=y
-CONFIG_MISDN_MEMDEBUG=y

Deleted: misdn-kernel/km_mISDN.spec
===================================================================
--- misdn-kernel-1.1.5/km_mISDN.spec	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/km_mISDN.spec	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,60 +0,0 @@
-Vendor:       SuSE GmbH, Nuernberg, Germany
-Distribution: SuSE Linux 8.2 (i386)
-Name:         km_mISDN
-Release:      14
-Packager:     feedback at suse.de
-
-Copyright:    Karsten Keil GPL
-Group:        unsorted
-Autoreqprov:  on
-Version:      1.0
-Summary:      modular ISDN driver architecture
-Source:       mISDN-%{version}-%{release}.tar.bz2
-#Patch:       isdn4k-utils.dif
-Buildroot:    /var/tmp/mISDN.build
-
-%description
-This package provides the mISDN sourcecode for kernelmodules
-Attention!!! These modules are BETA code and experimental, they may be
-crash your machine. Here is no support from SuSE for it.
-
-Authors:
---------
-	Karsten Keil
-
-SuSE series: unsorted
-
-%prep
-%setup -n mISDN
-#%patch
-
-%build
-mv Makefile.standalone Makefile
-
-%install
-rm -f -r $RPM_BUILD_ROOT
-DESTDIR=$RPM_BUILD_ROOT/usr/src/kernel-modules/mISDN
-mkdir -p $DESTDIR
-install -p Makefile* $DESTDIR
-install -p Rules.make.ext $DESTDIR
-install -p add.config $DESTDIR
-mkdir -p $DESTDIR/newinclude/linux
-install -p include/linux/*.h $DESTDIR/newinclude/linux
-mkdir -p $DESTDIR/drivers/isdn/hardware/mISDN
-install -p drivers/isdn/hardware/mISDN/Makefile $DESTDIR/drivers/isdn/hardware/mISDN
-install -p drivers/isdn/hardware/mISDN/*.[ch] $DESTDIR/drivers/isdn/hardware/mISDN
-install -p drivers/isdn/hardware/mISDN/Rules.mISDN.v2.4 $DESTDIR/drivers/isdn/hardware/mISDN/Rules.mISDN
-
-#
-%{?suse_check}
-
-%clean
-
-%files
-%dir %attr (-,root,root) /usr/src/kernel-modules/mISDN
-%attr (-,root,root) /usr/src/kernel-modules/mISDN/*
-
-%changelog -n km_mISDN
-
-* Tue Jul 01 2003 - kkeil at suse.de
-  - first version

Deleted: misdn-kernel/mISDN.modprobe.d
===================================================================
--- misdn-kernel-1.1.5/mISDN.modprobe.d	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/mISDN.modprobe.d	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,25 +0,0 @@
-
-install hfcmulti /usr/sbin/misdn-init start hfcmulti
-remove  hfcmulti /usr/sbin/misdn-init stop 
-
-install hfcpci /usr/sbin/misdn-init start hfcpci
-remove  hfcpci /usr/sbin/misdn-init stop 
-
-install hfcsusb /usr/sbin/misdn-init start hfcsusb
-remove  hfcsusb /usr/sbin/misdn-init stop 
-
-install hfcsmini /usr/sbin/misdn-init start hfcsmini
-remove  hfcsmini /usr/sbin/misdn-init stop 
-
-install xhfc /usr/sbin/misdn-init start xhfc
-remove  xhfc /usr/sbin/misdn-init stop 
-
-install avmfritz /usr/sbin/misdn-init start avmfritz
-remove  avmfritz /usr/sbin/misdn-init stop 
-
-install w6692pci /usr/sbin/misdn-init start w6692pci
-remove  w6692pci /usr/sbin/misdn-init stop 
-
-install sedlfax /usr/sbin/misdn-init start sedlfax
-remove  sedlfax /usr/sbin/misdn-init stop 
-

Deleted: misdn-kernel/misdn-init
===================================================================
--- misdn-kernel-1.1.5/misdn-init	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/misdn-init	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,780 +0,0 @@
-#!/bin/bash
-
-################################################################################
-#
-# misdn-init init script
-#
-# Copyright (C) 2005, Nadi Sarrar
-#
-# Nadi Sarrar <nadi at beronet.com>
-#
-# This program is free software, distributed under the terms of
-# the GNU General Public License
-#
-
-#
-# USAGE:
-#
-#   /usr/sbin/misdn-init start|stop|restart|config|scan|help
-#
-
-# chkconfig: 2345 35 60
-# description: mISDN Kernel Modules
-
-#
-# CONFIGURATION:
-#
-# Path to your misdn-init.conf:
-#
-misdn_init_conf="/etc/misdn-init.conf"
-#
-################################################################################
-
-#
-# change this to modify the user/group settings of /dev/mISDN
-#
-USER=asterisk
-GROUP=asterisk
-
-# HFC 8/4 (S0) Options
-master_clock=17
-
-# HFC-E1 Options
-optical=17
-los=19
-ais=20
-slip=21
-nocrc4=24
-
-# Card Settings
-ulaw=9
-dtmf=10
-pcm_slave=12
-ignore_pcm_frameclock=13
-
-rxclock=14
-crystalclock=19
-
-watchdog=20
-
-
-#dsp defaults
-dsp_options=0
-
-poll_option=
-
-dsp_poll_option=
-
-dtmfthreshold_option=
-
-function check_cmd {
-	if ! which "${1}" > /dev/null; then
-		if [ "$(id -u)" != "0" ]; then
-			echo "[!!] FATAL: $1 not in path, please install and/or be root."
-		else
-			echo "[!!] FATAL: $1 not in path, please install."
-		fi
-		if [ "${2}" != "notfatal" ] ; then
-			exit 1
-		fi
-	else
-		var=$(echo ${1} | tr a-z A-Z)
-		eval "$var=`which ${1}`"
-	fi
-}
-
-check_cmd modprobe
-check_cmd rmmod
-check_cmd insmod
-check_cmd lspci
-check_cmd lsusb notfatal
-check_cmd mknod
-check_cmd bc
-check_cmd cut
-check_cmd wc
-check_cmd seq
-check_cmd sed
-
-function check_asterisk {
-	if ps ax | grep -v grep | grep asterisk > /dev/null ; then asterisk -rx "stop now" ; fi
-}
-
-function create_card_db
-{
-	cardline=""
-	cardcount=1
-	skipnext=0
-
-	IFS=$'\n'
-	NL="
-"
-	function addcard {
-		cardline="${cardline}${cardcount},${1}${NL}"
-		let "cardcount = ${cardcount} + 1"
-	}
-
-	function addport {
-		let "portcount = ${portcount} + ${1}"
-	}
-
-	for line in $(${LSPCI} -n -d 0xd161:b410); do
-		addcard "4,0x4"
-	done
-
-	for line in $(${LSPCI} -n | ${SED} -n 's/^\(0000:\|\)\([0-9a-f]\{2\}:[0-9a-f]\{2\}.[0-9a-f]\{1\}\)\( Class \| \)[0-9a-f]\{4\}: 1397:\([0-9a-f]\{4\}\).*$/\4 \2/p'); do
-		if [ ${skipnext} -eq 1 ]; then
-			skipnext=0
-			continue
-		fi
-		case "${line}" in
-			30b1*)
-				case "${line:5}" in
-					00*)
-						addcard "1,0x1"
-						;;
-					*)
-						if [ $(${LSPCI} -n -s ${line:5:3} -d 0x1397:30b1 | ${WC} -l) -eq 2 ]; then
-							addcard "2,2E1"
-							skipnext=1
-						else
-							addcard "1,0x1"
-						fi
-						;;
-				esac
-				;;
-			16b8*)
-				addcard "8,0x8"
-				;;
-			08b4*)
-
-				if ${LSPCI} -n -v -s "${line:5}" | grep "Subsystem" | grep "1397:b567" > /dev/null ; then
-					addcard "1,0x4"
-				elif ${LSPCI} -n -v -s "${line:5}" | grep "Subsystem" | grep "1397:b566\|1397:b569" > /dev/null ; then
-					addcard "2,0x4"
-				else
-					addcard "4,0x4"
-				fi
-				;;
-		esac
-	done
-	for line in $(${LSPCI} -n | grep "1397:\(2bd\(0\|6\|7\|8\|9\|a\|b\|c\)\|b100\)\|1043:0675\|0871:ffa\(1\|2\)\|1051:0100\|15b0:2bd0\|114f:007\(0\|1\|2\|3\)\|13d1:2bd1\|182d:3069"); do
-		addcard "1,hfcpci"
-	done
-	for line in $(${LSPCI} -n | grep "1244:\(0a00\|0e00\)"); do
-		addcard "1,avmfritz"
-	done
-	for line in $(${LSPCI} -n -d 1050:6692); do
-		addcard "1,w6692pci"
-	done
-	
-	if [ -e ${LSUSB} ]; then 
-		for line in $(${LSUSB} | grep "0959:2bd0\|0675:1688\|07b0:0006\|0742:200\(7\|8\|9\|A\)\|08e3:0301\|07fa:084\(7\|8\)\|07ba:0006"); do
-			addcard "1,hfcsusb"
-		done
-	fi
-
-	echo "${cardline}"
-}
-
-function expand
-{
-	local IFS=$','
-	for tok in $1; do
-		if [ "$(echo $tok | ${SED} -ne 's/\([0-9]*\)-\([0-9]*\)/\1 \2/p')" != "" ]; then
-			${SEQ} $(echo $tok | ${SED} -ne 's/\([0-9]*\)-[0-9]*/\1/p') $(echo $tok | ${SED} -ne 's/[0-9]*-\([0-9]*\)/\1/p')
-		else
-			echo $tok
-		fi
-	done
-}
-
-function load_card_modules {
-
-	carddb=$(create_card_db)
-
-	function find_carddb_line {
-		i=1
-		for l in ${carddb} ; do
-			if [ $i -eq $1 ] ; then 
-				echo $l
-				return
-			fi
-			let "i=$i+1"
-		done
-	}
-
-	if [ ! -z "$1" ] ; then
-		echo "Loading only $1"
-	fi
-
-	IFS=$'\n'
-	skipnr=0
-
-	for line in $(${SED} -n -e '/^[^#]/p' ${misdn_init_conf});
-	do
-		var=$(echo "${line}" | ${CUT} -d "=" -f1)
-		val=$(echo "${line}" | ${CUT} -d "=" -f2)
-		
-		case "${var}" in
-			card)
-				#echo "processing line: $val" 
-				nr=$(echo "${val}" | ${CUT} -d "," -f1)
-				mod=$(echo "${val}" | ${CUT} -d "," -f2)
-				opns=$(echo "${val}" | ${CUT} -d "," -f3-)
-
-				#getting portcount from carddb
-				ports=$(find_carddb_line $nr | ${CUT} -d "," -f2)
-				let "nr = ${nr} + ${skipnr}"
-				#echo "nr $nr ports $ports mod $mod opns: $opns"
-
-				case "${mod}" in
-					2E1)
-						hfcmulti[${nr}]=1
-						hfcmulti[$((${nr} + 1))]=1
-						let "hfcports = ${hfcports} + ${ports}"
-						IFS=$','
-						for li in ${opns}; do
-							hfcmulti[${nr}]=$(echo "obase=10;2^(${!li}-1)+${hfcmulti[${nr}]}" | ${BC})
-							if [ "${li}" != "pcm_slave" ]; then
-								hfcmulti[$((${nr} + 1))]=$(echo "obase=10;2^(${!li}-1)+${hfcmulti[$((${nr}+1))]}" | ${BC})
-							fi
-						done
-						IFS=$'\n'
-						hfcmulti[$((${nr} + 1))]=$(echo "obase=10;2^(${pcm_slave}-1)+${hfcmulti[$((${nr}+1))]}" | ${BC})
-						let "skipnr = ${skipnr} + 1"
-						;;
-					0x*)
-						hfcmulti[${nr}]=$(echo ${mod} | ${SED} -e "s/^0x\([0-9]*\)/\1/")
-						let "hfcports = ${hfcports} + ${ports}"
-						IFS=$','
-						for li in ${opns}; do
-							hfcmulti[${nr}]=$(echo "obase=10;2^(${!li}-1)+${hfcmulti[${nr}]}" | ${BC})
-						done
-						IFS=$'\n'
-						;;
-					*)
-						other_card[${nr}]=${mod}
-						;;
-				esac
-				;;
-			te_ptp)
-				for li in $(expand "${val}"); do
-					layermask[${li}]="0xf"
-					protocol[${li}]=34 # 0x22 == 34
-				done
-				;;
-			te_ptmp)
-				for li in $(expand "${val}"); do
-					layermask[${li}]="0xf"
-					protocol[${li}]=2 # 0x2 == 2
-				done
-				;;
-			nt_*)
-				for li in $(expand "${val}"); do
-					layermask[${li}]="0x3"
-					protocol[${li}]=18 # 0x12 == 18
-				done
-				;;
-			te_capi_ptp)
-				for li in $(expand "${val}"); do
-					layermask[${li}]="0x0"
-					protocol[${li}]=34 # 0x22 == 34
-				done
-
-				export addcapi=1
-				;;
-			te_capi_ptmp)
-				for li in $(expand "${val}"); do
-					layermask[${li}]="0x0"
-					protocol[${li}]=2 # 0x2 == 2
-				done
-
-				export addcapi=1
-				;;
-
-			option)
-				port=`echo "${val}" | ${SED} -e "s/^\([0-9]*\),.*/\1/"`
-				opt=`echo "${val}" | ${SED} -e "s/^[0-9]*,\(.*\)/\1/"`
-
-				if [ -z ${protocol[${port}]} ]; then
-					protocol[${port}]="0"
-				fi
-				
-				IFS=$','
-				for li in ${opt}; do
-					protocol[${port}]=$(echo "obase=10;2^(${!li}-1)+${protocol[${port}]}" | ${BC})
-				done
-				IFS=$'\n'
-				;;
-			poll)
-				poll=${val}
-				poll_option=poll=${val}
-				;;
-			dsp_poll)
-				dsp_poll_option=poll=${val}
-				;;
-			pcm)
-				pcm=${val}
-				;;
-			dsp_options)
-				export dsp_options=${val}
-				;;
-			dtmfthreshold)
-				export dtmfthreshold_option="dtmfthreshold=${val}"
-				;;
-			debug)
-				debug=${val}
-				;;
-			timer)
-				timer=${val}
-				;;
-			*)
-				echo "unknown variable: ${var}"
-				;;
-		esac
-		
-	done
-
-	echo "-----------------------------------------"
-	echo " Loading module(s) for your misdn-cards:"
-	echo "-----------------------------------------"
-
-	card_index=1
-	port_index=1
-	while [ ! -z ${hfcmulti[${card_index}]} ] || [ ! -z ${other_card[${card_index}]} ];
-	do
-		if [ ! -z ${hfcmulti[${card_index}]} ]; then
-	# MODPROBE COMMAND FOR hfcmulti CARD
-			hfcmulti_type="type="
-			hfcmulti_prot="protocol="
-			hfcmulti_layer="layermask="
-			while [ ! -z ${hfcmulti[${card_index}]} ];
-			do
-				hfcmulti_type="${hfcmulti_type}$(echo "obase=16;\"0x\";${hfcmulti[${card_index}]}" | ${BC} ),"
-				let "card_index = ${card_index} + 1"
-			done
-			while [ ${hfcports} -gt 0 ];
-			do
-				if [ ! -z ${protocol[${port_index}]} ]; then
-					hfcmulti_prot="${hfcmulti_prot}$(echo "obase=16;\"0x\";${protocol[${port_index}]}" | ${BC}),"
-				else
-					hfcmulti_prot="${hfcmulti_prot}0x2,"
-				fi
-				if [ ! -z ${layermask[${port_index}]} ]; then
-					hfcmulti_layer="${hfcmulti_layer}${layermask[${port_index}]},"
-				else
-					hfcmulti_layer="${hfcmulti_layer}0xf,"
-				fi
-				let "port_index = ${port_index} + 1"
-				let "hfcports = ${hfcports} - 1"
-			done
-			hfcmulti_type="$(echo ${hfcmulti_type} | ${SED} -e 's/^\(.*\),$/\1/')"
-			hfcmulti_prot="$(echo ${hfcmulti_prot} | ${SED} -e 's/^\(.*\),$/\1/')"
-			hfcmulti_layer="$(echo ${hfcmulti_layer} | ${SED} -e 's/^\(.*\),$/\1/')"
-			hfcmulti_cmd="${MODPROBE} --ignore-install hfcmulti ${hfcmulti_type} ${hfcmulti_prot} ${hfcmulti_layer}"
-			if [ ! -z ${poll} ]; then
-				hfcmulti_cmd="${hfcmulti_cmd} poll=${poll}"
-			fi
-			if [ ! -z ${pcm} ]; then
-				hfcmulti_cmd="${hfcmulti_cmd} pcm=${pcm}"
-			fi
-			if [ ! -z ${debug} ]; then
-				hfcmulti_cmd="${hfcmulti_cmd} debug=${debug}"
-			fi
-
-			if [ ! -z ${timer} ]; then
-				hfcmulti_cmd="${hfcmulti_cmd} timer=${timer}"
-			fi
-
-			if [ -z "$1" ] ; then
-				echo ${hfcmulti_cmd}
-				eval ${hfcmulti_cmd}
-			else
-				if [ "$1" = "hfcmulti" ] ; then 
-					echo ${hfcmulti_cmd}
-					eval ${hfcmulti_cmd}
-				fi
-			fi
-		else
-	# MODPROBE COMMAND FOR _NON_ hfcmulti CARD
-			other_mod="${other_card[${card_index}]}"
-			other_cmd="${MODPROBE} --ignore-install ${other_mod}"
-			if [ ! -z ${protocol[${port_index}]} ]; then
-				other_prot="protocol=$(echo "obase=16;\"0x\";${protocol[${port_index}]}" | ${BC}),"
-			else
-				other_prot="protocol=0x2,"
-			fi
-			if [ ! -z ${layermask[${port_index}]} ]; then
-				other_layer="layermask=${layermask[${port_index}]},"
-			else
-				other_layer="layermask=0xf,"
-			fi
-			other_extra=""
-			modinfo $other_mod | egrep -q 'parm: *poll' && other_extra="$other_extra ${poll_option}"
-
-			let "prev = ${card_index}"
-			let "card_index = ${card_index} + 1"
-			let "port_index = ${port_index} + 1"
-			while [ "${other_card[${card_index}]}" == "${other_card[${prev}]}" ];
-			do
-				if [ ! -z ${protocol[${port_index}]} ]; then
-					other_prot="${other_prot}$(echo "obase=16;\"0x\";${protocol[${port_index}]}" | ${BC}),"
-				else
-					other_prot="${other_prot}0x2,"
-				fi
-				if [ ! -z ${layermask[${port_index}]} ]; then
-					other_layer="${other_layer}${layermask[${port_index}]},"
-				else
-					other_layer="${other_layer}0xf,"
-				fi
-				let "prev = ${card_index}"
-				let "card_index = ${card_index} + 1"
-				let "port_index = ${port_index} + 1"
-			done
-			
-			other_prot="$(echo ${other_prot} | ${SED} -e 's/^\(.*\),$/\1/')"
-			other_layer="$(echo ${other_layer} | ${SED} -e 's/^\(.*\),$/\1/')"
-			other_cmd="${other_cmd} ${other_prot} ${other_layer} ${other_extra}"
-
-			if [ -z "$1" ] ; then
-				echo "${other_cmd}"
-				eval ${other_cmd}
-			else
-				if [ "$1" = "${other_card[${prev}]}" ] ; then 
-					echo ${other_cmd}
-					eval ${other_cmd}
-				fi
-			fi
-
-
-		fi
-	done
-}
-
-function unload_card_modules {
-
-	IFS=$'\n'
-
-	for line in $(${SED} -ne '/^[^#]/p' ${misdn_init_conf});
-	do
-		var=$(echo "${line}" | ${CUT} -d "=" -f 1)
-		val=$(echo "${line}" | ${CUT} -d "=" -f 2)
-		
-		case "${var}" in
-			card)
-				nr=$(echo "${val}" | ${CUT} -d "," -f 1)
-				mod=$(echo "${val}" | ${CUT} -d "," -f 2)
-				case "${mod}" in
-					2E1)
-						modulelist[${nr}]=hfcmulti
-						;;
-					0x*)
-						modulelist[${nr}]=hfcmulti
-						;;
-					*)
-						modulelist[${nr}]=${mod}
-						;;
-				esac
-				;;
-		esac
-		
-	done
-
-	echo "-------------------------------------------"
-	echo " Unloading module(s) for your misdn-cards:"
-	echo "-------------------------------------------"
-
-	rmmod_cmd="${RMMOD} ${modulelist[1]}"
-	echo "${rmmod_cmd}"
-	eval ${rmmod_cmd}
-	
-	index=2
-	prev=1
-	while [ ! -z ${modulelist[${index}]} ];
-	do
-		if [ ${modulelist[${index}]} != ${modulelist[${prev}]} ]; then
-			rmmod_cmd="${RMMOD} ${modulelist[${index}]}"
-			echo "${rmmod_cmd}"
-			eval ${rmmod_cmd}
-		fi
-		let "prev = ${index}"
-		let "index = ${index} + 1"
-	done
-}
-
-function create_misdn_init_conf {
-	cardline=""	
-	cardcount=1
-	portcount=0
-	cardconf=""
-	IFS=$'\n'
-	NL="
-"
-	carddb=$(create_card_db)
-
-	for line in $carddb ; do 
-		tmp="card=$(echo $line | ${CUT} -d, -f1,3)"
-		let "portcount = ${portcount} + $(echo $line | ${CUT} -d, -f2)"
-		cardline="${cardline}${tmp}${NL}"	
-	done
-
-	function die {
-		echo "[!!] ${1}"
-		exit 1
-	}
-	
-	if [ "${1}" == "scan" ]; then
-		echo "[OK] found the following devices:"
-		echo "${cardline}[ii] run \"/usr/sbin/misdn-init config\" to store this information to ${misdn_init_conf}"
-	else
-		
-		index=1
-		portline="te_ptmp="
-		while [ ${index} -le ${portcount} ]; do
-			portline="${portline}${index},"
-			let "index = ${index} + 1"
-		done
-		portline="$(echo ${portline} | ${SED} -e 's/^\(.*\),$/\1/')"
-
-		misdn_cfg_pt1="#
-# Configuration file for your misdn hardware
-#
-# Usage: /usr/sbin/misdn-init start|stop|restart|config|scan|help
-#
-
-#
-# Card Settings
-#
-# Syntax: card=<number>,<type>[,<option>...]
-#
-#    <number>   count your cards beginning with 1
-#    <type>     either 0x1,0x4 or 0x8 for your hfcmulti hardware,
-#               or the name of your card driver module.
-#    <option>	ulaw       - uLaw (instead of aLaw)
-#               dtmf       - enable DTMF detection on all B-channels
-#
-#               pcm_slave  - set PCM bus into slave mode
-#			     If you have a set of cards, all wired via PCM. Set 
-#			     all cards into pcm_slave mode and leave one out.
-#			     The left card will automatically be Master.
-#
-#		ignore_pcm_frameclock	- this can be set in conjunction with
-#					pcm_slave. If this card has a  
-#					PCI Bus Position before the Position 
-#					of the Master, then this port cannot
-#					yet receive a frameclock, so it must
-#					ignore the pcm frameclock.
-#					 
-#		rxclock    - use clocking for pcm from ST Port
-#		crystalclock - use clocking for pcm from PLL (genrated on board)
-#		watchdog   - This dual E1 Board has a Watchdog for 
-#			     transparent mode
-#
-#"
-		misdn_cfg_pt2="#
-# Port settings
-#
-# Syntax: <port_type>=<port_number>[,<port_number>...]
-#
-#    <port_type>    te_ptp   		- TE-Mode, PTP
-#                   te_ptmp  		- TE-Mode, PTMP
-#                   te_capi_ptp  	- TE-Mode (capi), PTP
-#                   te_capi_ptmp 	- TE-Mode (capi), PTMP
-#                   nt_ptp   		- NT-Mode, PTP
-#                   nt_ptmp  		- NT-Mode, PTMP
-#    <port_number>  port that should be considered
-#"
-		misdn_cfg_pt3="#
-# Port Options
-#
-# Syntax: option=<port_number>,<option>[,<option>...]
-#
-#    <option>  master_clock  - use master clock for this S/T interface
-#                              (only once per chip, only for HFC 8/4)
-#              optical       - optical (only HFC-E1)
-#              los           - report LOS (only HFC-E1)
-#              ais           - report AIS (only HFC-E1)
-#              slip          - report SLIP (only HFC-E1)
-#              nocrc4	     - turn off crc4 mode use double frame instead 
-#				(only HFC-E1)
-#
-# The master_clock option is essential for retrieving and transmitting
-# faxes to avoid failures during transmission. It tells the driver to 
-# synchronize the Card with the given Port which should be a TE Port and
-# connected to the PSTN in general.
-#
-#option=1,master_clock
-#option=2,ais,nocrc4
-#option=3,optical,los,ais,slip
-
-
-#
-# General Options for your hfcmulti hardware
-#
-# poll=<number>
-#
-#        Only one poll value must be given for all cards.
-#        Give the number of samples for each fifo process.
-#        By default 128 is used. Decrease to reduce delay, increase to
-#        reduce cpu load. If unsure, don't mess with it!!!
-#        Valid is 32, 64, 128, 256.
-#
-# dsp_poll=<number>
-#	This is the poll option which is used by mISDN_dsp, this might 
-# 	differ from the one given by poll= for the hfc based cards, since
-# 	they can only use multiples of 32, the dsp_poll is dependant on 
-#	the kernel timer setting which can be found in the CPU section
-#	in the kernel config. Defaults are there either 100Hz, 250Hz 
-#	or 1000Hz. If your setting is either 1000 or 250 it is compatible
-#	with the poll option for the hfc chips, if you have 100 it is 
-#	different and you need here a multiple of 80.
-#	The default is to have no dsp_poll option, then the dsp itself
-#	finds out which option is the best to use by itself
-#
-# pcm=<number>
-#        
-#        Give the id of the PCM bus. All PCM busses with the same ID
-#        are expected to be connected and have equal slots.
-#        Only one chip of the PCM bus must be master, the others slave.
-#
-# debug=<number>
-#
-#        Enable debugging (see hfc_multi.h for debug options).
-#
-# dsp_options=<number>
-#  
-#	set this to 2 and you'll have software bridging instead of 
-#	hardware bridging.
-# 
-#
-# dtmfthreshold=<milliseconds>
-#
-#	Here you can tune the sensitivity of the dtmf tone recognizer.
-#
-# timer=<1|0>
-# 
-#	set this to 1 if you want hfcmulti to register at ztdummy (zaptel) 
-#	and provide a 1khz timing source for it. This makes it possible
-#	to have an accurate timing source for asterisk through zaptel from
-#	hfcmulti to make applications like Meetme and faxing between wctdm
-#	and hfcmulti work properly.
-#
-poll=128
-dsp_poll=128
-dsp_options=0
-dtmfthreshold=100
-debug=0"
-
-		if [ -f ${misdn_init_conf} ]; then
-			cp "${misdn_init_conf}" "${misdn_init_conf}.save" || die "could not backup your existing ${misdn_init_conf}!"
-			echo "[OK] ${misdn_init_conf} already present. backing it up to ${misdn_init_conf}.save"
-		fi
-		echo "${misdn_cfg_pt1}${NL}${cardline}${NL}${misdn_cfg_pt2}${NL}${portline}${NL}${NL}${misdn_cfg_pt3}" > ${misdn_init_conf} || die "could not write to /etc/misdn-init.conf!"
-#echo "${misdn_cfg_pt1}${NL}${cardline}${NL}${misdn_cfg_pt2}${NL}${portline}${NL}${NL}${misdn_cfg_pt3}" > testconf || die "could not write to /etc/misdn-init.conf!"
-
-		echo "[OK] ${misdn_init_conf} created. It's now safe to run \"/usr/sbin/misdn-init start\""
-		if [ ${portcount} -gt 1 ]; then
-			echo "[ii] make your ports (1-${portcount}) available in asterisk by editing \"/etc/asterisk/misdn.conf\""
-		elif [ ${portcount} -eq 1 ]; then
-			echo "[ii] make your port (1) available in asterisk by editing \"/etc/asterisk/misdn.conf\""
-		fi
-	fi
-}
-
-function check_cfg_file {
-	if [ ! -f ${misdn_init_conf} ]; then
-
-		if [ ! -z "$1" ] ; then
-			/usr/sbin/misdn-init config
-		else
-			echo "[!!] failed to load: ${misdn_init_conf}"
-			echo "run \"/usr/sbin/misdn-init config\" to scan your devices and generate a basic config file."
-			exit 1
-		fi
-	fi
-}
-
-# MAIN #############
-
-case "$1" in
-	start|--start)
-		check_cfg_file $2
-
-		${MODPROBE} capi
-		${MODPROBE} mISDN_core debug=0
-		${MODPROBE} mISDN_l1 debug=0
-		${MODPROBE} mISDN_l2 debug=0
-		${MODPROBE} l3udss1 debug=0
-		${MODPROBE} mISDN_capi
-		
-		load_card_modules $2
-		
-		echo "${MODPROBE} mISDN_dsp debug=0x0 options=$dsp_options $dsp_poll_option $dtmfthreshold_option"
-		${MODPROBE} mISDN_dsp debug=0x0 options=$dsp_options $dsp_poll_option $dtmfthreshold_option
-		sleep 1
-		
-		if [ ! -e /dev/mISDN ]; then
-			$MKNOD /dev/mISDN c 46 0
-			if grep asterisk /etc/passwd > /dev/null; then
-				chown $USER:$GROUP /dev/mISDN 
-			fi
-			echo "[i] creating device node: /dev/mISDN"
-		fi
-		;;
-
-	stop|--stop)
-		
-		check_cfg_file
-
-		check_asterisk
-
-		
-		for mod in $(lsmod | ${SED} -ne '/Module/!{s/\([^ ]*\).*/\1/;p}');
-		do
-			case "${mod}" in
-				mISDN_capi | mISDN_dsp | l3udss1 | mISDN_l2 | mISDN_l1 | mISDN_isac )
-					eval "${RMMOD} ${mod}"
-					;;
-			esac
-		done
-
-		unload_card_modules
-
-		${RMMOD} mISDN_core
-
-		;;
-
-	restart|--restart)
-		
-		check_cfg_file
-
-		sh $0 stop
-		sleep 2 # some phones will release tei when layer 1 is down
-		sh $0 start
-		;;
-
-	config|--config)
-
-		create_misdn_init_conf
-
-		;;
-
-	scan|--scan)
-
-		create_misdn_init_conf scan
-
-		;;
-
-	help|--help)
-		echo "Usage: $0 {start|stop|restart|config|scan|help}"
-		exit 0
-		;;
-
-	*)
-		echo "Usage: $0 {start|stop|restart|config|scan|help}"
-		exit 2
-		;;
-
-esac
-
-

Deleted: misdn-kernel/std2kern
===================================================================
--- misdn-kernel-1.1.5/std2kern	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/std2kern	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,325 +0,0 @@
-#!/bin/sh
-
-KERNELDIR=/lib/modules/$(uname -r)/build
-PREPARSER="./preparser"
-UNIQUE=false
-VERBOSE=false
-NOTEST=true
-DODIFF=false
-DIFFREV=false
-ALLOW_ANY_DIR=true
-
-docp() {
-
-    SRCNAME=$1;
-    if $VERBOSE; then
-	echo -n "$SRCNAME... "
-    fi
-
-    # special cases
-    
-    TMPNAME=/tmp/`basename $1`.$$
-    
-    # Makefiles
-    BASENAME=`basename $2`; 
-    if [ "$BASENAME" = "Makefile" ]; then
-	if [ $VERSION -gt 3 -o \( $VERSION -eq 2 -a $PATCHLEVEL -gt 3 \) ]; then
-	    sed -e "s/drivers\/isdn\/Rules\.make/Rules\.make/" < $SRCNAME > $TMPNAME
-	    if $VERBOSE ; then
-		echo -n "processing... modified..."
-	    fi
-	    SRCNAME=$TMPNAME
-	fi
-    fi
-
-    # Rules.make
-    if [ "$BASENAME" = "Rules.make" ]; then
-	if ! [ $VERSION -gt 3 -o \( $VERSION -eq 2 -a $PATCHLEVEL -gt 3 \) ]; then
-	    if $VERBOSE; then
-		echo "skipped"
-	    fi
-	    return
-	fi
-    fi
-
-    # *.[hc] : preparse if selected
-    if $UNIQUE ; then
-        if echo $SRCNAME | egrep -q '.[hc]$'; then
-	    # only copy isdn_compat.h if we don't have a
-	    # delete #include <linux/isdn_compat.h> in the ctrlfile
-	    if [ "$1" = "include/linux/isdn_compat.h" ]; then
-		if grep -q isdn_compat.h $CTRLNAME; then
-		    if $VERBOSE; then
-			echo "skipped"
-		    fi
-		    return
-		fi;
-	    fi
-	    if $VERBOSE; then
-		echo -n "processing... "
-	    fi
-	    $PREPARSER -c $CTRLNAME $SRCNAME $TMPNAME
-	    RETVAL=$?
-	    if [ $RETVAL -ne 2 -a $RETVAL -ne 0 ] ; then 
-		echo "Problem with preparser retval $RETVAL"
-		exit 1
-	    fi
-	    if [ $RETVAL -eq 2 ] ; then
-		if $VERBOSE; then
-		    echo -n "modified... "
-		fi
-		SRCNAME=$TMPNAME
-	    fi
-	fi
-    fi
-
-    if $DODIFF; then
-	if $VERBOSE; then
-	    echo
-	fi
-	if $DIFFREV; then
-	    diff -u $2 $SRCNAME
-        else
-	    diff -u $SRCNAME $2
-	fi
-    else
-	# do the actual copy, if necessary
-	if ! cmp -s $SRCNAME $2 ; then
-	    if $VERBOSE; then
-		echo "copying"
-	    else
-		echo "$1... copying"
-	    fi
-	    if $NOTEST ; then
-		    mkdir -p `dirname $2`
-		    rm -f $2 # unlink first
-		    cp $SRCNAME $2
-	    fi
-	else
-	    if $VERBOSE; then
-		echo "up to date"
-	    fi
-	fi
-    fi
-	
-    if [ -f $TMPNAME ]; then
-	rm -f $TMPNAME
-    fi
-}
-
-#
-# Print usage and exit
-#
-usage() {
-	cat<<EOM
-
-	std2kern is used for updating your kernel-tree from within
-	this directory.
-
-	std2kern [-h] [-k DIR] [-v] [-u] [-c FILE] [files ...]
-
-	Options:
-
-	-h	This Text.
-	-k DIR	Kerneltree is in DIR instead of /usr/src/linux
-        -v      More mesages about processing
-	-u      preprocessing with $PREPARSER
-	-d      don't copy but do a unified diff instead
-	-r      reverse directions of diff
-	-c FILE	Use FILE as control file for $PREPARSER (only with -u)
-	-t      Test, don't really copy files
-	-p PREFIX use PREFIX to install mISDNif.h in the system in the path $PREFIX/usr/include/linux
-
-	Without any files given, within the whole tree, the "right"
-	files are copied. When any files are given in the commandline,
-	only those are copied.
-
-EOM
-	exit
-}
-
-#
-# Check, if argument is a linux kernel dir
-#
-checkkernel() {
-	if [ -f $1/Makefile ] ; then
-		if [ "`grep ^vmlinux: $1/Makefile | grep vmlinux`" != "" ] ; then
-			return 0
-		fi
-	fi
-	echo "The given argument does not look like a kernel dir"
-	if ! $ALLOW_ANY_DIR; then
-	    exit 1
-	fi
-}
-
-#
-# Determine a control file name
-#
-calc_ctrl_file() {
-	if [ -z "$CTRLNAME" ] ; then
-		CTRLNAME=v$VERSION.$PATCHLEVEL.$SUBLEVEL.ctrl
-		if [ -f $CTRLNAME ] ; then
-			return 0
-		fi
-		CTRLNAME=v$VERSION.$PATCHLEVEL.ctrl
-		if [ -f $CTRLNAME ] ; then
-			return 0
-		fi
-		CTRLNAME=default.ctrl
-	fi
-	if [ -f $CTRLNAME ] ; then
-		return 0
-	fi
-	echo "No control file found"
-	exit 1
-}
-
-#
-# Determine a version depend file name
-#
-calc_version_file() {
-	VERSION_NAME=$1.v$VERSION.$PATCHLEVEL.$SUBLEVEL
-	if [ -f $VERSION_NAME ] ; then
-		return 0
-	fi
-	VERSION_NAME=$1.v$VERSION.$PATCHLEVEL
-	if [ -f $VERSION_NAME ] ; then
-		return 0
-	fi
-	VERSION_NAME=""
-	return 1
-}
-
-while getopts :p:dhk:uc:vtidr a ; do
-	case $a in
-		\?)	case $OPTARG in
-				k)	echo "-k requires Kernel directory parameter"
-					;;
-				*)  echo "Unknown option: -$OPTARG"
-					echo "Try std2kern -h"
-					;;
-			esac
-			exit 1
-			;;
-		k)	checkkernel $OPTARG
-			KERNELDIR=$OPTARG
-			;;
-		c)	CTRLNAME=$OPTARG
-			;;
-		u)	UNIQUE=true
-			;;
-		v)	VERBOSE=true
-			;;
-		t)	NOTEST=false
-			;;
-		i)      ALLOW_ANY_DIR=true;
-			;;
-		d)      DODIFF=true;
-			;;
-		r)      DIFFREV=true;
-			;;
-		p)      PREFIX=$OPTARG;
-			;;
-		h)	usage
-			;;
-	esac
-done
-shift `expr $OPTIND - 1`
-
-echo 
-echo "BE AWARE!!"
-echo 
-echo "You are just attempting to overwrite your Kernel mISDN Sources"
-echo "and to install mISDNif.h in your /usr/include/linux directory"
-echo "you probably prefer to use make install."
-echo
-echo "KERNELDIR=$KERNELDIR"
-ls -ld $KERNELDIR
-echo 
-echo "If you still want to patch this Kernel just answer yes:"
-read i
-
-if [ ! $i == "yes" ] ; then
-	echo "OK exiting"
-	exit 1
-fi
-
-#copy mISDNif.h to allow userspace apps to compile againt mISDN
-echo "Installing mISDNif.h in $PREFIX/usr/include/linux/mISDNif.h"
-mkdir -p $PREFIX/usr/include/linux/
-cp include/linux/mISDNif.h $PREFIX/usr/include/linux/
-
-if [ -z "$VERSION" -o -z "$PATCHLEVEL" ] ; then
-    if ! [ -f $KERNELDIR/Makefile ] ; then
-	echo "VERSION/PATCHLEVEL not set and no Makefile to read from"
-	exit 1
-    fi
-    eval `sed -n 's/^\([A-Z]*\) = \([0-9]*\)$/\1=\2/p' $KERNELDIR/Makefile`
-fi
-echo "Current kernel version is $VERSION.$PATCHLEVEL.$SUBLEVEL"
-
-if $UNIQUE ; then
-    calc_ctrl_file
-    echo "Controlfile $CTRLNAME"
-fi
-
-if [ $# != 0 ]; then
-    for i in $* ; do
-	docp $i $KERNELDIR/$i
-    done
-else
-    for i in `find drivers -type f -name '*.[hc]'`; do
-	docp $i $KERNELDIR/$i
-    done
-    for i in `find include -type f -name '*.h'`; do
-	docp $i $KERNELDIR/$i
-    done
-    for i in drivers/isdn/hardware/Makefile \
-	drivers/isdn/hardware/Kconfig \
-	drivers/isdn/hardware/mISDN/Makefile \
-	drivers/isdn/hardware/mISDN/Rules.mISDN \
-	drivers/isdn/hardware/mISDN/Kconfig \
-	drivers/isdn/Config.in \
-	drivers/isdn/Makefile; do
-	calc_version_file $i 
-	if [ -n "$VERSION_NAME" ] ; then
-	    docp $VERSION_NAME $KERNELDIR/$i
-	else
-	    if [ -f $i ] ; then
-		echo "use version independ $i for version v$VERSION.$PATCHLEVEL.$SUBLEVEL"
-		docp $i $KERNELDIR/$i
-	    else
-		echo "no $i for version v$VERSION.$PATCHLEVEL.$SUBLEVEL found -- skipped"
-	    fi
-	fi
-    done
-#    for i in `find Documentation -type f | grep -v CVS`; do
-#	docp $i $KERNELDIR/$i
-#    done
-fi
-exit 0
-
-  if [ -f $KERNELDIR/Documentation/Configure.help ] ; then
-    grep -q CONFIG_ISDN_DIVERSION $KERNELDIR/Documentation/Configure.help
-    if [ $? != 0 ] ; then
-      patch -d $KERNELDIR/Documentation < Documentation/Configure.help.divert.diff
-    fi
-  fi
-  if [ -f $KERNELDIR/Documentation/Configure.help ] ; then
-    grep -q CONFIG_ISDN_DRV_EICON $KERNELDIR/Documentation/Configure.help
-    if [ $? != 0 ] ; then
-      patch -d $KERNELDIR/Documentation < Documentation/Configure.help.eicon.diff
-    fi
-  fi
-  if $NOTEST ; then
-    if [ -f $KERNELDIR/Documentation/Configure.help ] ; then
-      grep -q CONFIG_ISDN_WITH_ABC $KERNELDIR/Documentation/Configure.help
-      if [ $? != 0 ] ; then
-	  if [ -f  Documentation/Configure.help.dwabc.diff ] ; then
-            patch -d $KERNELDIR/Documentation < Documentation/Configure.help.dwabc.diff
-	  fi
-      fi
-    fi
-  fi
-fi

Deleted: misdn-kernel/stddiff
===================================================================
--- misdn-kernel-1.1.5/stddiff	2007-07-17 14:05:57 UTC (rev 3753)
+++ misdn-kernel/stddiff	2007-07-17 14:12:37 UTC (rev 3754)
@@ -1,206 +0,0 @@
-#!/bin/sh
-
-KERNELDIR=/lib/modules/$(uname -r)/build
-KERNFIRST=false
-PREPARSER="./preparser"
-DODIFF=dodiff
-UNIQUE=false
-
-dodiff() {
-  if $KERNFIRST ; then
-    diff -u $EXTRAOPT $2 $1
-  else
-    diff -u $EXTRAOPT $1 $2
-  fi
-}
-
-dodiffuni() {
-    echo -n "Processing $1 ... "
-    TMPNAME=/tmp/`basename $1`.$$ 
-    $PREPARSER -c $CTRLNAME $1 $TMPNAME
-    RES=$?
-    if [ "$RES" -eq "0" ] ; then 
-	echo diff original
-	dodiff $1 $2
-	rm $TMPNAME
-	return 0
-    fi
-    if [ "$RES" -eq "2" ] ; then
-	echo diff modified
-	dodiff $TMPNAME $2
-	rm $TMPNAME
-	return 0
-    fi
-    echo "problem with $PREPARSER retcode $RES"
-    exit 1
-}
-
-
-#
-# Print usage and exit
-#
-usage() {
-	cat<<EOM
-
-	stddiff is used for generating diffs of the cvs-tree
-		versus the kernel-tree.
-
-	stddiff [-r] [-h] [-k DIR] [-u] [-c FILE] [-w] [files ...]
-
-	Options:
-
-	-h      This Text.
-	-r      Reverse direction (kernel versus cvs).
-	-k DIR  Kerneltree is in DIR instead of /usr/src/linux
-	-u      Make a diff for a unique kernel-tree 
-                (preprocessing with $PREPARSER)
-	-c FILE	Use FILE as control file for $PREPARSER (only with -u)
-	-w      Ignore white space when comparing lines 
-
-	Without any files given, within the whole tree, the "right"
-	files are diffed. When any files are given in the commandline,
-	only those are diffed.
-
-EOM
-	exit
-}
-
-#
-# Check, if argument is a linux kernel dir
-#
-checkkernel() {
-	if [ -f $1/Makefile ] ; then
-#		if [ "`grep ^vmlinux: $1/Makefile | grep vmlinux`" != "" ] ; then
-			return 0
-#		fi
-	fi
-	echo "The given argument does not look like a kernel dir"
-	exit 1
-}
-
-#
-# Determine a control file name
-#
-calc_ctrl_file() {
-	eval `sed -n 's/^\([A-Z]*\) = \([0-9]*\)$/\1=\2/p' $KERNELDIR/Makefile`
-	echo "Current kernel version is $VERSION.$PATCHLEVEL.$SUBLEVEL"
-	if [ -z "$CTRLNAME" ] ; then
-		CTRLNAME=v$VERSION.$PATCHLEVEL.$SUBLEVEL.ctrl
-		if [ -f $CTRLNAME ] ; then
-			return 0
-		fi
-		CTRLNAME=v$VERSION.$PATCHLEVEL.ctrl
-		if [ -f $CTRLNAME ] ; then
-			return 0
-		fi
-		CTRLNAME=default.ctrl
-	fi
-	if [ -f $CTRLNAME ] ; then
-		return 0
-	fi
-	echo "No control file found"
-	exit 1
-}
-
-#
-# Determine a version depend file name
-#
-calc_version_file() {
-	VERSION_NAME=$1.v$VERSION.$PATCHLEVEL.$SUBLEVEL
-	if [ -f $VERSION_NAME ] ; then
-		return 0
-	fi
-	VERSION_NAME=$1.v$VERSION.$PATCHLEVEL
-	if [ -f $VERSION_NAME ] ; then
-		return 0
-	fi
-	VERSION_NAME=""
-	return 1
-}
-
-while getopts :rhk:uc:w a ; do
-	case $a in
-		\?) case $OPTARG in
-			k)  echo "-k requires Kernel directory parameter"
-					;;
-			*)  echo "Unknown option: -$OPTARG"
-				echo "Try stddiff -h"
-				;;
-			esac
-			exit 1
-			;;
-		k)  checkkernel $OPTARG
-			KERNELDIR=$OPTARG
-			;;
-		c)  CTRLNAME=$OPTARG
-			;;
-		u)  UNIQUE=true
-			;;
-		r)  KERNFIRST=true
-			;;
-		w)  EXTRAOPT=-w
-			;;
-		h)  usage
-			;;
-	esac
-done
-shift `expr $OPTIND - 1`
-
-if [ -z "$VERSION" -o -z "$PATCHLEVEL" ] ; then
-    if ! [ -f $KERNELDIR/Makefile ] ; then
-	echo "VERSION/PATCHLEVEL not set and no Makefile to read from"
-	exit 1
-    fi
-    eval `sed -n 's/^\([A-Z]*\) = \([0-9]*\)$/\1=\2/p' $KERNELDIR/Makefile`
-fi
-echo "Current kernel version is $VERSION.$PATCHLEVEL.$SUBLEVEL"
-
-if $UNIQUE ; then
-	DODIFF=dodiffuni
-	calc_ctrl_file
-fi
-
-echo -n "Using $DODIFF $EXTRAOPT"
-
-if $UNIQUE ; then
-	echo " with controlfile $CTRLNAME"
-else
-	echo
-fi
-
-if [ $# != 0 ]; then
-	for i in $* ; do
-		$DODIFF $i $KERNELDIR/$i
-	done
-else
-	for i in drivers/isdn/hardware/mISDN/*.[ch] ; do
-		$DODIFF $i $KERNELDIR/$i
-	done
-	for i in include/linux/*.h ; do
-		if [ "$i" = "include/linux/isdn_compat.h" -a \
-		     "$UNIQUE" = "true" ] ; then
-			echo "$i skipped"
-		else
-			$DODIFF $i $KERNELDIR/$i
-		fi
-	done
-	
-	for i in drivers/isdn/hardware/Makefile \
-		drivers/isdn/hardware/Kconfig \
-		drivers/isdn/hardware/mISDN/Makefile \
-		drivers/isdn/hardware/mISDN/Rules.make \
-		drivers/isdn/hardware/mISDN/Kconfig ; do
-		calc_version_file $i 
-		if [ -n "$VERSION_NAME" ] ; then
-	    		dodiff $VERSION_NAME $KERNELDIR/$i
-		else
-			if [ -f $i ] ; then
-				echo "use version independ $i for version v$VERSION.$PATCHLEVEL.$SUBLEVEL"
-				$DODIFF $i $KERNELDIR/$i
-			else
-				echo "no $i for version v$VERSION.$PATCHLEVEL.$SUBLEVEL found -- skipped"
-			fi
-		fi
-	done
-fi
-

Added: misdn-kernel/trunk/CHANGES
===================================================================
--- misdn-kernel/trunk/CHANGES	                        (rev 0)
+++ misdn-kernel/trunk/CHANGES	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,5 @@
+mISDN-1-1-2:
+	- added a workaround that fixes a kernel panic when bridging is done after already a few 
+	  voice frames where transceived on both legs (like when you transfer a call from SIP 2 ISDN)
+	- jollys mail has changed
+	- minor tweaks to misdn-init and to the Kernel-Patch script

Added: misdn-kernel/trunk/Makefile
===================================================================
--- misdn-kernel/trunk/Makefile	                        (rev 0)
+++ misdn-kernel/trunk/Makefile	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,125 @@
+BASEDIR=$(shell pwd)
+
+MAJOR=1
+MINOR=1
+SUBMINOR=5
+
+INSTALL_PREFIX := /
+export INSTALL_PREFIX
+
+#PATH to linux source/headers
+#LINUX=/usr/src/linux
+
+ifndef KVERS
+KVERS:=$(shell uname -r)
+endif
+
+MODS=/lib/modules/$(KVERS)
+LINUX=$(MODS)/build
+LINUX_SOURCE=$(MODS)/source
+UPDATE_MODULES=$(shell which update-modules)
+MODULES_UPDATE=$(shell which modules-update)
+DEPMOD=$(shell which depmod)
+
+
+MISDNDIR=$(BASEDIR)
+MISDN_SRC=$(MISDNDIR)/drivers/isdn/hardware/mISDN
+
+########################################
+# USER CONFIGS END
+########################################
+
+CONFIGS+=CONFIG_MISDN_DRV=m 
+CONFIGS+=CONFIG_MISDN_DSP=m 
+CONFIGS+=CONFIG_MISDN_HFCMULTI=m 
+CONFIGS+=CONFIG_MISDN_HFCPCI=m
+CONFIGS+=CONFIG_MISDN_HFCUSB=m
+CONFIGS+=CONFIG_MISDN_XHFC=m
+CONFIGS+=CONFIG_MISDN_HFCMINI=m
+CONFIGS+=CONFIG_MISDN_W6692=m
+CONFIGS+=CONFIG_MISDN_SPEEDFAX=m
+CONFIGS+=CONFIG_MISDN_AVM_FRITZ=m
+CONFIGS+=CONFIG_MISDN_NETJET=m
+CONFIGS+=CONFIG_MISDN_DEBUGTOOL=m 
+
+#CONFIGS+=CONFIG_MISDN_NETDEV=y
+
+MISDNVERSION=$(shell cat VERSION)
+
+MINCLUDES+=-I$(MISDNDIR)/include
+
+all: VERSION test_old_misdn
+	cp $(MISDNDIR)/drivers/isdn/hardware/mISDN/Makefile.v2.6 $(MISDNDIR)/drivers/isdn/hardware/mISDN/Makefile
+	export MINCLUDES=$(MISDNDIR)/include ; export MISDNVERSION=$(MISDNVERSION); make -C $(LINUX) SUBDIRS=$(MISDN_SRC) modules $(CONFIGS)  
+
+install: all modules-install misdn-init
+	$(DEPMOD) 
+	$(UPDATE_MODULES)
+	$(MODULES_UPDATE)
+	make -C config install
+
+modules-install:
+	cd $(LINUX) ; make INSTALL_MOD_PATH=$(INSTALL_PREFIX) SUBDIRS=$(MISDN_SRC) modules_install 
+	mkdir -p $(INSTALL_PREFIX)/usr/include/linux/
+	cp $(MISDNDIR)/include/linux/*.h $(INSTALL_PREFIX)/usr/include/linux/
+	if [ -e $(INSTALL_PREFIX)/usr/include/linux/mISDNdsp.h ]; then rm -f $(INSTALL_PREFIX)/usr/include/linux/mISDNdsp.h; fi
+
+misdn-init:
+	mkdir -p $(INSTALL_PREFIX)/usr/sbin/
+	install -m755 misdn-init $(INSTALL_PREFIX)/usr/sbin/
+	if [ -d $(INSTALL_PREFIX)/etc/init.d ]; then \
+		if [ -e $(INSTALL_PREFIX)/etc/init.d/misdn-init ]; then rm -rf $(INSTALL_PREFIX)/etc/init.d/misdn-init; fi; \
+		ln -s $(INSTALL_PREFIX)/usr/sbin/misdn-init $(INSTALL_PREFIX)/etc/init.d/misdn-init; \
+	fi
+	mkdir -p $(INSTALL_PREFIX)/etc/modprobe.d
+	cp mISDN.modprobe.d $(INSTALL_PREFIX)/etc/modprobe.d/mISDN
+	mkdir -p $(INSTALL_PREFIX)/etc/modules.d
+	cp mISDN.modprobe.d $(INSTALL_PREFIX)/etc/modules.d/mISDN
+
+test_old_misdn:
+	@if echo -ne "#include <linux/mISDNif.h>" | gcc -C -E - 2>/dev/null 1>/dev/null  ; then \
+		if ! echo -ne "#include <linux/mISDNif.h>\n#if MISDN_MAJOR_VERSION < 4\n#error old mISDNif.h\n#endif\n" | gcc -C -E - 2>/dev/null 1>/dev/null ; then \
+			echo -ne "\n!!You should remove the following files:\n\n$(LINUX)/include/linux/mISDNif.h\n$(LINUX)/include/linux/isdn_compat.h\n/usr/include/linux/mISDNif.h\n/usr/include/linux/isdn_compat.h\n\nIn order to upgrade to the mqueue branch\n\n"; \
+			echo -ne "I can do that for you, just type: make force\n\n" ; \
+			exit 1; \
+		fi ;\
+	fi
+
+
+
+.PHONY: modules-install install all clean misdn-init VERSION
+
+force:
+	rm -f $(LINUX)/include/linux/mISDNif.h
+	rm -f $(LINUX)/include/linux/isdn_compat.h
+	rm -f /usr/include/linux/mISDNif.h
+	rm -f /usr/include/linux/isdn_compat.h
+
+clean:
+	rm -rf drivers/isdn/hardware/mISDN/*.o
+	rm -rf drivers/isdn/hardware/mISDN/*.ko
+	rm -rf *~
+	find . -iname ".*.cmd" -exec rm -rf {} \;
+	find . -iname ".*.d" -exec rm -rf {} \;
+	find . -iname "*.mod.c" -exec rm -rf {} \;
+	find . -iname "*.mod" -exec rm -rf {} \;
+
+VERSION:
+	echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION ; \
+
+snapshot: clean
+	DIR=mISDN-$$(date +"20%y_%m_%d") ; \
+	echo $(MAJOR)_$(MINOR)_$(SUBMINOR)-$$(date +"20%y_%m_%d" | sed -e "s/\//_/g") > VERSION ; \
+	mkdir -p /tmp/$$DIR ; \
+	cp -a * /tmp/$$DIR ; \
+	cd /tmp/; \
+	tar czf $$DIR.tar.gz $$DIR
+
+release: clean
+	DIR=mISDN-$(MAJOR)_$(MINOR)_$(SUBMINOR) ; \
+	echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION ; \
+	mkdir -p /tmp/$$DIR ; \
+	cp -a * /tmp/$$DIR ; \
+	cd /tmp/; \
+	tar czf $$DIR.tar.gz $$DIR
+

Added: misdn-kernel/trunk/Makefile.module
===================================================================
--- misdn-kernel/trunk/Makefile.module	                        (rev 0)
+++ misdn-kernel/trunk/Makefile.module	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,49 @@
+# Master Makefile for the ipppcomp
+# (c) 03/2001 Karsten Keil <kkeil at suse.de>
+# adapted from Kurt Garloffs <garloff at suse.de> SecuMod package
+
+DESTDIR = 
+KDIR := /usr/src/linux
+
+TARGET := mISDN
+TARGETS := Rules.make arch scripts .config include $(TARGET)
+TARGETDIR := drivers/isdn/hardware/mISDN
+
+default: $(TARGETS)
+
+all: $(TARGETS)
+
+Rules.make: $(KDIR)/Rules.make Rules.make.ext
+	cp -pf $(KDIR)/Rules.make .
+	cat Rules.make.ext >> Rules.make
+
+.config: $(KDIR)/.config
+	cp -pf $(KDIR)/.config .
+	cat add.config >> .config
+
+arch: $(KDIR)/arch
+	rm -f arch
+	ln -s $(KDIR)/arch .
+
+scripts: $(KDIR)/scripts
+	rm -f scripts
+	ln -s $(KDIR)/scripts
+
+include: $(KDIR)/include
+	rm -f include
+	ln -s $(KDIR)/include
+
+clean:
+	rm -f $(TARGETS) $(TARGETDIR)/.*.flags $(TARGETDIR)/*.o $(TARGETDIR)/.depend
+	rm -f $(TARGETDIR)/*~ newinclude/linux/*~ *~ .kversion
+	rm -f -r modules .depend .hdepend
+	
+$(TARGET):
+	$(MAKE) -f Makefile KDIR=$(KDIR) TARGETDIR=$(TARGETDIR) $(TARGET)
+
+install: $(TARGETS)
+	$(MAKE) -f Makefile KDIR=$(KDIR) TARGETDIR=$(TARGETDIR) install_mod
+	install newinclude/linux/mISDNif.h /usr/include/linux
+
+modlist:
+	$(MAKE) -f Makefile KDIR=$(KDIR) TARGETDIR=$(TARGETDIR) modlist

Added: misdn-kernel/trunk/Makefile.standalone
===================================================================
--- misdn-kernel/trunk/Makefile.standalone	                        (rev 0)
+++ misdn-kernel/trunk/Makefile.standalone	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,76 @@
+# km_mISDN slave Makefile
+# (c) 10/2001 Karsten Keil <kkeil at suse.de>
+#
+KDIR = /usr/src/linux
+
+DESTDIR =
+TARGET = 
+TARGETS := $(TARGET)
+
+default: $(TARGETS)
+
+all: $(TARGETS)
+
+MYDIR := $(PWD)
+
+TOPDIR := $(KDIR)
+include $(KDIR)/.config
+include $(KDIR)/Makefile
+
+CFLAGS := -I. -I $(KDIR)/drivers/isdn/avmb1 $(CFLAGS) -I $(MYDIR)/newinclude -DLINUX
+CC := $(filter-out -I$(HPATH), $(CC)) -I $(MYDIR)/newinclude -I $(HPATH)
+
+ifdef CONFIG_MODVERSIONS
+CFLAGS := -DMODULE -DMODVERSIONS -include $(MODVERFILE) $(CFLAGS)
+else
+CFLAGS := -DMODULE $(CFLAGS)
+endif
+
+FINDHPATH += $(MYDIR)/newinclude/linux
+
+MODLIB := $(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
+
+mISDN: $(TARGETDIR) depend mISDN_mod 
+	$(MAKE) -C $(TARGETDIR) CFLAGS="$(CFLAGS)" MAKING_MODULES=1 modules
+
+dep-files: scripts/mkdep archdep include/linux/version.h
+	scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
+	$(MAKE) $(patsubst %,_sfdep_%,$(TARGETDIR)) _FASTDEP_ALL_SUB_DIRS="$(TARGETDIR)"
+ifdef CONFIG_MODVERSIONS
+	$(MAKE) update-modverfile
+endif
+
+depend dep: dep-files
+
+ifeq ($(PATCHLEVEL), 2)
+
+TARGETMODDIR = misc
+
+install: install_mod
+
+install_mod: modules_install
+
+mISDN_mod:
+	echo patchlevel $(PATCHLEVEL)
+	mkdir -p modules
+
+else
+
+TARGETMODDIR = ../misc
+
+mISDN_mod:
+	echo patchlevel $(PATCHLEVEL)
+
+install: install_mod
+
+install_mod: $(MODLIB)/$(TARGETMODDIR)
+	$(MAKE) -C $(TARGETDIR) MOD_DESTDIR=$(TARGETMODDIR) modules_install
+
+$(MODLIB)/$(TARGETMODDIR):
+	mkdir -p $(MODLIB)/$(TARGETMODDIR) 
+
+endif
+
+modlist: $(MODLIB)/$(TARGETMODDIR)
+	$(MAKE) -C $(TARGETDIR) MOD_DESTDIR=$(TARGETMODDIR) mod_list
+

Added: misdn-kernel/trunk/README.misdn-init
===================================================================
--- misdn-kernel/trunk/README.misdn-init	                        (rev 0)
+++ misdn-kernel/trunk/README.misdn-init	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,55 @@
+misdn-init: init-script to auto-configure and load the mISDN kernel drivers
+===========================================================================
+
+This script makes it easy to configure and activate mISDN compatible 
+adapter cards. It scans an eyecandy config file named misdn-init.conf
+for your card and port settings, then it loads the driver modules properly.
+The misdn-init.conf can also be autogenerated by the misdn-init script.
+
+---------------------------------------------------------------------------
+Usage: /usr/sbin/misdn-init start|stop|restart|config|scan|help
+
+  --start      scan /etc/misdn-init.conf and load the mISDN drivers
+  --stop       unload the mISDN drivers
+  --restart    see stop, then start
+  --config     scan your PCI bus for mISDN compatible hardware and generate
+               a /etc/misdn-init.conf
+  --scan       scan your PCI bus for mISDN compatible hardware and print
+               the results to the console
+  --help       print the usage info
+---------------------------------------------------------------------------
+
+
+* Here is a quick overview on how to use misdn-init:
+
+1) Get and install misdn-init:
+   $ wget http://www.beronet.com/downloads/chan_misdn/stable/chan_misdn.tar.gz
+   $ tar zxf chan_misdn.tar.gz
+   $ (as root) cp chan_misdn/misdn-init /usr/sbin/misdn-init
+   
+2) Let misdn-init scan your PCI bus for mISDN compatible hardware and write
+   the results into /etc/misdn-init.conf:
+   $ (as root) /usr/sbin/misdn-init config
+ 
+3) (optional) Edit /etc/misdn-init.conf and set everything the way you want it.
+   This file is heavily commented, hence it should be self-explaining.
+
+4) (optional, but recommended) Add misdn-init to your run level.
+   This is distribution dependend. Here an example for a debian system:
+   ATTENTION: If you have services in your runlevels that depend
+              on mISDN, make sure that misdn-init starts before, and
+              stops after them (this is done by changing the values
+              that are set to 60 in this example, more info: read the 
+              manpage for update-rc.d).
+   $ (as root) update-rc.d misdn-init start 60 2 3 4 5 . stop 60 0 1 6 .
+
+5) Run the following to start mISDN:
+   $ (as root) /usr/sbin/misdn-init start
+
+
+
+---------------------------------------------------------------------------
+* Report Bugs:
+If you experience any bugs or have a feature request, please visit:
+www.isdn4linux.de/mantis
+

Added: misdn-kernel/trunk/Rules.make.ext
===================================================================
--- misdn-kernel/trunk/Rules.make.ext	                        (rev 0)
+++ misdn-kernel/trunk/Rules.make.ext	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,5 @@
+
+mod_list: $(obj-m)
+	rm -f $(TOPDIR)/files.mod
+	for i in $(obj-m) ; do echo $(MODLIB)/misc/$$i>>$(TOPDIR)/files.mod; done
+

Added: misdn-kernel/trunk/VERSION
===================================================================
--- misdn-kernel/trunk/VERSION	                        (rev 0)
+++ misdn-kernel/trunk/VERSION	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1 @@
+1_1_5

Added: misdn-kernel/trunk/add.config
===================================================================
--- misdn-kernel/trunk/add.config	                        (rev 0)
+++ misdn-kernel/trunk/add.config	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,10 @@
+#
+# Modular ISDN driver
+#
+CONFIG_MISDN_DRV=m
+CONFIG_MISDN_AVM_FRITZ=y
+CONFIG_MISDN_HFCPCI=y
+CONFIG_MISDN_SPEEDFAX=y
+CONFIG_MISDN_W6692=y
+CONFIG_MISDN_DSP=y
+CONFIG_MISDN_MEMDEBUG=y

Added: misdn-kernel/trunk/config/Makefile
===================================================================
--- misdn-kernel/trunk/config/Makefile	                        (rev 0)
+++ misdn-kernel/trunk/config/Makefile	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,11 @@
+
+all:
+	@echo "Please run 'make install'."
+
+install:
+	install -D -m755 mISDN $(INSTALL_PREFIX)/usr/sbin/mISDN
+	for file in $(shell echo *.xsl); do install -D -m644 $${file} $(INSTALL_PREFIX)/usr/lib/mISDN/$${file}; done
+	if [ -d $(INSTALL_PREFIX)/etc/init.d ]; then \
+		if [ -e $(INSTALL_PREFIX)/etc/init.d/mISDN ]; then rm -rf $(INSTALL_PREFIX)/etc/init.d/mISDN; fi; \
+		ln -s $(INSTALL_PREFIX)/usr/sbin/mISDN $(INSTALL_PREFIX)/etc/init.d/mISDN; \
+	fi

Added: misdn-kernel/trunk/config/README.mISDN
===================================================================
--- misdn-kernel/trunk/config/README.mISDN	                        (rev 0)
+++ misdn-kernel/trunk/config/README.mISDN	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,65 @@
+'mISDN': init-script to auto-configure and load the mISDN kernel drivers
+===========================================================================
+This script makes it easy to configure and activate mISDN compatible 
+adapter cards. It scans an eyecandy config file named mISDN.conf
+for your card and port settings, then it loads the driver modules properly.
+The misdn-init.conf can also be autogenerated by the mISDN script.
+
+
+---------------------------------------------------------------------------
+Requirements:
+
+The 'mISDN' script requires you to install the tool 'xsltproc'. To install 
+xsltproc on debian, just type: 
+
+   $ apt-get install xsltproc (as root)
+
+On other distros the package name might be libxmtools or likewise.
+
+---------------------------------------------------------------------------
+Usage: /usr/sbin/misdn-init start|stop|restart|config|scan|help
+
+  --start      scan /etc/misdn-init.conf and load the mISDN drivers
+  --stop       unload the mISDN drivers
+  --restart    see stop, then start
+  --config     scan your PCI bus for mISDN compatible hardware and generate
+               a /etc/mISDN.conf
+  --scan       scan your PCI bus for mISDN compatible hardware and print
+               the results to the console
+  --help       print the usage info
+---------------------------------------------------------------------------
+
+
+* Here is a quick overview on how to use mISDN:
+
+1) Get and install mISDN:
+   $ wget http://www.misdn.org/downloads/mISDN.tar.gz
+   $ tar xzf mISDN.tar.gz
+   $ cd mISDN*
+   $ make install
+
+   
+2) Let mISDN scan your PCI bus for mISDN compatible hardware and write
+   the results into /etc/mISDN.conf:
+   $ (as root) mISDN config
+ 
+3) (optional) Edit /etc/mISDN.conf and set everything the way you want it.
+   This file is heavily commented, hence it should be self-explaining.
+
+4) (optional, but recommended) Add 'mISDN' to your run level.
+   This is distribution dependend. Here an example for a debian system:
+   ATTENTION: If you have services in your runlevels that depend
+              on mISDN, make sure that 'mISDN' starts before, and
+              stops after them (this is done by changing the values
+              that are set to 60 in this example, more info: read the 
+              manpage for update-rc.d).
+   $ (as root) update-rc.d mISDN start 60 2 3 4 5 . stop 60 0 1 6 .
+
+5) Run the following to start mISDN:
+   $ (as root) mISDN start
+
+---------------------------------------------------------------------------
+* Report Bugs:
+If you experience any bugs or have a feature request, please visit:
+www.isdn4linux.de/mantis
+

Added: misdn-kernel/trunk/config/mISDN
===================================================================
--- misdn-kernel/trunk/config/mISDN	                        (rev 0)
+++ misdn-kernel/trunk/config/mISDN	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,488 @@
+#!/bin/bash
+
+#----------------------------------------------
+#
+# CONFIGURATION:
+#
+MISDN_CONF="/etc/mISDN.conf"
+MISDN_CONF_XSL="/usr/lib/mISDN/mISDN.conf.xsl"
+#
+#----------------------------------------------
+
+SELF="${0}"
+USAGE="Usage: ${SELF} start|stop|restart|config|scan|help"
+
+function die {
+	echo "[!!] ${1}"
+	exit 1
+}
+
+function check_cmd
+{
+	if ! which "${1}" > /dev/null; then
+		if [ "${2}" = "opt" ]; then
+			return
+		fi
+		if [ "$(id -u)" != "0" ]; then
+			die "$1 not in path, please install and/or be root."
+		else
+			die "$1 not in path, please install."
+		fi
+		exit 1
+	else
+		local var=$(echo ${1} | tr a-z A-Z)
+		eval "$var=`which ${1}`"
+	fi
+}
+
+function check_misdn_conf
+{
+	if [ ! -f ${MISDN_CONF} ]; then
+		die "${MISDN_CONF} not found. Please run: ${SELF} config"
+	fi
+}
+
+check_cmd sed
+check_cmd cut
+check_cmd cp
+check_cmd wc
+check_cmd grep
+check_cmd xsltproc
+check_cmd modprobe
+check_cmd sleep
+check_cmd lspci
+check_cmd lsusb opt
+check_cmd mknod
+check_cmd chown
+check_cmd chmod
+
+declare -a START_COMMANDS
+declare -a STOP_COMMANDS
+
+declare -a HFCMULTI_card
+declare -a HFCMULTI_type
+declare -a HFCMULTI_protocol
+declare -a HFCMULTI_layermask
+HFCMULTI_options=''
+MISDNDSP_options=''
+L1OIP_options=''
+
+AVMFRITZ_protocol=''
+AVMFRITZ_layermask=''
+
+HFCPCI_protocol=''
+HFCPCI_layermask=''
+
+L1OIP_type=''
+L1OIP_protocol=''
+L1OIP_layermask=''
+L1OIP_codec=''
+L1OIP_ip=''
+L1OIP_port=''
+L1OIP_localport=''
+L1OIP_ondemand=''
+L1OIP_id=''
+
+DEVNODE_user='root'
+DEVNODE_group='root'
+DEVNODE_mode='0644'
+
+declare -a SCAN_card
+declare -a SCAN_opts
+declare -a SCAN_num_ports
+declare -a SCAN_port_opts
+
+function parse_config
+{
+	local CONFIG=$(${XSLTPROC} ${MISDN_CONF_XSL} ${MISDN_CONF})
+	local t p l line i tmpcmd curr tmpstr extra_modules val
+	local IFS=$'\n'
+	
+	START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install capi"
+	START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_core debug=0"
+	START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_l1 debug=0"
+	START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_l2 debug=0"
+	START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install l3udss1 debug=0"
+	START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_capi"
+	
+	for line in ${CONFIG}; do
+		case "${line}" in
+			DEVNODE:mISDN*)
+				tmpstr=$(echo ${line} | ${SED} -n 's/.*user:\([^ ]*\).*/\1/p')
+				if [ ! -z "${tmpstr}" ]; then
+					DEVNODE_user="${tmpstr}"
+				fi
+				tmpstr=$(echo ${line} | ${SED} -n 's/.*group:\([^ ]*\).*/\1/p')
+				if [ ! -z "${tmpstr}" ]; then
+					DEVNODE_group="${tmpstr}"
+				fi
+				tmpstr=$(echo ${line} | ${SED} -n 's/.*mode:\([^ ]*\).*/\1/p')
+				if [ ! -z "${tmpstr}" ]; then
+					DEVNODE_mode="${tmpstr}"
+				fi
+				;;
+			MODULE:hfcmulti*)
+				HFCMULTI_options=${line:16}
+				;;
+			MODULE:mISDN_debugtool*)
+				extra_modules[${#extra_modules[@]}]=${line:7}
+				;;
+			MODULE:mISDN_dsp*)
+				MISDNDSP_options=${line:17}
+				;;
+			MODULE:l1oip*)
+				L1OIP_options=${line:13}
+				;;
+			CARD:BN*)
+				curr='hfcmulti'
+				i=${#HFCMULTI_type[@]}
+				let "t = $(echo ${line} | ${SED} -n 's/.*type:\([^,]*\).*/\1/p')"
+				HFCMULTI_type[${i}]=$(printf "0x%x" ${t})
+
+# this is for the BN2E1 card that needs two type numbers
+				t=$(echo ${line} | ${SED} -n 's/.*type:[^,]*,\([^ ]*\).*/\1/p')
+				if [ ! -z "${t}" ]; then
+					let "t = ${t}"
+					HFCMULTI_type[${i}]="${HFCMULTI_type[${i}]},$(printf "0x%x" ${t})"
+				fi
+
+				HFCMULTI_card[${i}]=$(echo ${line:5} | ${CUT} -d" " -f1)
+				;;
+			CARD:hfcpci*)
+				curr='hfcpci'
+				;;
+			CARD:avmfritz*)
+				curr='avmfritz'
+				;;
+			CARD:l1oip*)
+				curr='l1oip'
+				;;
+			PORT*)
+				case "${curr}" in
+					hfcmulti)
+						let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
+						HFCMULTI_protocol[${i}]="${HFCMULTI_protocol[${i}]:+"${HFCMULTI_protocol[${i}]},"}$(printf "0x%x" ${p})"
+						let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
+						HFCMULTI_layermask[${i}]="${HFCMULTI_layermask[${i}]:+"${HFCMULTI_layermask[${i}]},"}$(printf "0x%x" ${l})"
+						;;
+					hfcpci)
+						let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
+						HFCPCI_protocol="${HFCPCI_protocol:+"${HFCPCI_protocol},"}$(printf "0x%x" ${p})"
+						let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
+						HFCPCI_layermask="${HFCPCI_layermask:+"${HFCPCI_layermask},"}$(printf "0x%x" ${l})"
+						;;
+					avmfritz)
+						let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
+						AVMFRITZ_protocol="${AVMFRITZ_protocol:+"${AVMFRITZ_protocol},"}$(printf "0x%x" ${p})"
+						let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
+						AVMFRITZ_layermask="${AVMFRITZ_layermask:+"${AVMFRITZ_layermask},"}$(printf "0x%x" ${l})"
+						;;
+					l1oip)
+						let "val = $(echo ${line} | ${SED} -n 's/.*type:\([^ ]*\).*/\1/p')"
+						L1OIP_type="${L1OIP_type:+"${L1OIP_type},"}$(printf "0x%x" ${val})"
+						let "val = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
+						L1OIP_protocol="${L1OIP_protocol:+"${L1OIP_protocol},"}$(printf "0x%x" ${val})"
+						let "val = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
+						L1OIP_layermask="${L1OIP_layermask:+"${L1OIP_layermask},"}$(printf "0x%x" ${val})"
+						val="$(echo ${line} | ${SED} -n 's/.*codec:\([^ ]*\).*/\1/p')"
+						L1OIP_codec="${L1OIP_codec:+"${L1OIP_codec},"}${val}"
+						val="$(echo ${line} | ${SED} -n 's/.*ip:\([^ ]*\).*/\1/p')"
+						L1OIP_ip="${L1OIP_ip:+"${L1OIP_ip},"}${val}"
+						val="$(echo ${line} | ${SED} -n 's/.*port:\([^ ]*\).*/\1/p')"
+						L1OIP_port="${L1OIP_port:+"${L1OIP_port},"}${val}"
+						val="$(echo ${line} | ${SED} -n 's/.*localport:\([^ ]*\).*/\1/p')"
+						L1OIP_localport="${L1OIP_localport:+"${L1OIP_localport},"}${val}"
+						val="$(echo ${line} | ${SED} -n 's/.*ondemand:\([^ ]*\).*/\1/p')"
+						L1OIP_ondemand="${L1OIP_ondemand:+"${L1OIP_ondemand},"}${val}"
+						val="$(echo ${line} | ${SED} -n 's/.*id:\([^ ]*\).*/\1/p')"
+						L1OIP_id="${L1OIP_id:+"${L1OIP_id},"}${val}"
+						;;
+				esac
+				;;
+		esac
+	done
+
+	if [ ! -z "${HFCMULTI_protocol[0]}" ]; then
+		tmpcmd="${MODPROBE} --ignore-install hfcmulti type=${HFCMULTI_type[0]}"
+		i=1
+		while [ ! -z "${HFCMULTI_type[${i}]}" ]; do
+			tmpcmd="${tmpcmd},${HFCMULTI_type[${i}]}"
+			let "i = ${i} + 1"
+		done
+		tmpcmd="${tmpcmd} protocol=${HFCMULTI_protocol[0]}"
+		i=1
+		while [ ! -z "${HFCMULTI_protocol[${i}]}" ]; do
+			tmpcmd="${tmpcmd},${HFCMULTI_protocol[${i}]}"
+			let "i = ${i} + 1"
+		done
+		tmpcmd="${tmpcmd} layermask=${HFCMULTI_layermask[0]}"
+		i=1
+		while [ ! -z "${HFCMULTI_layermask[${i}]}" ]; do
+			tmpcmd="${tmpcmd},${HFCMULTI_layermask[${i}]}"
+			let "i = ${i} + 1"
+		done
+		START_COMMANDS[${#START_COMMANDS[@]}]="${tmpcmd} ${HFCMULTI_options}"
+	fi
+
+	if [ ! -z "${HFCPCI_protocol}" ]; then
+		START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install hfcpci protocol=${HFCPCI_protocol} layermask=${HFCPCI_layermask}"
+	fi
+
+	if [ ! -z "${AVMFRITZ_protocol}" ]; then
+		START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install avmfritz protocol=${AVMFRITZ_protocol} layermask=${AVMFRITZ_layermask}"
+	fi
+
+	if [ ! -z "${L1OIP_type}" ]; then
+		START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install l1oip type=${L1OIP_type} protocol=${L1OIP_protocol} layermask=${L1OIP_layermask} codec=${L1OIP_codec} ip=${L1OIP_ip} port=${L1OIP_port} localport=${L1OIP_localport} ondemand=${L1OIP_ondemand} id=${L1OIP_id} ${L1OIP_options}"
+	fi
+
+	START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_dsp ${MISDNDSP_options}"
+
+	i=1
+	while [ ! -z "${extra_modules[${i}]}" ]; do
+		START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install ${extra_modules[${i}]}"
+		let "i = ${i} + 1"
+	done
+}
+
+function run_start_commands
+{
+	local i=0
+
+	echo "-- Loading mISDN modules --"
+	while [ ! -z "${START_COMMANDS[${i}]}" ]; do
+		echo ">> ${START_COMMANDS[${i}]}"
+		eval "${START_COMMANDS[${i}]}"
+		let "i = ${i} + 1"
+	done
+}
+
+function run_stop_commands
+{
+	local mod i=0
+
+	for mod in $(lsmod | ${SED} -ne '/Module/!{s/\([^ ]*\).*/\1/;p}');	do
+		case "${mod}" in
+			mISDN_capi | mISDN_dsp | l3udss1 | mISDN_l2 | mISDN_l1 | mISDN_isac | hfcmulti | hfcpci | avmfritz | l1oip)
+				STOP_COMMANDS[0]="${STOP_COMMANDS[0]:-"${MODPROBE} -r --ignore-remove"} ${mod}"
+				;;
+			mISDN_debugtool)
+				STOP_COMMANDS[1]="${MODPROBE} -r --ignore-remove mISDN_debugtool"
+				;;
+			mISDN_core)
+				STOP_COMMANDS[2]="${MODPROBE} -r --ignore-remove mISDN_core"
+				;;
+		esac
+	done
+
+	echo "-- Unloading mISDN modules --"
+	for i in `seq 0 1 2`; do
+		if [ ! -z "${STOP_COMMANDS[${i}]}" ]; then
+			echo ">> ${STOP_COMMANDS[${i}]}"
+			eval "${STOP_COMMANDS[${i}]}"
+		fi
+	done
+}
+
+function scan_devices
+{
+	local skipnext=0 IFS=$'\n'
+	local NL="
+"
+	
+	function addcard {
+		SCAN_card[${#SCAN_card[@]}]="${1}"
+		SCAN_opts[${#SCAN_opts[@]}]="${2}"
+		SCAN_num_ports[${#SCAN_num_ports[@]}]="${3}"
+		SCAN_port_opts[${#SCAN_port_opts[@]}]="${4}"
+	}
+
+	for line in $(${LSPCI} -n -d 0xd161:b410); do
+		addcard "BN4S0" "" 4 'mode="te" link="ptmp"'
+	done
+
+	for line in $(${LSPCI} -n | ${SED} -n 's/^\(0000:\|\)\([0-9a-f]\{2\}:[0-9a-f]\{2\}.[0-9a-f]\{1\}\)\( Class \| \)[0-9a-f]\{4\}: 1397:\([0-9a-f]\{4\}\).*$/\4 \2/p'); do
+		if [ ${skipnext} -eq 1 ]; then
+			skipnext=0
+			continue
+		fi
+		case "${line}" in
+			30b1*)
+				case "${line:5}" in
+					00*)
+						addcard "BN1E1" "" 1 'mode="nt" link="ptp"'
+						;;
+					*)
+						if [ $(${LSPCI} -n -s "${line:5:3}" -d 0x1397:30b1 | ${WC} -l) -eq 2 ]; then
+							addcard "BN2E1" "" 2 'mode="nt" link="ptp"'
+							skipnext=1
+						else
+							addcard "BN1E1" "" 1 'mode="nt" link="ptp"'
+						fi
+						;;
+				esac
+				;;
+			16b8*)
+				addcard "BN8S0" "" 8 'mode="te" link="ptmp"'
+				;;
+			08b4*)
+				if ${LSPCI} -n -v -s "${line:5}" | ${GREP} "Subsystem" | ${GREP} "1397:b567" > /dev/null ; then
+					addcard "BN1S0" "" 1 'mode="te" link="ptmp"'
+				elif ${LSPCI} -n -v -s "${line:5}" | ${GREP} "Subsystem" | ${GREP} "1397:b566\|1397:b569" > /dev/null ; then
+					addcard "BN2S0" "" 2 'mode="te" link="ptmp"'
+				else
+					addcard "BN4S0" "" 4 'mode="te" link="ptmp"'
+				fi
+				;;
+		esac
+	done
+	for line in $(${LSPCI} -n | ${GREP} "1397:\(2bd\(0\|6\|7\|8\|9\|a\|b\|c\)\|b100\)\|1043:0675\|0871:ffa\(1\|2\)\|1051:0100\|15b0:2bd0\|114f:007\(0\|1\|2\|3\)\|13d1:2bd1\|182d:3069"); do
+		addcard "hfcpci" "" 1 'mode="te" link="ptmp"'
+	done
+	for line in $(${LSPCI} -n | ${GREP} "1244:\(0a00\|0e00\)"); do
+		addcard "avmfritz" "" 1 'mode="te" link="ptmp"'
+	done
+	for line in $(${LSPCI} -n -d 1050:6692); do
+		addcard "w6692pci" "" 1 'mode="te" link="ptmp"'
+	done
+	if [ -e ${LSUSB} ]; then 
+		for line in $(${LSUSB} | ${GREP} "0959:2bd0\|0675:1688\|07b0:0007\|0742:200\(7\|8\|9\|A\)\|08e3:0301\|07fa:084\(7\|8\)\|07ba:0006"); do
+			addcard "hfcsusb" "" 1 'mode="te" link="ptmp"'
+		done
+	fi
+}
+
+function write_mISDN_conf
+{
+	local NL="
+"
+	local TAB="	"
+	local HEADER="<?xml version=\"1.0\"?>
+<!--
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Card Type: BN2S0, BN4S0, BN8S0
+Card Attributes: ulaw=(yes|no), dtmf=(yes|no), pcm_slave=(yes|no),
+                 ignore_pcm_frameclock=(yes|no), rxclock=(yes|no),
+                 crystalclock=(yes|no), watchdog=(yes|no)
+Port Attributes: mode=(te|nt), link=(ptp|ptmp), master-clock=(yes|no),
+                 capi=(yes|no)
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Card Type: BN2E1
+Card Attributes: ulaw=(yes|no), dtmf=(yes|no), pcm_slave=(yes|no),
+                 ignore_pcm_frameclock=(yes|no), rxclock=(yes|no),
+                 crystalclock=(yes|no), watchdog=(yes|no)
+Port Attributes: mode=(te|nt), link=(ptp|ptmp), optical=(yes|no), los=(yes|no),
+                 ais=(yes|no), slip=(yes|no), nocrc4=(yes|no), capi=(yes|no)
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Card Type: hfcmulti, avmfritz, w6692pci
+Port Attributes: mode=(te|nt), link=(ptp|ptmp), capi=(yes|no)
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Module: hfcmulti
+Options: poll=<number>, pcm=<number>, debug=<number>, timer=(yes|no)
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Module: mISDN_dsp
+Options: debug=<number>, options=<number>, poll=<number>,
+         dtmfthreshold=<number>
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+-->
+<mISDNconf>
+${TAB}<module poll=\"128\" debug=\"0\" timer=\"no\">hfcmulti</module>
+${TAB}<module debug=\"0\" options=\"0\">mISDN_dsp</module>
+${TAB}<devnode user=\"root\" group=\"root\" mode=\"644\">mISDN</devnode>"
+	local FOOTER="</mISDNconf>"
+	local i=0 j=0 MAIN=""
+
+	echo "Writing ${MISDN_CONF} for ${#SCAN_card[@]} mISDN compatible device(s):"
+	while [ ! -z "${SCAN_card[${i}]}" ]; do
+		echo ">> ${SCAN_card[${i}]}"
+		MAIN="${MAIN}${NL}${TAB}<card type=\"${SCAN_card[${i}]}\"${SCAN_opts[${i}]:+" ${SCAN_opts[${i}]}"}>"
+		j=1
+		while [ ${j} -le ${SCAN_num_ports[${i}]} ]; do
+			MAIN="${MAIN}${NL}${TAB}${TAB}<port${SCAN_port_opts[${i}]:+" ${SCAN_port_opts[${i}]}"}>${j}</port>"
+			let "j = ${j} + 1"
+		done
+		MAIN="${MAIN}${NL}${TAB}</card>"
+		let "i = ${i} + 1"
+	done
+
+	if [ -f ${MISDN_CONF} ]; then
+		echo "${MISDN_CONF} already present, saving a backup: ${MISDN_CONF}.bak"
+		${CP} "${MISDN_CONF}" "${MISDN_CONF}.bak" || die "Could not backup your existing ${MISDN_CONF}!"
+	fi
+	echo "${HEADER}${MAIN}${NL}${FOOTER}" > ${MISDN_CONF}
+}
+
+function print_scan_results
+{
+	local i=0
+	
+	echo "${#SCAN_card[@]} mISDN compatible device(s) found:"
+	while [ ! -z "${SCAN_card[${i}]}" ]; do
+		echo ">> ${SCAN_card[${i}]}"
+		let "i = ${i} + 1"
+	done
+}
+
+function mk_misdn_dev
+{
+	if [ ! -e /dev/mISDN ]; then
+		echo "creating device node: /dev/mISDN"
+		${MKNOD} /dev/mISDN c 46 0
+	fi
+	${CHOWN} ${DEVNODE_user}:${DEVNODE_group} /dev/mISDN
+	${CHMOD} ${DEVNODE_mode} /dev/mISDN
+}
+
+#
+# MAIN
+#
+
+case "${1}" in
+
+	start|--start)
+
+		check_misdn_conf
+		parse_config
+		run_start_commands
+		mk_misdn_dev
+		;;
+
+	stop|--stop)
+
+		run_stop_commands
+		;;
+
+	restart|--restart)
+
+		check_misdn_conf
+		parse_config
+		run_stop_commands
+		${SLEEP} 2
+		run_start_commands
+		mk_misdn_dev
+		;;
+
+	config|--config)
+		
+		scan_devices
+		write_mISDN_conf
+		;;
+
+	scan|--scan)
+
+		scan_devices
+		print_scan_results
+		;;
+
+	help|--help)
+		echo "${USAGE}"
+		exit 0
+		;;
+
+	*)
+		echo "${USAGE}"
+		exit 2
+		;;
+
+esac
+


Property changes on: misdn-kernel/trunk/config/mISDN
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-kernel/trunk/config/mISDN.conf
===================================================================
--- misdn-kernel/trunk/config/mISDN.conf	                        (rev 0)
+++ misdn-kernel/trunk/config/mISDN.conf	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<mISDNconf>
+	<card type="BN8S0">
+		<port mode="nt" link="ptmp">1</port>
+		<port mode="nt" link="ptmp">2</port>
+		<port mode="te" link="ptmp">3</port>
+		<port mode="te" link="ptmp">4</port>
+		<port mode="nt" link="ptmp">5</port>
+		<port mode="nt" link="ptmp">6</port>
+		<port mode="te" link="ptmp">7</port>
+		<port mode="te" link="ptmp">8</port>
+	</card>
+</mISDNconf>

Added: misdn-kernel/trunk/config/mISDN.conf.bnx.xsl
===================================================================
--- misdn-kernel/trunk/config/mISDN.conf.bnx.xsl	                        (rev 0)
+++ misdn-kernel/trunk/config/mISDN.conf.bnx.xsl	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
+
+<!--
+	Card Type: BN2S0, BN4S0, BN8S0
+	Ports: 2, 4, 8
+	Card Attributes: ulaw=(yes|no), dtmf=(yes|no), pcm_slave=(yes|no), ignore_pcm_frameclock=(yes|no),
+	                 rxclock=(yes|no), crystalclock=(yes|no), watchdog=(yes|no)
+	Port Attributes: mode=(te|nt), link=(ptp|ptmp), master-clock=(yes|no), capi=(yes|no)
+-->
+<xsl:template name="type-options">
+<xsl:param name="force-pcm-slave">no</xsl:param>
+
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@ulaw" />
+ <xsl:with-param name="val-true">(2**8)</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@dtmf" />
+ <xsl:with-param name="val-true">(2**9)</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:choose>
+ <xsl:when test="$force-pcm-slave='yes'">
+  <xsl:text>(2**11)</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+  <xsl:call-template name="if-match">
+   <xsl:with-param name="val" select="@pcm_slave" />
+   <xsl:with-param name="val-true">(2**11)</xsl:with-param>
+  </xsl:call-template>
+ </xsl:otherwise>
+</xsl:choose>
+<xsl:text>+</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@ignore_pcm_frameclock" />
+ <xsl:with-param name="val-true">(2**12)</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@rxclock" />
+ <xsl:with-param name="val-true">(2**13)</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@crystalclock" />
+ <xsl:with-param name="val-true">(2**18)</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@watchdog" />
+ <xsl:with-param name="val-true">(2**19)</xsl:with-param>
+</xsl:call-template>
+</xsl:template>
+
+<xsl:template name="BN2S0card">
+<xsl:param name="type">4</xsl:param>
+<xsl:value-of select="concat(' type:',$type,'+')" />
+<xsl:call-template name="type-options" />
+<xsl:text>
+</xsl:text>
+</xsl:template>
+
+<xsl:template name="BN2S0port">
+
+<xsl:text> layermask:</xsl:text>
+<xsl:choose>
+<xsl:when test="@mode='nt'">
+ <xsl:text>3</xsl:text>
+</xsl:when>
+<xsl:when test="@capi='yes'">
+ <xsl:text>0</xsl:text>
+</xsl:when>
+<xsl:otherwise>
+ <xsl:text>15</xsl:text>
+</xsl:otherwise>
+</xsl:choose>
+
+<xsl:text> protocol:</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@mode" />
+ <xsl:with-param name="match-true">te</xsl:with-param>
+ <xsl:with-param name="match-false">nt</xsl:with-param>
+ <xsl:with-param name="val-true">34</xsl:with-param>
+ <xsl:with-param name="val-false">18</xsl:with-param>
+ <xsl:with-param name="val-default">34</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:if test="@mode!='nt'">
+ <xsl:call-template name="if-match">
+  <xsl:with-param name="val" select="@link" />
+  <xsl:with-param name="match-true">ptp</xsl:with-param>
+  <xsl:with-param name="match-false">ptmp</xsl:with-param>
+  <xsl:with-param name="val-true">0</xsl:with-param>
+  <xsl:with-param name="val-false">(-32)</xsl:with-param>
+  <xsl:with-param name="val-default">(-32)</xsl:with-param>
+ </xsl:call-template>
+ <xsl:text>+</xsl:text>
+</xsl:if>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@master-clock" />
+ <xsl:with-param name="val-true">(2**16)</xsl:with-param>
+</xsl:call-template>
+
+<xsl:text> capi:</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@capi" />
+ <xsl:with-param name="val-true">yes</xsl:with-param>
+ <xsl:with-param name="val-false">no</xsl:with-param>
+ <xsl:with-param name="val-default">no</xsl:with-param>
+</xsl:call-template>
+
+<xsl:text>
+</xsl:text>
+</xsl:template>
+
+<xsl:template name="BN4S0card">
+<xsl:call-template name="BN2S0card">
+ <xsl:with-param name="type">4</xsl:with-param>
+</xsl:call-template>
+</xsl:template>
+
+<xsl:template name="BN4S0port">
+<xsl:call-template name="BN2S0port" />
+</xsl:template>
+
+<xsl:template name="BN8S0card">
+<xsl:call-template name="BN2S0card">
+ <xsl:with-param name="type">8</xsl:with-param>
+</xsl:call-template>
+</xsl:template>
+
+<xsl:template name="BN8S0port">
+<xsl:call-template name="BN2S0port" />
+</xsl:template>
+
+<!--
+	Card Type: BN2E1
+	Ports: 2
+	Card Attributes: ulaw=(yes|no), dtmf=(yes|no), pcm_slave=(yes|no), ignore_pcm_frameclock=(yes|no),
+	                 rxclock=(yes|no), crystalclock=(yes|no), watchdog=(yes|no)
+	Port Attributes: mode=(te|nt), link=(ptp|ptmp), optical=(yes|no), los=(yes|no), ais=(yes|no),
+	                 slip=(yes|no), nocrc4=(yes|no), capi=(yes|no)
+-->
+<xsl:template name="BN2E1card">
+<xsl:text> type:1+</xsl:text>
+<xsl:call-template name="type-options" />
+<xsl:text>,1+</xsl:text>
+<xsl:call-template name="type-options">
+ <xsl:with-param name="force-pcm-slave">yes</xsl:with-param>
+</xsl:call-template>
+<xsl:text>
+</xsl:text>
+</xsl:template>
+
+<xsl:template name="BN2E1port">
+<xsl:text> layermask:</xsl:text>
+<xsl:choose>
+<xsl:when test="@mode='nt'">
+ <xsl:text>3</xsl:text>
+</xsl:when>
+<xsl:when test="@capi='yes'">
+ <xsl:text>0</xsl:text>
+</xsl:when>
+<xsl:otherwise>
+ <xsl:text>15</xsl:text>
+</xsl:otherwise>
+</xsl:choose>
+
+<xsl:text> protocol:</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@mode" />
+ <xsl:with-param name="match-true">te</xsl:with-param>
+ <xsl:with-param name="match-false">nt</xsl:with-param>
+ <xsl:with-param name="val-true">34</xsl:with-param>
+ <xsl:with-param name="val-false">18</xsl:with-param>
+ <xsl:with-param name="val-default">34</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:if test="@mode!='nt'">
+ <xsl:call-template name="if-match">
+  <xsl:with-param name="val" select="@link" />
+  <xsl:with-param name="match-true">ptp</xsl:with-param>
+  <xsl:with-param name="match-false">ptmp</xsl:with-param>
+  <xsl:with-param name="val-true">0</xsl:with-param>
+  <xsl:with-param name="val-false">(-32)</xsl:with-param>
+  <xsl:with-param name="val-default">(-32)</xsl:with-param>
+ </xsl:call-template>
+ <xsl:text>+</xsl:text>
+</xsl:if>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@optical" />
+ <xsl:with-param name="val-true">(2**16)</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@los" />
+ <xsl:with-param name="val-true">(2**18)</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@ais" />
+ <xsl:with-param name="val-true">(2**19)</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@slip" />
+ <xsl:with-param name="val-true">(2**21)</xsl:with-param>
+</xsl:call-template>
+<xsl:text>+</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@nocrc4" />
+ <xsl:with-param name="val-true">(2**23)</xsl:with-param>
+</xsl:call-template>
+
+<xsl:text> capi:</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@capi" />
+ <xsl:with-param name="val-true">yes</xsl:with-param>
+ <xsl:with-param name="val-false">no</xsl:with-param>
+ <xsl:with-param name="val-default">no</xsl:with-param>
+</xsl:call-template>
+
+<xsl:text>
+</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>

Added: misdn-kernel/trunk/config/mISDN.conf.hfcmulti.xsl
===================================================================
--- misdn-kernel/trunk/config/mISDN.conf.hfcmulti.xsl	                        (rev 0)
+++ misdn-kernel/trunk/config/mISDN.conf.hfcmulti.xsl	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
+
+<!--
+	Module: hfcmulti
+	Options: poll=<number>, pcm=<number>, debug=<number>, timer=(yes|no)
+-->
+<xsl:template name="HFCMULTImodule">
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> poll=</xsl:with-param>
+ <xsl:with-param name="val" select="@poll" />
+ <xsl:with-param name="val-default">128</xsl:with-param>
+</xsl:call-template>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> pcm=</xsl:with-param>
+ <xsl:with-param name="val" select="@pcm" />
+</xsl:call-template>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> debug=</xsl:with-param>
+ <xsl:with-param name="val" select="@debug" />
+ <xsl:with-param name="val-default">0</xsl:with-param>
+</xsl:call-template>
+
+<xsl:call-template name="if-set-match">
+ <xsl:with-param name="prefix"> timer=</xsl:with-param>
+ <xsl:with-param name="val" select="@timer" />
+ <xsl:with-param name="val-default">0</xsl:with-param>
+ <xsl:with-param name="val-true">1</xsl:with-param>
+</xsl:call-template>
+
+<xsl:text>
+</xsl:text>
+
+</xsl:template>
+
+</xsl:stylesheet>

Added: misdn-kernel/trunk/config/mISDN.conf.inc.xsl
===================================================================
--- misdn-kernel/trunk/config/mISDN.conf.inc.xsl	                        (rev 0)
+++ misdn-kernel/trunk/config/mISDN.conf.inc.xsl	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
+
+<xsl:template name="if-set">
+ <xsl:param name="prefix"></xsl:param>
+ <xsl:param name="val"></xsl:param>
+ <xsl:param name="val-default"></xsl:param>
+ <xsl:choose>
+  <xsl:when test="$val!=''">
+   <xsl:value-of select="concat($prefix,$val)" />
+  </xsl:when>
+  <xsl:otherwise>
+   <xsl:if test="$val-default!=''">
+    <xsl:value-of select="concat($prefix,$val-default)" />
+   </xsl:if>
+  </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="if-set-match">
+ <xsl:param name="prefix"></xsl:param>
+ <xsl:param name="val"></xsl:param>
+ <xsl:param name="val-default"></xsl:param>
+ <xsl:param name="val-true">0</xsl:param>
+ <xsl:param name="val-false">0</xsl:param>
+ <xsl:param name="match-true">yes</xsl:param>
+ <xsl:param name="match-false">no</xsl:param>
+ <xsl:choose>
+  <xsl:when test="$val=$match-true">
+   <xsl:value-of select="concat($prefix,$val-true)" />
+  </xsl:when>
+  <xsl:when test="$val=$match-false">
+   <xsl:value-of select="concat($prefix,$val-false)" />
+  </xsl:when>
+  <xsl:otherwise>
+   <xsl:if test="$val-default!=''">
+    <xsl:value-of select="concat($prefix,$val-default)" />
+   </xsl:if>
+  </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="if-match">
+ <xsl:param name="val">no</xsl:param>
+ <xsl:param name="val-default">0</xsl:param>
+ <xsl:param name="val-true">0</xsl:param>
+ <xsl:param name="val-false">0</xsl:param>
+ <xsl:param name="match-true">yes</xsl:param>
+ <xsl:param name="match-false">no</xsl:param>
+ <xsl:choose>
+  <xsl:when test="$val=$match-true">
+   <xsl:value-of select="$val-true" />
+  </xsl:when>
+  <xsl:when test="$val=$match-false">
+   <xsl:value-of select="$val-false" />
+  </xsl:when>
+  <xsl:otherwise>
+   <xsl:value-of select="$val-default" />
+  </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>

Added: misdn-kernel/trunk/config/mISDN.conf.l1oip.xsl
===================================================================
--- misdn-kernel/trunk/config/mISDN.conf.l1oip.xsl	                        (rev 0)
+++ misdn-kernel/trunk/config/mISDN.conf.l1oip.xsl	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
+
+<!--
+	Module: l1oip
+	Options: poll=<number>, pcm=<number>, debug=<number>, timer=(yes|no)
+-->
+<xsl:template name="L1OIPmodule">
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> debug=</xsl:with-param>
+ <xsl:with-param name="val" select="@debug" />
+ <xsl:with-param name="val-default">0</xsl:with-param>
+</xsl:call-template>
+
+<xsl:text>
+</xsl:text>
+
+</xsl:template>
+
+<!--
+	Card Type: l1oip
+	Ports: n
+	Port Attributes: mode=(te|nt), link=(ptp|ptmp), type=(bri|pri|bri-mc|pri-mc), codec=0, ip=n,n,n,n port=<number>,
+                     localport=<number>, ondemand=(0|1), id=<random-id>
+-->
+<xsl:template name="L1OIPcard">
+<xsl:text>
+</xsl:text>
+</xsl:template>
+
+<xsl:template name="L1OIPport">
+<xsl:text> type:</xsl:text>
+<xsl:choose>
+<xsl:when test="@type='bri'">
+ <xsl:text>1</xsl:text>
+</xsl:when>
+<xsl:when test="@type='pri'">
+ <xsl:text>2</xsl:text>
+</xsl:when>
+<xsl:when test="@type='bri-mc'">
+ <xsl:text>3</xsl:text>
+</xsl:when>
+<xsl:when test="@type='pri-mc'">
+ <xsl:text>4</xsl:text>
+</xsl:when>
+<xsl:otherwise>
+ <xsl:text>1</xsl:text>
+</xsl:otherwise>
+</xsl:choose>
+
+<xsl:text> layermask:</xsl:text>
+<xsl:choose>
+<xsl:when test="@mode='nt'">
+ <xsl:text>3</xsl:text>
+</xsl:when>
+<xsl:otherwise>
+ <xsl:text>15</xsl:text>
+</xsl:otherwise>
+</xsl:choose>
+
+<xsl:text> protocol:</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@mode" />
+ <xsl:with-param name="match-true">te</xsl:with-param>
+ <xsl:with-param name="match-false">nt</xsl:with-param>
+ <xsl:with-param name="val-true">34</xsl:with-param>
+ <xsl:with-param name="val-false">18</xsl:with-param>
+ <xsl:with-param name="val-default">34</xsl:with-param>
+</xsl:call-template>
+<xsl:if test="@mode!='nt'">
+ <xsl:text>+</xsl:text>
+ <xsl:call-template name="if-match">
+  <xsl:with-param name="val" select="@link" />
+  <xsl:with-param name="match-true">ptp</xsl:with-param>
+  <xsl:with-param name="match-false">ptmp</xsl:with-param>
+  <xsl:with-param name="val-true">0</xsl:with-param>
+  <xsl:with-param name="val-false">(-32)</xsl:with-param>
+  <xsl:with-param name="val-default">(-32)</xsl:with-param>
+ </xsl:call-template>
+</xsl:if>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> codec:</xsl:with-param>
+ <xsl:with-param name="val" select="@codec" />
+ <xsl:with-param name="val-default">0</xsl:with-param>
+</xsl:call-template>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> ip:</xsl:with-param>
+ <xsl:with-param name="val" select="@ip" />
+ <xsl:with-param name="val-default">0,0,0,0</xsl:with-param>
+</xsl:call-template>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> port:</xsl:with-param>
+ <xsl:with-param name="val" select="@port" />
+ <xsl:with-param name="val-default">0</xsl:with-param>
+</xsl:call-template>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> localport:</xsl:with-param>
+ <xsl:with-param name="val" select="@localport" />
+ <xsl:with-param name="val-default">0</xsl:with-param>
+</xsl:call-template>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> ondemand:</xsl:with-param>
+ <xsl:with-param name="val" select="@ondemand" />
+ <xsl:with-param name="val-default">0</xsl:with-param>
+</xsl:call-template>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> id:</xsl:with-param>
+ <xsl:with-param name="val" select="@id" />
+ <xsl:with-param name="val-default">0</xsl:with-param>
+</xsl:call-template>
+
+<xsl:text>
+</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>

Added: misdn-kernel/trunk/config/mISDN.conf.mISDN_debugtool.xsl
===================================================================
--- misdn-kernel/trunk/config/mISDN.conf.mISDN_debugtool.xsl	                        (rev 0)
+++ misdn-kernel/trunk/config/mISDN.conf.mISDN_debugtool.xsl	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
+
+<!--
+	Module: mISDN_debugtool
+	Options: port=<number>
+-->
+<xsl:template name="MISDNdebugtoolmodule">
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> PORT=</xsl:with-param>
+ <xsl:with-param name="val" select="@port" />
+</xsl:call-template>
+
+<xsl:text>
+</xsl:text>
+
+</xsl:template>
+
+</xsl:stylesheet>

Added: misdn-kernel/trunk/config/mISDN.conf.mISDN_dsp.xsl
===================================================================
--- misdn-kernel/trunk/config/mISDN.conf.mISDN_dsp.xsl	                        (rev 0)
+++ misdn-kernel/trunk/config/mISDN.conf.mISDN_dsp.xsl	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
+
+<!--
+	Module: mISDN_dsp
+	Options: debug=<number>, options=<number>, poll=<number>, dtmfthreshold=<number>
+-->
+<xsl:template name="MISDNDSPmodule">
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> debug=</xsl:with-param>
+ <xsl:with-param name="val" select="@debug" />
+ <xsl:with-param name="val-default">0</xsl:with-param>
+</xsl:call-template>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> options=</xsl:with-param>
+ <xsl:with-param name="val" select="@options" />
+ <xsl:with-param name="val-default">0</xsl:with-param>
+</xsl:call-template>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> poll=</xsl:with-param>
+ <xsl:with-param name="val" select="@poll" />
+</xsl:call-template>
+
+<xsl:call-template name="if-set">
+ <xsl:with-param name="prefix"> dtmfthreshold=</xsl:with-param>
+ <xsl:with-param name="val" select="@dtmfthreshold" />
+</xsl:call-template>
+
+<xsl:text>
+</xsl:text>
+
+</xsl:template>
+
+</xsl:stylesheet>

Added: misdn-kernel/trunk/config/mISDN.conf.singlepci.xsl
===================================================================
--- misdn-kernel/trunk/config/mISDN.conf.singlepci.xsl	                        (rev 0)
+++ misdn-kernel/trunk/config/mISDN.conf.singlepci.xsl	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
+
+<!--
+	Card Type: hfcmulti, avmfritz, w6692pci
+	Ports: 1
+	Port Attributes: mode=(te|nt), link=(ptp|ptmp), capi=(yes|no)
+-->
+<xsl:template name="SINGLEPCIcard">
+<xsl:text>
+</xsl:text>
+</xsl:template>
+
+<xsl:template name="SINGLEPCIport">
+<xsl:text> layermask:</xsl:text>
+<xsl:choose>
+<xsl:when test="@mode='nt'">
+ <xsl:text>3</xsl:text>
+</xsl:when>
+<xsl:when test="@capi='yes'">
+ <xsl:text>0</xsl:text>
+</xsl:when>
+<xsl:otherwise>
+ <xsl:text>15</xsl:text>
+</xsl:otherwise>
+</xsl:choose>
+
+<xsl:text> protocol:</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@mode" />
+ <xsl:with-param name="match-true">te</xsl:with-param>
+ <xsl:with-param name="match-false">nt</xsl:with-param>
+ <xsl:with-param name="val-true">34</xsl:with-param>
+ <xsl:with-param name="val-false">18</xsl:with-param>
+ <xsl:with-param name="val-default">34</xsl:with-param>
+</xsl:call-template>
+<xsl:if test="@mode!='nt'">
+ <xsl:text>+</xsl:text>
+ <xsl:call-template name="if-match">
+  <xsl:with-param name="val" select="@link" />
+  <xsl:with-param name="match-true">ptp</xsl:with-param>
+  <xsl:with-param name="match-false">ptmp</xsl:with-param>
+  <xsl:with-param name="val-true">0</xsl:with-param>
+  <xsl:with-param name="val-false">(-32)</xsl:with-param>
+  <xsl:with-param name="val-default">(-32)</xsl:with-param>
+ </xsl:call-template>
+</xsl:if>
+
+<xsl:text> capi:</xsl:text>
+<xsl:call-template name="if-match">
+ <xsl:with-param name="val" select="@capi" />
+ <xsl:with-param name="val-true">yes</xsl:with-param>
+ <xsl:with-param name="val-false">no</xsl:with-param>
+ <xsl:with-param name="val-default">no</xsl:with-param>
+</xsl:call-template>
+
+<xsl:text>
+</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>

Added: misdn-kernel/trunk/config/mISDN.conf.xsl
===================================================================
--- misdn-kernel/trunk/config/mISDN.conf.xsl	                        (rev 0)
+++ misdn-kernel/trunk/config/mISDN.conf.xsl	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
+
+<xsl:include href='mISDN.conf.inc.xsl' />
+<xsl:include href='mISDN.conf.mISDN_dsp.xsl' />
+<xsl:include href='mISDN.conf.mISDN_debugtool.xsl' />
+<xsl:include href='mISDN.conf.hfcmulti.xsl' />
+<xsl:include href='mISDN.conf.bnx.xsl' />
+<xsl:include href='mISDN.conf.singlepci.xsl' />
+<xsl:include href='mISDN.conf.l1oip.xsl' />
+
+<!--
+	Main mISDNconf Template
+-->
+<xsl:template match="mISDNconf">
+
+<!-- module -->
+
+<xsl:for-each select="module">
+
+<xsl:choose>
+
+ <xsl:when test=".='hfcmulti'">
+  <xsl:value-of select="concat('MODULE:',.)" />
+  <xsl:call-template name="HFCMULTImodule" />
+ </xsl:when>
+
+ <xsl:when test=".='l1oip'">
+  <xsl:value-of select="concat('MODULE:',.)" />
+  <xsl:call-template name="L1OIPmodule" />
+ </xsl:when>
+
+ <xsl:when test=".='mISDN_dsp'">
+  <xsl:value-of select="concat('MODULE:',.)" />
+  <xsl:call-template name="MISDNDSPmodule" />
+ </xsl:when>
+
+ <xsl:when test=".='mISDN_debugtool'">
+  <xsl:value-of select="concat('MODULE:',.)" />
+  <xsl:call-template name="MISDNdebugtoolmodule" />
+ </xsl:when>
+
+</xsl:choose>
+
+</xsl:for-each>
+
+<!-- devnode -->
+
+<xsl:for-each select="devnode">
+
+<xsl:choose>
+
+ <xsl:when test=".='mISDN'">
+  <xsl:value-of select="concat('DEVNODE:',.)" />
+  <xsl:call-template name="if-set">
+   <xsl:with-param name="prefix"> user:</xsl:with-param>
+   <xsl:with-param name="val" select="@user" />
+   <xsl:with-param name="val-default">root</xsl:with-param>
+  </xsl:call-template>
+  <xsl:call-template name="if-set">
+   <xsl:with-param name="prefix"> group:</xsl:with-param>
+   <xsl:with-param name="val" select="@group" />
+   <xsl:with-param name="val-default">root</xsl:with-param>
+  </xsl:call-template>
+  <xsl:call-template name="if-set">
+   <xsl:with-param name="prefix"> mode:</xsl:with-param>
+   <xsl:with-param name="val" select="@mode" />
+   <xsl:with-param name="val-default">644</xsl:with-param>
+  </xsl:call-template>
+ </xsl:when>
+</xsl:choose>
+<xsl:text>
+</xsl:text>
+
+</xsl:for-each>
+
+<!-- card, port -->
+
+<xsl:for-each select="card">
+
+<xsl:choose>
+
+ <xsl:when test="@type='BN2S0'">
+  <xsl:value-of select="concat('CARD:', at type)" />
+  <xsl:call-template name="BN2S0card" />
+  <xsl:for-each select="port">
+   <xsl:sort data-type="number" />
+   <xsl:text>PORT:</xsl:text>
+   <xsl:value-of select="." />
+   <xsl:call-template name="BN2S0port" />
+  </xsl:for-each>
+ </xsl:when>
+
+ <xsl:when test="@type='BN4S0'">
+  <xsl:value-of select="concat('CARD:', at type)" />
+  <xsl:call-template name="BN4S0card" />
+  <xsl:for-each select="port">
+   <xsl:sort data-type="number" />
+   <xsl:text>PORT:</xsl:text>
+   <xsl:value-of select="." />
+   <xsl:call-template name="BN4S0port" />
+  </xsl:for-each>
+ </xsl:when>
+
+ <xsl:when test="@type='BN8S0'">
+  <xsl:value-of select="concat('CARD:', at type)" />
+  <xsl:call-template name="BN8S0card" />
+  <xsl:for-each select="port">
+   <xsl:sort data-type="number" />
+   <xsl:text>PORT:</xsl:text>
+   <xsl:value-of select="." />
+   <xsl:call-template name="BN8S0port" />
+  </xsl:for-each>
+ </xsl:when>
+
+ <xsl:when test="@type='BN2E1'">
+  <xsl:value-of select="concat('CARD:', at type)" />
+  <xsl:call-template name="BN2E1card" />
+  <xsl:for-each select="port">
+   <xsl:sort data-type="number" />
+   <xsl:text>PORT:</xsl:text>
+   <xsl:value-of select="." />
+   <xsl:call-template name="BN2E1port" />
+  </xsl:for-each>
+ </xsl:when>
+
+ <xsl:when test="@type='hfcpci' or @type='avmfritz' or @type='w6692pci'">
+  <xsl:value-of select="concat('CARD:', at type)" />
+  <xsl:call-template name="SINGLEPCIcard" />
+  <xsl:for-each select="port">
+   <xsl:sort data-type="number" />
+   <xsl:text>PORT:</xsl:text>
+   <xsl:value-of select="." />
+   <xsl:call-template name="SINGLEPCIport" />
+  </xsl:for-each>
+ </xsl:when>
+
+ <xsl:when test="@type='l1oip'">
+  <xsl:value-of select="concat('CARD:', at type)" />
+  <xsl:call-template name="L1OIPcard" />
+  <xsl:for-each select="port">
+   <xsl:sort data-type="number" />
+   <xsl:text>PORT:</xsl:text>
+   <xsl:value-of select="." />
+   <xsl:call-template name="L1OIPport" />
+  </xsl:for-each>
+ </xsl:when>
+
+</xsl:choose>
+
+</xsl:for-each>
+</xsl:template>
+</xsl:stylesheet>

Added: misdn-kernel/trunk/debian/README.Debian
===================================================================
--- misdn-kernel/trunk/debian/README.Debian	                        (rev 0)
+++ misdn-kernel/trunk/debian/README.Debian	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,17 @@
+Building kernel modules
+-----------------------
+
+First, install msidn-kernel-source package if you have not yet done so.
+
+You can build and install the modules package (as root) with the
+following command:
+# module-assistant a-i misdn-kernel-source
+
+It may be handy (for e.g., testing purposes) to build the module packages
+for all of the kernel-header packages installed on your system. Something
+in the lines of:
+
+  m-a -u . -t -i -f -k "`echo usr/src/kernel-headers-*`" build misdn-kernel-source
+
+You can also use the environment variable TARBALL to build the modules
+with a custom misdn-kernel-source.tar.bz2 tarball with some local modifications.

Added: misdn-kernel/trunk/debian/changelog
===================================================================
--- misdn-kernel/trunk/debian/changelog	                        (rev 0)
+++ misdn-kernel/trunk/debian/changelog	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,99 @@
+misdn-kernel (1.1.5-1) stable; urgency=low
+
+  * Updated to mISDN 1.1.5.
+
+ -- Dermot Bradley <dermot.bradley at sla-networks.com>  Wed,  5 Jul 2007 16:08:26 +0100
+
+misdn-kernel (0.0.0+cvs20061029-4) unstable; urgency=low
+
+  * Updated to new kernel ABI
+
+ -- Simon Richter <sjr at debian.org>  Mon, 27 Nov 2006 16:31:25 +0100
+
+misdn-kernel (0.0.0+cvs20061029-3) unstable; urgency=low
+
+  * Fix control file generation and parsing to avoid building modules for
+    flavours that have "modules: false" set, and to avoid the substring match
+    "mips" in "mipsel" (Closes: #385813)
+
+ -- Simon Richter <sjr at debian.org>  Wed,  1 Nov 2006 21:54:52 +0100
+
+misdn-kernel (0.0.0+cvs20061029-2) unstable; urgency=low
+
+  * Adapted toplevel debian/rules to also use $KPKG_DEST_DIR. Interestingly
+    enough, it worked during my testing here.
+
+ -- Simon Richter <sjr at debian.org>  Wed,  1 Nov 2006 20:20:04 +0100
+
+misdn-kernel (0.0.0+cvs20061029-1) unstable; urgency=low
+
+  * New upstream release
+  * Using $KPKG_DEST_DIR instead of $MODDIR as the output directory
+    (Closes: #395245)
+
+ -- Simon Richter <sjr at debian.org>  Wed,  1 Nov 2006 13:33:54 +0100
+
+misdn-kernel (0.0.0+cvs20060902-1) unstable; urgency=low
+
+  * New upstream snapshot
+  * Updated to kernel 2.6.17-2 (Closes: #352121, #343700)
+  * Fix building with module-assistant, should also work with make-kpkg
+    (Closes: #296167, #305197)
+  * Modules are built for standard kernels (Closes: #304511)
+  * Reactivated HFC-S USB, as it appears to be fixed (Closes: #363241)
+  * Activated new NetJet driver
+
+ -- Simon Richter <sjr at debian.org>  Sat,  2 Sep 2006 20:34:39 +0200
+
+misdn-kernel (0.0.0+cvs20060214-1) unstable; urgency=low
+
+  * Updated to 2.6.16
+  * New upstream "release"
+
+ -- Simon Richter <sjr at debian.org>  Tue, 21 Mar 2006 16:33:47 +0100
+
+misdn-kernel (0.0.0+cvs20051212-1) unstable; urgency=low
+
+  * Reworked the build scripting, a lot.
+  * New version (now using "mqueue" branch)
+  * Switched to new kernel packages, dropping sarge support (sorry).
+  * Disabled HFC-USB support for this version, APIs in flux
+
+ -- Simon Richter <sjr at debian.org>  Sun, 12 Feb 2006 01:12:50 +0100
+
+misdn-kernel (0.0.0+cvs20050408-2) unstable; urgency=low
+
+  * Bumped build-dep to point to a newer kernel
+  * Cleaned up debian/rules
+
+ -- Simon Richter <sjr at debian.org>  Sat, 30 Apr 2005 00:43:23 +0200
+
+misdn-kernel (0.0.0+cvs20050408-1) unstable; urgency=low
+
+  * New upstream version
+  * Allow building against 2.6.8 kernel in sarge
+
+ -- Simon Richter <sjr at debian.org>  Fri,  8 Apr 2005 16:30:27 +0200
+
+misdn-kernel (0.0.0+cvs20050402-1) unstable; urgency=low
+
+  * Moved to 2.6.10 (Closes: #302448)
+  * New upstream version
+
+ -- Simon Richter <sjr at debian.org>  Sat,  2 Apr 2005 01:13:07 +0200
+
+misdn-kernel (0.0.0+cvs20041116-1) unstable; urgency=low
+
+  * New upstream version
+  * Moved to 2.6.9
+  * Corrected build dependencies (Closes: #281273)
+  * Fixed dependency of misdn-kernel-source (Closes: #281716)
+
+ -- Simon Richter <sjr at debian.org>  Tue, 16 Nov 2004 15:30:28 +0100
+
+misdn-kernel (0.0.0+cvs20041018-1) unstable; urgency=low
+
+  * Initial Release (Closes: #263085).
+
+ -- Simon Richter <sjr at debian.org>  Mon, 18 Aug 2004 11:11:56 +0200
+

Added: misdn-kernel/trunk/debian/compat
===================================================================
--- misdn-kernel/trunk/debian/compat	                        (rev 0)
+++ misdn-kernel/trunk/debian/compat	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1 @@
+4

Added: misdn-kernel/trunk/debian/control
===================================================================
--- misdn-kernel/trunk/debian/control	                        (rev 0)
+++ misdn-kernel/trunk/debian/control	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,41 @@
+Source: misdn-kernel
+Section: comm
+Priority: extra
+Maintainer: Dermot Bradley <dermot.bradley at sla-networks.com>
+Build-Depends: debhelper (>= 4.0.0), dpatch, bzip2
+Standards-Version: 3.7.2
+
+Package: misdn-kernel-source
+Section: devel
+Architecture: all
+Depends: debhelper, module-assistant, bzip2
+Recommends: misdn
+Suggests: kernel-package
+Description: Source code for the mISDN modules
+ The modular ISDN drivers are the bleeding edge implementation of ISDN support
+ in the Linux kernel. The most prominent new feature is support for ISDN cards
+ in NT mode, so you can connect an ISDN telephone to your computer.
+ .
+ You need this package if you want to compile the mISDN modules to accompany
+ your custom kernel.
+
+Package: misdn
+Section: comm
+Architecture: all
+Depends: ${shlibs:Depends}, xsltproc
+Description: Control programs for the mISDN modules
+ The modular ISDN drivers are the bleeding edge implementation of ISDN support
+ in the Linux kernel. The most prominent new feature is support for ISDN cards
+ in NT mode, so you can connect an ISDN telephone to your computer.
+ .
+ You need this package to control the mISDN kernel drivers.
+
+Package: misdn-headers
+Architecture: all
+Description: Header files for the mISDN drivers
+ The modular ISDN drivers are the bleeding edge implementation of ISDN support
+ in the Linux kernel. The most prominent new feature is support for ISDN cards
+ in NT mode, so you can connect an ISDN telephone to your computer.
+ .
+ You need this package if you intend to compile userspace applications that
+ access mISDN specific interfaces.

Added: misdn-kernel/trunk/debian/control.modules.in
===================================================================
--- misdn-kernel/trunk/debian/control.modules.in	                        (rev 0)
+++ misdn-kernel/trunk/debian/control.modules.in	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,17 @@
+Source: misdn-kernel
+Section: comm
+Priority: extra
+Maintainer: Dermot Bradley <dermot.bradley at sla-networks.com>
+Build-Depends: debhelper (>> 3.0.0), bzip2
+Standards-Version: 3.6.1.1
+
+Package: misdn-modules-_KVERS_
+Architecture: any
+Depends: linux-image-_KVERS_ | kernel-image-_KVERS_
+Provides: misdn-modules
+Description: misdn modules for Linux (kernel _KVERS_).
+ This package contains the set of loadable kernel modules for the
+ mISDN.
+ This package contains the compiled kernel modules for _KVERS_
+ .
+ In order to compile these modules use the module-assistant utility.

Added: misdn-kernel/trunk/debian/copyright
===================================================================
--- misdn-kernel/trunk/debian/copyright	                        (rev 0)
+++ misdn-kernel/trunk/debian/copyright	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,38 @@
+This package was debianized by Dermot Bradley <dermot.bradley at sla-networks.com>
+on Mon, 16 Jul 2007 10:38:51 +0100.
+
+It was downloaded from http://www.misdn.org
+
+Upstream Authors: Karsten Keil <kkeil at suse.de>
+                  Werner Cornelius <werner at isdn-development.de>
+                  Andreas Eversberg <jolly at jolly.de>
+                  Fritz Elfert <fritz at isdn4linux.de>
+                  Christian Richter <crich at beronet.de>
+
+Copyright:
+
+Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Karsten Keil
+Copyright (C) 1999                               Werner Cornelius
+Copyright (C) 2002, 2003                         Andreas Eversberg
+Copyright (C) 2001                               Steve Underwood
+Copyright (C) 2005, 2006                         Christian Richter
+Copyright (C) 2002                               Digium, Inc.
+Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Fritz Elfert
+Copyright (C) 2005, 2006                         Cologne Chip AG
+
+   This package 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; version 2 dated June, 1991.
+
+   This package 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.
+

Added: misdn-kernel/trunk/debian/dirs
===================================================================
--- misdn-kernel/trunk/debian/dirs	                        (rev 0)
+++ misdn-kernel/trunk/debian/dirs	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1 @@
+usr/src

Added: misdn-kernel/trunk/debian/docs
===================================================================
--- misdn-kernel/trunk/debian/docs	                        (rev 0)
+++ misdn-kernel/trunk/debian/docs	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1 @@
+README.misdn-init

Added: misdn-kernel/trunk/debian/misdn-headers.install
===================================================================
--- misdn-kernel/trunk/debian/misdn-headers.install	                        (rev 0)
+++ misdn-kernel/trunk/debian/misdn-headers.install	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,2 @@
+usr/include/linux/isdn_compat.h		usr/include/linux
+usr/include/linux/mISDNif.h		usr/include/linux

Added: misdn-kernel/trunk/debian/misdn-modules.modules
===================================================================

Added: misdn-kernel/trunk/debian/misdn.dirs
===================================================================
--- misdn-kernel/trunk/debian/misdn.dirs	                        (rev 0)
+++ misdn-kernel/trunk/debian/misdn.dirs	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,3 @@
+etc/init.d/
+usr/lib/mISDN/
+usr/sbin/

Added: misdn-kernel/trunk/debian/misdn.init
===================================================================
--- misdn-kernel/trunk/debian/misdn.init	                        (rev 0)
+++ misdn-kernel/trunk/debian/misdn.init	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,63 @@
+#! /bin/sh
+
+### BEGIN INIT INFO
+# Provides:          misdn
+# Required-Start:    
+# Required-Stop:     
+# Should-Start:      $local_fs hotplug module-init-tools
+# Should-Stop:       $local_fs
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Configures misdn kernel modules.
+# Description:       Configures misdn kernel modules. Waits until
+#                    they are fully loaded (if modules are available).
+### END INIT INFO
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/mISDN
+MISDNCONF_FILE=/etc/mISDN.conf
+NAME=misdn
+DESC="mISDN telephony kernel driver"
+
+# Include am defaults if available
+if [ -f /etc/default/misdn ] ; then
+	. /etc/default/misdn
+fi
+
+if [ ! -x $DAEMON ] ; then
+	echo >&2 $NAME ":" $DAEMON "fails test for exists and executable" ;
+	exit 0
+fi
+
+if [ ! -f $MISDNCONF_FILE ] ; then
+	echo >&2 $NAME ":" $MISDNCONF_FILE "fails test for exists and readable";
+	exit 0
+fi
+
+
+set -e
+
+case "$1" in
+	start|reload)
+		echo -n "$DESC: "
+		$DAEMON start
+		;;
+	stop|unload)
+		$DAEMON stop
+		;;
+	status)
+		$DAEMON scan
+		;;
+	force-reload|restart)
+		$0 stop
+		sleep 5
+		$0 start
+		;;
+  *)
+		N=/etc/init.d/$NAME
+		echo "Usage: $N {start|stop|restart|force-reload|status|unload|status}" >&2
+	exit 1
+	;;
+esac
+
+exit 0

Added: misdn-kernel/trunk/debian/misdn.install
===================================================================
--- misdn-kernel/trunk/debian/misdn.install	                        (rev 0)
+++ misdn-kernel/trunk/debian/misdn.install	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1 @@
+usr/sbin/mISDN		usr/sbin

Added: misdn-kernel/trunk/debian/misdn.postinst
===================================================================
--- misdn-kernel/trunk/debian/misdn.postinst	                        (rev 0)
+++ misdn-kernel/trunk/debian/misdn.postinst	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,49 @@
+#! /bin/sh
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+
+DYNFS=`ps ax | grep -v grep`
+
+case "$1" in
+    configure)
+
+	# Add the mISDN and hfcmulti module to the blacklist
+	# to ensure that hotplug/udev will NOT autoload them
+	BLACKLIST=/etc/modprobe.d/blacklist
+        if [ "`grep "mISDN_core" $BLACKLIST`" != "blacklist mISDN_core" ]; then
+		echo "" >> $BLACKLIST
+        	echo "# We don't want kernel to autoload mISDN modules" >> $BLACKLIST
+		echo "blacklist hfcmulti" >> $BLACKLIST
+		echo "blacklist mISDN_core" >> $BLACKLIST
+		echo "" >> $BLACKLIST
+	fi
+
+    ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+
+    ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
+

Added: misdn-kernel/trunk/debian/rules
===================================================================
--- misdn-kernel/trunk/debian/rules	                        (rev 0)
+++ misdn-kernel/trunk/debian/rules	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,146 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatibility version to use.
+
+ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -g
+endif
+
+## MODULE-ASSISTANT STUFF
+# prefix of the target package name
+PREFIX:=misdn
+SKPG:=$(PREFIX)-kernel-source
+PACKAGE:=$(PREFIX)-modules
+# modifieable for experiments or debugging m-a
+MA_DIR ?= /usr/share/modass
+# load generic variable handling
+-include $(MA_DIR)/include/generic.make
+# load default rules
+-include $(MA_DIR)/include/common-rules.make
+
+kdist_clean: clean-unpatched
+
+kdist_config: prep-deb-files
+
+binary-modules: prep-deb-files
+	dh_testdir
+	dh_testroot
+	dh_clean -k
+	make KERNEL_SOURCES=$(KSRC) MODVERSIONS=detect KERNEL=linux-$(KVERS)
+	make modules-install KERNELRELEASE=$(KVERS) INSTALL_PREFIX=$(CURDIR)/debian/$(PKGNAME)
+ifeq (2.6,$(shell echo $(KVERS) | cut -d. -f1-2))
+	# The 2.6 modules are way too big. This is only in kernel 2.6
+	find debian/$(PKGNAME)/lib/modules -name '*.ko' |xargs strip -g
+endif
+	dh_installmodules
+	dh_installdebconf
+	dh_installchangelogs
+	dh_compress
+	dh_fixperms
+	dh_installdeb
+	dh_gencontrol -- -v$(VERSION)
+	dh_md5sums
+	dh_builddeb --destdir=$(DEB_DESTDIR)
+
+## END OF M-A SECTION
+
+build: build-stamp
+build-stamp:
+	dh_testdir
+	
+	touch $@
+
+clean: clean-unpatched unpatch
+clean-unpatched:
+	dh_testdir
+	dh_testroot
+	rm -f *-stamp
+	
+	# Add here commands to clean up after the build process.
+	-$(MAKE) clean
+	
+	#rm -f debian/manpage.links  debian/manpage.refs debian/*.8
+	
+	dh_clean
+
+install: install-arch install-indep
+
+install-arch: build-stamp
+	dh_testdir
+	dh_testroot
+	dh_clean -k -a
+	dh_installdirs -a
+	
+	# Add here commands to install the package into debian/tmp
+
+
+TARPARDIR=$(CURDIR)/debian/misdn-kernel-source
+TARDIR=$(TARPARDIR)/modules/$(PREFIX)
+install-indep: build-stamp
+	dh_testdir
+	dh_testroot
+	dh_clean -k -i
+	dh_installdirs -i
+	
+	mkdir -p $(CURDIR)/debian/misdn-headers/usr/include/linux/
+	cp include/linux/*.h \
+		$(CURDIR)/debian/misdn-headers/usr/include/linux/
+
+
+	# driver source code
+	mkdir -p $(TARDIR)/debian
+	cp Makefile Makefile.module Makefile.standalone Rules.make.ext add.config VERSION $(TARDIR)/
+	for dir in config drivers include; do \
+	  if [ -d $$dir ]; then cp -r $$dir $(TARDIR); fi; \
+	done
+	
+	# Packaging infrastructure
+	cp -r debian/*-modules.* debian/rules debian/changelog debian/copyright\
+	  debian/control debian/compat \
+	  debian/control.modules.in \
+	  $(TARDIR)/debian/
+	
+	tar cjf debian/$(PREFIX)-kernel-source/usr/src/$(PREFIX).tar.bz2 \
+	  -C $(TARPARDIR) modules
+	
+	rm -rf $(TARPARDIR)/modules
+
+	mkdir -p $(CURDIR)/debian/misdn/usr/sbin
+	cp config/mISDN \
+		$(CURDIR)/debian/misdn/usr/sbin/
+	mkdir -p $(CURDIR)/debian/misdn/usr/lib/mISDN
+	cp config/*.xsl \
+		$(CURDIR)/debian/misdn/usr/lib/mISDN/
+	
+# Build architecture-independent files here.
+binary-indep: build install-indep
+	dh_testdir
+	dh_testroot
+	
+	dh_installdocs -i
+	dh_installinit --update-rcd-params="defaults 15 30"
+	dh_installchangelogs -i CHANGES
+	dh_installexamples -i
+	dh_link -i
+	dh_compress -i
+	dh_fixperms -i
+	dh_installdeb -i
+	dh_gencontrol -i
+	dh_md5sums -i
+	dh_builddeb -i
+
+# Build architecture-dependent files here.
+binary-arch: build install-arch
+	dh_testdir
+	dh_testroot
+	
+	#install -m644 debian/$(PREFIX).modprobe.d debian/$(PREFIX)/etc/modprobe.d/$(PREFIX)
+	
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure patch unpatch


Property changes on: misdn-kernel/trunk/debian/rules
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-kernel/trunk/debian/rules.modules
===================================================================
--- misdn-kernel/trunk/debian/rules.modules	                        (rev 0)
+++ misdn-kernel/trunk/debian/rules.modules	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,36 @@
+#!/usr/bin/make -f
+
+PACKAGE := misdn-modules
+MA_DIR ?= /usr/share/modass
+-include $(MA_DIR)/include/generic.make
+-include $(MA_DIR)/include/common-rules.make
+
+.PHONY: kdist_config
+kdist_config: prep-deb-files
+
+.PHONY: binary-modules
+binary-modules: kdist_config
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+
+       # Build the module
+       $(MAKE) -C $(CURDIR) KERNEL_VERSION=$(KVERS) KERNELDIR=$(KSRC)
+
+       dh_installdocs
+       dh_installchangelogs
+       dh_compress
+       dh_fixperms
+       dh_installmodules
+       dh_installdeb
+       dh_gencontrol -- -v$(VERSION)
+       dh_md5sums
+       dh_builddeb --destdir=$(DEB_DESTDIR)
+
+.PHONY: kdist_clean
+kdist_clean:
+       dh_testdir
+       dh_testroot
+       dh_clean
+       rm -f *.symvers
+       $(MAKE) -C $(CURDIR) clean

Added: misdn-kernel/trunk/drivers/isdn/Config.in.v2.4
===================================================================
--- misdn-kernel/trunk/drivers/isdn/Config.in.v2.4	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/Config.in.v2.4	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,177 @@
+#
+# ISDN device configuration
+#
+
+# only included if CONFIG_ISDN != n
+
+define_bool CONFIG_ISDN_BOOL y
+if [ "$CONFIG_INET" != "n" ]; then
+   bool '  Support synchronous PPP' CONFIG_ISDN_PPP
+   if [ "$CONFIG_ISDN_PPP" != "n" ]; then
+      bool         '    Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
+      bool         '    Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
+      dep_tristate '    Support BSD compression' CONFIG_ISDN_PPP_BSDCOMP $CONFIG_ISDN
+   fi
+fi
+bool '  Support audio via ISDN' CONFIG_ISDN_AUDIO
+if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
+   bool '    Support AT-Fax Class 1 and 2 commands' CONFIG_ISDN_TTY_FAX
+fi
+if [ "$CONFIG_X25" != "n" ]; then
+   bool '  X.25 PLP on top of ISDN' CONFIG_ISDN_X25
+fi
+
+mainmenu_option next_comment
+comment 'ISDN feature submodules'
+   dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
+   dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN
+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
+   define_bool CONFIG_ISDN_HISAX y
+   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 '    Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD
+   fi
+   bool '  HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+   bool '  HiSax Support for US NI1' CONFIG_HISAX_NI1
+   int  '  Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8
+   comment '  HiSax supported cards'
+   if [ "$CONFIG_ISA" != "n" ]; then
+      bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0
+      bool '  Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+      bool '  AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+      bool '  ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+      bool '  ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
+      bool '  TELEINT cards' CONFIG_HISAX_TELEINT
+      bool '  HFC-S based cards' CONFIG_HISAX_HFCS
+      bool '  USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+      bool '  MIC card' CONFIG_HISAX_MIC
+      bool '  Siemens I-Surf card' CONFIG_HISAX_ISURF
+      bool '  HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+   fi
+   bool '  Teles PCI' CONFIG_HISAX_TELESPCI 
+   bool '  Teles S0Box' CONFIG_HISAX_S0BOX 
+   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 '  Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
+   bool '  Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
+   bool '  NETjet card' CONFIG_HISAX_NETJET
+   bool '  NETspider U card' CONFIG_HISAX_NETJET_U
+   bool '  Niccy PnP/PCI card' CONFIG_HISAX_NICCY
+   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
+   bool '  HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
+   if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+#      bool '  TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+      bool '  Formula-n enter:now PCI card' CONFIG_HISAX_ENTERNOW_PCI
+      if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+	 bool '  Am7930' CONFIG_HISAX_AMD7930
+      fi
+   fi
+   bool '  HiSax debugging' CONFIG_HISAX_DEBUG
+
+   dep_tristate 'Sedlbauer PCMCIA cards'                              CONFIG_HISAX_SEDLBAUER_CS  $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
+   dep_tristate 'ELSA PCMCIA MicroLink cards'                         CONFIG_HISAX_ELSA_CS       $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
+   dep_tristate 'AVM A1 PCMCIA cards'                                 CONFIG_HISAX_AVM_A1_CS     $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA $CONFIG_HISAX_AVM_A1_PCMCIA
+   dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)'                CONFIG_HISAX_ST5481        $CONFIG_ISDN_DRV_HISAX    $CONFIG_EXPERIMENTAL
+   dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP  $CONFIG_ISDN_DRV_HISAX                $CONFIG_EXPERIMENTAL
+   dep_tristate 'Auerswald devices ISDN support'                      CONFIG_USB_AUERISDN        $CONFIG_ISDN_DRV_HISAX
+
+fi
+endmenu
+
+### Active ISDN cards
+
+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
+dep_tristate       'Spellcaster support' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+dep_tristate       'IBM Active 2000 support' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
+
+bool               'Eicon active card support' CONFIG_ISDN_DRV_EICON
+if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
+   if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "y" ]; then
+      dep_tristate '  Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN $CONFIG_PCI
+   fi
+   if [ "$CONFIG_ISDN_DRV_EICON_DIVAS" != "y" ]; then
+      dep_tristate '  Legacy Eicon driver' CONFIG_ISDN_DRV_EICON_OLD $CONFIG_ISDN
+      if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "n" ]; then
+         dep_bool  '    Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI $CONFIG_PCI
+         bool      '    Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+      fi
+   fi
+fi
+
+if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+   dep_tristate    'Auvertech TurboPAM support' CONFIG_ISDN_DRV_TPAM $CONFIG_ISDN $CONFIG_PCI
+fi
+
+# CAPI subsystem
+
+tristate           'CAPI2.0 support' CONFIG_ISDN_CAPI
+if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
+   bool            '  Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+   dep_bool        '  CAPI2.0 Middleware support (EXPERIMENTAL)' CONFIG_ISDN_CAPI_MIDDLEWARE $CONFIG_EXPERIMENTAL
+   dep_tristate    '  CAPI2.0 /dev/capi support' CONFIG_ISDN_CAPI_CAPI20 $CONFIG_ISDN_CAPI
+   if [ "$CONFIG_ISDN_CAPI_MIDDLEWARE" = "y" ]; then
+      dep_mbool    '    CAPI2.0 filesystem support' CONFIG_ISDN_CAPI_CAPIFS_BOOL $CONFIG_ISDN_CAPI_CAPI20
+      if [ "$CONFIG_ISDN_CAPI_CAPIFS_BOOL" = "y" ]; then
+	 define_tristate CONFIG_ISDN_CAPI_CAPIFS $CONFIG_ISDN_CAPI_CAPI20
+      else
+	 define_tristate CONFIG_ISDN_CAPI_CAPIFS n
+      fi
+   fi
+   dep_tristate    '  CAPI2.0 capidrv interface support' CONFIG_ISDN_CAPI_CAPIDRV $CONFIG_ISDN_CAPI $CONFIG_ISDN
+fi
+
+# CAPI drivers
+
+if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
+   dep_tristate '  AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA $CONFIG_ISDN_CAPI
+   dep_tristate '  AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
+   dep_mbool    '    AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4 $CONFIG_ISDN_DRV_AVMB1_B1PCI
+   dep_tristate '  AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA $CONFIG_ISDN_CAPI
+   dep_tristate '  AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_ISDN_CAPI
+   dep_tristate '  AVM B1/M1/M2 PCMCIA cs module' CONFIG_ISDN_DRV_AVMB1_AVM_CS $CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_PCMCIA
+   dep_tristate '  AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
+   dep_tristate '  AVM C4/C2 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_ISDN_CAPI $CONFIG_PCI
+fi
+
+# HYSDN
+
+dep_tristate '  Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)' CONFIG_HYSDN m $CONFIG_PROC_FS
+dep_mbool    '    HYSDN CAPI 2.0 support' CONFIG_HYSDN_CAPI $CONFIG_HYSDN $CONFIG_ISDN_CAPI
+endmenu
+
+mainmenu_option next_comment
+comment 'modular ISDN driver'
+
+dep_tristate '  mISDN support' CONFIG_MISDN_DRV $CONFIG_ISDN_CAPI
+if [ "$CONFIG_MISDN_DRV" != "n" ]; then
+   comment '  mISDN supported cards'
+   bool '  AVM Fritz PCI and ISA PnP cards' CONFIG_MISDN_AVM_FRITZ
+   bool '  Cologne Chip Design HFC PCI cards' CONFIG_MISDN_HFCPCI
+   bool '  Cologne Chip Design HFC multiport cards' CONFIG_MISDN_HFCMULTI
+   bool '  Sedlbauer Speedfax + cards' CONFIG_MISDN_SPEEDFAX
+   bool '  Winbond W6692 cards' CONFIG_MISDN_W6692
+   comment '  mISDN supported features'
+   bool '  mISDN audio DSP module' CONFIG_MISDN_DSP
+   bool '  mISDN memory leak debug' CONFIG_MISDN_MEMDEBUG
+fi
+endmenu

Added: misdn-kernel/trunk/drivers/isdn/Makefile.v2.4
===================================================================
--- misdn-kernel/trunk/drivers/isdn/Makefile.v2.4	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/Makefile.v2.4	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,58 @@
+# Makefile for the kernel ISDN subsystem and device drivers.
+
+# The target object and module list name.
+
+O_TARGET	:= vmlinux-obj.o
+
+# Objects that export symbols.
+
+export-objs	:= isdn_common.o
+
+# Multipart objects.
+
+list-multi	:= isdn.o
+isdn-objs	:= isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
+
+# Optional parts of multipart objects.
+
+isdn-objs-$(CONFIG_ISDN_PPP)		+= isdn_ppp.o
+isdn-objs-$(CONFIG_ISDN_X25)		+= isdn_concap.o isdn_x25iface.o
+isdn-objs-$(CONFIG_ISDN_AUDIO)		+= isdn_audio.o
+isdn-objs-$(CONFIG_ISDN_TTY_FAX)	+= isdn_ttyfax.o
+isdn-objs-$(CONFIG_ISDN_WITH_ABC)	+= isdn_dwabc.o
+
+isdn-objs				+= $(isdn-objs-y)
+
+# Ordering constraints: isdn.o first, rest doesn't matter
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN)			+= isdn.o
+obj-$(CONFIG_ISDN_PPP_BSDCOMP)		+= isdn_bsdcomp.o
+
+# Object files in subdirectories
+
+mod-subdirs				:= avmb1 eicon hisax
+subdir-$(CONFIG_ISDN_DIVERSION)		+= divert
+subdir-$(CONFIG_ISDN_HISAX)		+= hisax
+subdir-$(CONFIG_ISDN_DRV_ICN)		+= icn
+subdir-$(CONFIG_ISDN_DRV_PCBIT)		+= pcbit
+subdir-$(CONFIG_ISDN_DRV_SC)		+= sc
+subdir-$(CONFIG_ISDN_CAPI)		+= avmb1
+subdir-$(CONFIG_ISDN_DRV_LOOP)		+= isdnloop
+subdir-$(CONFIG_ISDN_DRV_ACT2000)	+= act2000
+subdir-$(CONFIG_ISDN_DRV_EICON)		+= eicon
+subdir-$(CONFIG_HYSDN)			+= hysdn
+subdir-$(CONFIG_ISDN_DRV_TPAM)		+= tpam
+subdir-$(CONFIG_MISDN_DRV)		+= hardware/mISDN
+
+obj-y += $(addsuffix /vmlinux-obj.o, $(subdir-y))
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
+
+# Link rules for multi-part drivers.
+
+isdn.o: $(isdn-objs)
+	$(LD) -r -o $@ $(isdn-objs)

Added: misdn-kernel/trunk/drivers/isdn/hardware/Kconfig.v2.6
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/Kconfig.v2.6	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/Kconfig.v2.6	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,12 @@
+#
+# ISDN hardware drivers
+#
+comment "CAPI hardware drivers"
+	depends on NET && ISDN && ISDN_CAPI
+
+source "drivers/isdn/hardware/avm/Kconfig"
+
+source "drivers/isdn/hardware/eicon/Kconfig"
+
+source "drivers/isdn/hardware/mISDN/Kconfig"
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/Makefile.v2.6
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/Makefile.v2.6	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/Makefile.v2.6	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,7 @@
+# Makefile for the CAPI hardware drivers
+
+# Object files in subdirectories
+
+obj-$(CONFIG_CAPI_AVM)		+= avm/
+obj-$(CONFIG_CAPI_EICON)	+= eicon/
+obj-$(CONFIG_MISDN_DRV)		+= mISDN/

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Kconfig.v2.6
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Kconfig.v2.6	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Kconfig.v2.6	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,141 @@
+#
+# modularer ISDN driver
+#
+
+menu "Modular ISDN driver"
+	depends on NET && ISDN && ISDN_CAPI!=n
+
+config MISDN_DRV
+	tristate "Support modular ISDN driver"
+	help
+	  Enable support for the modular ISDN driver.
+          This driver is the successor of the famous HiSax driver.
+
+if MISDN_DRV!=n
+
+config MISDN_MEMDEBUG
+	bool "Enable memory leak debug for mISDN"
+	help
+	  This option is for watching the use of several resources in mISDN.
+	  It includes extra code to maintain list of allocated memory and
+	  sk_buffs. On module unload you can see not freed resources an
+	  their allocation orging and some object specific informations.
+	  If unsure, say 'N'.
+
+config MISDN_AVM_FRITZ
+	bool "Support for AVM Fritz!Cards"
+	depends on PCI || ISA
+	help
+	  Enable support for AVM Fritz!Card PCI and PnP.
+
+config MISDN_NETJET
+       bool "Support for NETJet cards"
+       depends on PCI
+       help
+          Enable support for Traverse Technologies' NETJet PCI cards.
+
+config MISDN_HFCPCI
+	bool "Support for HFC PCI cards"
+	depends on PCI
+	help
+	  Enable support for card with Cologne Chips Design HFC PCI based
+	  cards.
+
+config MISDN_HFCMULTI
+	bool "Support for HFC multiport cards (HFC-4S/8S/E1)"
+	depends on PCI
+	help
+	  Enable support for card with Cologne Chip AG's HFC multiport
+	  chip. There are three types of chips that are quite similar,
+	  but the interface is different:
+	   * HFC-4S (4 S/T interfaces on one chip)
+	   * HFC-8S (8 S/T interfaces on one chip)
+	   * HFC-E1 (E1 interface for 2Mbit ISDN)
+
+if MISDN_HFCMULTI!=n
+
+config HFCMULTI_PCIMEM
+	bool "HFC multiport driver with memory mapped IO"
+	depends on PCI
+	help
+	  Use memory mapped PCI access rather than IO access.
+	  This feature MIGHT be slightly faster, especially when
+	  using hardware DTMF detection. Also it may cause trouble with some
+	  PCI bridges.
+	  If unsure, say 'N'.
+
+endif
+
+config MISDN_HFCUSB
+	bool "Support for HFC-S USB based TAs"
+	depends on USB && EXPERIMENTAL
+	help
+	  Enable support for USB ISDN TAs with Cologne Chip AG's
+	  HFC-S USB ISDN Controller
+
+config MISDN_HFCMINI
+	bool "Support for 'HFC-S mini' based TAs"
+	depends on PCI
+	help
+	  Enable support for Cologne Chip AG's 'HFC-S mini' Evaluation Card
+
+config MISDN_XHFC
+	bool "Support for XHFC based cards"
+	depends on PCI
+	help
+	  Enable support for Cologne Chips AG's XHFC Evaluation Card
+
+config MISDN_SPEEDFAX
+	bool "Support for Sedlbauer Speedfax+"
+	depends on PCI || ISA
+	help
+	  Enable support for Sedlbauer Speedfax+.
+
+config MISDN_W6692
+	bool "Support for Winbond 6692 based cards"
+	depends on PCI
+	help
+	  Enable support for Winbond 6692 PCI chip based cards.
+
+config MISDN_DSP
+	bool "Digital Audio Processing of transparent data"
+	help
+	  Enable support for digital audio processing capability.
+	  This module may be used for special applications that require
+	  cross connecting of bchannels, conferencing, dtmf decoding
+	  echo cancelation, tone generation, and Blowfish encryption and
+	  decryption.
+	  It may use hardware features if available.
+	  E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu
+	  and get more informations about this module and it's usage.
+	  If unsure, say 'N'.
+
+config MISDN_LOOP
+	bool "Loop device"
+	help
+	  Enable support for loop device.
+	  This module may be used for special applications that provide
+	  bchannel data from user space. Applications can directly
+	  access bchannels, so applications can be integrated into DSP
+	  audio processing. 
+	  E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu
+	  and get more informations about this module and it's usage.
+	  If unsure, say 'N'.
+
+config MISDN_L1OIP
+	bool "ISDN over IP tunnel"
+	help
+	  Enable support for ISDN over IP tunnel.
+
+	  It features:
+	    - layer 1 control via network keepalive frames
+	    - dynamic IP exchange, if one or both peers have dynamic IPs
+	    - channel bundeling for reduced IP overhead
+	    - BRI (S0) and PRI (S2M) interface
+
+	  NOTE: This protocol is called 'Layer 1 over IP' and is not
+	  compatible with ISDNoIP (Agfeo) or TDMoIP.
+
+endif
+
+endmenu

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,119 @@
+# Makefile for the modular ISDN driver
+#
+EXTRA_CFLAGS += -ggdb
+#
+
+ifdef MINCLUDES
+CFLAGS += -I$(MINCLUDES) -g
+endif
+ifdef CONFIG_MISDN_MEMDEBUG
+	EXTRA_CFLAGS += -DMISDN_MEMDEBUG
+endif
+
+ifdef CONFIG_MISDN_NETDEV
+	EXTRA_CFLAGS += -DCONFIG_MISDN_NETDEV 
+endif
+
+CFLAGS += -DMISDNVERSION=\"$(MISDNVERSION)\"
+
+obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_l2.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_x25dte.o
+obj-$(CONFIG_MISDN_DRV) += l3udss1.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_capi.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_dtmf.o
+
+ifdef CONFIG_MISDN_AVM_FRITZ
+obj-$(CONFIG_MISDN_DRV) += avmfritz.o
+endif
+
+ifdef CONFIG_MISDN_NETJET
+obj-$(CONFIG_MISDN_DRV) += netjetpci.o
+endif
+
+ifdef CONFIG_MISDN_HFCPCI
+obj-$(CONFIG_MISDN_DRV) += hfcpci.o
+endif
+
+ifdef CONFIG_MISDN_HFCUSB
+obj-$(CONFIG_MISDN_DRV) += hfcsusb.o
+endif
+
+ifdef CONFIG_MISDN_HFCMINI
+obj-$(CONFIG_MISDN_DRV) += hfcsmini.o
+endif
+
+ifdef CONFIG_MISDN_SPEEDFAX
+obj-$(CONFIG_MISDN_DRV) += sedlfax.o
+# obj-$(CONFIG_MISDN_DRV) += faxl3.o
+endif
+
+ifdef CONFIG_MISDN_W6692
+obj-$(CONFIG_MISDN_DRV) += w6692pci.o
+endif
+
+ifdef CONFIG_MISDN_HFCMULTI
+obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
+endif
+
+ifdef CONFIG_MISDN_XHFC
+obj-$(CONFIG_MISDN_DRV) += xhfc.o
+endif
+
+ifdef CONFIG_MISDN_DSP
+obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
+endif
+
+ifdef CONFIG_MISDN_LOOP
+obj-$(CONFIG_MISDN_DRV) += mISDN_loop.o
+endif
+
+ifdef CONFIG_I4L_CAPI_LAYER
+obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
+endif
+
+# multi objects
+
+sedlfax-objs := sedl_fax.o isar.o
+avmfritz-objs := avm_fritz.o
+netjetpci-objs := netjet.o
+hfcpci-objs := hfc_pci.o
+hfcsusb-objs := hfcs_usb.o
+hfcsmini-objs := hfcs_mini.o
+w6692pci-objs := w6692.o
+hfcmulti-objs := hfc_multi.o
+xhfc-objs := xhfc_su.o xhfc_pci2pi.o
+mISDN_isac-objs := isac.o arcofi.o
+mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
+			channel.o l3helper.o \
+			sysfs_obj.o sysfs_inst.o sysfs_st.o 
+
+ifdef CONFIG_MISDN_NETDEV			
+mISDN_core-objs += netdev.o
+endif
+
+ifdef CONFIG_MISDN_MEMDEBUG
+mISDN_core-objs += memdbg.o
+endif
+
+ifdef CONFIG_MISDN_DEBUGTOOL
+obj-$(CONFIG_MISDN_DEBUGTOOL) += mISDN_debugtool.o
+endif
+
+mISDN_l1-objs := layer1.o
+mISDN_l2-objs := layer2.o tei.o
+l3udss1-objs := layer3.o l3_udss1.o
+mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
+                   asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
+                   asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
+                   supp_serv.o
+mISDN_dtmf-objs := dtmf.o
+mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o
+mISDN_loop-objs := loop.o
+mISDN_x25dte-objs := x25_dte.o x25_l3.o
+I4LmISDN-objs := i4l_mISDN.o
+mISDN_debugtool-objs := debugtool.o
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile.v2.4
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile.v2.4	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile.v2.4	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,74 @@
+# Makefile for the modular ISDN driver
+#
+# EXTRA_CFLAGS += -S -g
+#
+
+ifdef CONFIG_MISDN_MEMDEBUG
+	EXTRA_CFLAGS += -DMISDN_MEMDEBUG
+endif
+
+EXTRA_CFLAGS += -I ../../avmb1
+
+obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_l2.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_x25dte.o
+obj-$(CONFIG_MISDN_DRV) += l3udss1.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_capi.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_dtmf.o
+
+ifdef CONFIG_MISDN_AVM_FRITZ
+obj-$(CONFIG_MISDN_DRV) += avmfritz.o
+endif
+
+ifdef CONFIG_MISDN_HFCPCI
+obj-$(CONFIG_MISDN_DRV) += hfcpci.o
+endif
+
+ifdef CONFIG_MISDN_SPEEDFAX
+obj-$(CONFIG_MISDN_DRV) += sedlfax.o
+endif
+
+ifdef CONFIG_MISDN_W6692
+obj-$(CONFIG_MISDN_DRV) += w6692pci.o
+endif
+
+ifdef CONFIG_MISDN_HFCMULTI
+obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
+endif
+
+ifdef CONFIG_MISDN_DSP
+obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
+endif
+
+ifdef CONFIG_I4L_CAPI_LAYER
+obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
+endif
+
+# multi objects
+
+sedlfax-objs := sedl_fax.o isar.o
+avmfritz-objs := avm_fritz.o
+hfcpci-objs := hfc_pci.o
+w6692pci-objs := w6692.o
+hfcmulti-objs := hfc_multi.o
+mISDN_isac-objs := isac.o arcofi.o
+mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
+			dchannel.o bchannel.o l3helper.o
+ifdef CONFIG_MISDN_MEMDEBUG
+mISDN_core-objs += memdbg.o
+endif
+mISDN_l1-objs := layer1.o
+mISDN_l2-objs := layer2.o tei.o
+l3udss1-objs := layer3.o l3_udss1.o
+mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
+                   asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
+                   asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
+                   supp_serv.o
+mISDN_dtmf-objs := dtmf.o
+mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o
+mISDN_x25dte-objs := x25_dte.o x25_l3.o
+I4LmISDN-objs := i4l_mISDN.o
+
+include Rules.mISDN

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile.v2.6
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile.v2.6	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Makefile.v2.6	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,119 @@
+# Makefile for the modular ISDN driver
+#
+EXTRA_CFLAGS += -ggdb
+#
+
+ifdef MINCLUDES
+CFLAGS += -I$(MINCLUDES) -g
+endif
+ifdef CONFIG_MISDN_MEMDEBUG
+	EXTRA_CFLAGS += -DMISDN_MEMDEBUG
+endif
+
+ifdef CONFIG_MISDN_NETDEV
+	EXTRA_CFLAGS += -DCONFIG_MISDN_NETDEV 
+endif
+
+CFLAGS += -DMISDNVERSION=\"$(MISDNVERSION)\"
+
+obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_l2.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_x25dte.o
+obj-$(CONFIG_MISDN_DRV) += l3udss1.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_capi.o
+obj-$(CONFIG_MISDN_DRV) += mISDN_dtmf.o
+
+ifdef CONFIG_MISDN_AVM_FRITZ
+obj-$(CONFIG_MISDN_DRV) += avmfritz.o
+endif
+
+ifdef CONFIG_MISDN_NETJET
+obj-$(CONFIG_MISDN_DRV) += netjetpci.o
+endif
+
+ifdef CONFIG_MISDN_HFCPCI
+obj-$(CONFIG_MISDN_DRV) += hfcpci.o
+endif
+
+ifdef CONFIG_MISDN_HFCUSB
+obj-$(CONFIG_MISDN_DRV) += hfcsusb.o
+endif
+
+ifdef CONFIG_MISDN_HFCMINI
+obj-$(CONFIG_MISDN_DRV) += hfcsmini.o
+endif
+
+ifdef CONFIG_MISDN_SPEEDFAX
+obj-$(CONFIG_MISDN_DRV) += sedlfax.o
+# obj-$(CONFIG_MISDN_DRV) += faxl3.o
+endif
+
+ifdef CONFIG_MISDN_W6692
+obj-$(CONFIG_MISDN_DRV) += w6692pci.o
+endif
+
+ifdef CONFIG_MISDN_HFCMULTI
+obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
+endif
+
+ifdef CONFIG_MISDN_XHFC
+obj-$(CONFIG_MISDN_DRV) += xhfc.o
+endif
+
+ifdef CONFIG_MISDN_DSP
+obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
+endif
+
+ifdef CONFIG_MISDN_LOOP
+obj-$(CONFIG_MISDN_DRV) += mISDN_loop.o
+endif
+
+ifdef CONFIG_I4L_CAPI_LAYER
+obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
+endif
+
+# multi objects
+
+sedlfax-objs := sedl_fax.o isar.o
+avmfritz-objs := avm_fritz.o
+netjetpci-objs := netjet.o
+hfcpci-objs := hfc_pci.o
+hfcsusb-objs := hfcs_usb.o
+hfcsmini-objs := hfcs_mini.o
+w6692pci-objs := w6692.o
+hfcmulti-objs := hfc_multi.o
+xhfc-objs := xhfc_su.o xhfc_pci2pi.o
+mISDN_isac-objs := isac.o arcofi.o
+mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
+			channel.o l3helper.o \
+			sysfs_obj.o sysfs_inst.o sysfs_st.o 
+
+ifdef CONFIG_MISDN_NETDEV			
+mISDN_core-objs += netdev.o
+endif
+
+ifdef CONFIG_MISDN_MEMDEBUG
+mISDN_core-objs += memdbg.o
+endif
+
+ifdef CONFIG_MISDN_DEBUGTOOL
+obj-$(CONFIG_MISDN_DEBUGTOOL) += mISDN_debugtool.o
+endif
+
+mISDN_l1-objs := layer1.o
+mISDN_l2-objs := layer2.o tei.o
+l3udss1-objs := layer3.o l3_udss1.o
+mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
+                   asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
+                   asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
+                   supp_serv.o
+mISDN_dtmf-objs := dtmf.o
+mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o
+mISDN_loop-objs := loop.o
+mISDN_x25dte-objs := x25_dte.o x25_l3.o
+I4LmISDN-objs := i4l_mISDN.o
+mISDN_debugtool-objs := debugtool.o
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Module.symvers
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Module.symvers	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Module.symvers	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,54 @@
+0x2348cc3c	mISDN_FsmFree	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x9f6faa8f	mISDN_get_lowlayer	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x55a52462	mISDN_SetHandledPID	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x5485b257	mISDN_module_register	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xa2c73420	mISDN_HasProtocol	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xff10c7d9	mISDN_debug	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x8160c169	mISDN_get_free_ext_ie	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xc6091c92	mISDN_get_up_layer	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x0830e9af	mISDN_module_unregister	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x31559777	mISDN_l3_pos2ie	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x4950aaa3	mISDN_dec_usage	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xc8e830e8	mISDN_debugprint	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x980a83c0	mISDN_initQ931_info	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x199e0497	mISDN_FsmDelTimer	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xb270a77b	mISDN_dt_set_callback	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xf9e7832f	mISDN_FsmNew	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x1f79a296	mISDN_ctrl	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xd3da6173	mISDN_register	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x909eefcb	mISDN_AddvarIE	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x85718442	vmISDN_debug	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x44e33110	mISDN_init_instance	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xec8987aa	mISDN_freechannel	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xfd5689cf	mISDN_initchannel	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xf0f275f3	mISDN_dt_enable	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xe0ec9f1b	mISDN_clear_isac	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_isac	EXPORT_SYMBOL
+0xe97d7a63	mISDN_isac_free	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_isac	EXPORT_SYMBOL
+0xe633b2f7	mISDN_alloc_l3msg	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x91f1a1b8	mISDN_getrev	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x76dd67e6	mISDN_add_pid_parameter	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xeb0f03c0	mISDN_unregister	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x6a35c630	mISDN_l3_ie2pos	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x83ac49f2	mISDN_inc_usage	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xca0e8c99	mISDN_dt_disable	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xd2e1b581	mISDN_FsmRestartTimer	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x1fa788a8	mISDN_isac_interrupt	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_isac	EXPORT_SYMBOL
+0x78fb79ff	mISDN_isac_init	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_isac	EXPORT_SYMBOL
+0x7598dfb4	mISDN_setpara	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xd5145151	mISDN_FsmEvent	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x26a8fd4c	mISDN_RemoveUsedPID	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x91b96ea6	mISDN_QuickHex	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x48cbe644	mISDN_layermask2layer	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x2cab210f	mISDN_AddIE	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xc626878f	mISDN_ISAC_l1hw	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_isac	EXPORT_SYMBOL
+0x04690c9e	mISDN_get_last_repeated_ie	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x1b313dd2	mISDN_LogL3Msg	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x0fce7874	mISDN_FsmAddTimer	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x4b024b67	mISDN_bprotocol2pid	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xd1c0ae73	mISDN_get_down_layer	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xfb0c64fe	mISDN_FsmInitTimer	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x09d00b8a	mISDN_set_dchannel_pid	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xbe3a0b15	mISDN_get_protocol	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0x50c2230c	mISDN_FsmChangeState	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xaf33c6fa	mISDN_dt_new_frame	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL
+0xf2ea1d2a	mISDN_queue_message	/usr/src/mISDN/drivers/isdn/hardware/mISDN/mISDN_core	EXPORT_SYMBOL

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Rules.mISDN.v2.4
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Rules.mISDN.v2.4	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Rules.mISDN.v2.4	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,79 @@
+# 
+# local Rules for 2.4
+#
+
+O_TARGET := vmlinux-obj.o
+
+export-objs := core.o isac.o helper.o debug.o fsm.o dchannel.o bchannel.o \
+		l3helper.o
+
+ifdef CONFIG_MISDN_MEMDEBUG
+	export-objs += memdbg.o
+endif
+
+M_OBJS := $(obj-m)
+
+include $(TOPDIR)/Rules.make
+
+mISDN_core.o: $(mISDN_core-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+mISDN_isac.o: $(mISDN_isac-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+avmfritz.o: $(avmfritz-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+sedlfax.o: $(sedlfax-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+w6692pci.o: $(w6692pci-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+hfcpci.o: $(hfcpci-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+hfcmulti.o: $(hfcmulti-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+mISDN_l1.o: $(mISDN_l1-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+mISDN_l2.o: $(mISDN_l2-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+mISDN_x25dte.o: $(mISDN_x25dte-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+l3udss1.o: $(l3udss1-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+mISDN_capi.o: $(mISDN_capi-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+mISDN_dtmf.o: $(mISDN_dtmf-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+ifdef CONFIG_I4L_CAPI_LAYER
+I4LmISDN.o: $(I4LmISDN-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
+
+endif
+
+mISDN_dsp.o: $(mISDN_dsp-objs)
+	$(RM) $@
+	$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)


Property changes on: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/Rules.mISDN.v2.4
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/app_plci.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/app_plci.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/app_plci.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,2280 @@
+/* $Id: app_plci.c,v 1.19 2006/12/06 15:18:07 gkelleter Exp $
+ *
+ */
+
+#include "m_capi.h"
+#include "helper.h"
+#include "debug.h"
+#include "dss1.h"
+
+#define AppPlciDebug(aplci, lev, fmt, args...) \
+	capidebug(lev, fmt, ## args)
+
+static void 	AppPlciClearOtherApps(AppPlci_t *);
+static void 	AppPlciInfoIndMsg(AppPlci_t *,  __u32, unsigned char);
+static void 	AppPlciInfoIndIE(AppPlci_t *, unsigned char, __u32, Q931_info_t *);
+static int 	AppPlciLinkUp(AppPlci_t *);
+static int	AppPlciLinkDown(AppPlci_t *);
+
+static u_char BEARER_SPEECH_64K_ALAW[] = {4, 3, 0x80, 0x90, 0xA3};
+static u_char BEARER_SPEECH_64K_ULAW[] = {4, 3, 0x80, 0x90, 0xA2};
+static u_char BEARER_UNRES_DIGITAL_64K[] = {4, 2, 0x88, 0x90};
+static u_char BEARER_RES_DIGITAL_64K[] = {4, 2, 0x89, 0x90};
+static u_char BEARER_31AUDIO_64K_ALAW[] = {4, 3, 0x90, 0x90, 0xA3};
+static u_char BEARER_31AUDIO_64K_ULAW[] = {4, 3, 0x90, 0x90, 0xA2};
+static u_char HLC_TELEPHONY[] = {0x7d, 2, 0x91, 0x81};
+static u_char HLC_FACSIMILE[] = {0x7d, 2, 0x91, 0x84};
+
+__u16 q931CIPValue(Q931_info_t *qi)
+{
+	__u16	CIPValue = 0;
+	u_char	*p;
+
+	if (!qi)
+		return 0;
+	if (!qi->bearer_capability.off)
+		return 0;
+	p = (u_char *)qi;
+	p += L3_EXTRA_SIZE + qi->bearer_capability.off;
+	if (memcmp(p, BEARER_SPEECH_64K_ALAW, 5) == 0
+	    || memcmp(p, BEARER_SPEECH_64K_ULAW, 5) == 0) {
+		CIPValue = 1;
+	} else if (memcmp(p, BEARER_UNRES_DIGITAL_64K, 4) == 0) {
+		CIPValue = 2;
+	} else if (memcmp(p, BEARER_RES_DIGITAL_64K, 4) == 0) {
+		CIPValue = 3;
+	} else if (memcmp(p, BEARER_31AUDIO_64K_ALAW, 5) == 0
+		   || memcmp(p, BEARER_31AUDIO_64K_ULAW, 5) == 0) {
+		CIPValue = 4;
+	} else {
+		CIPValue = 0;
+	}
+
+	// FIXME: handle duplicated IE's
+	if (!qi->hlc.off)
+		return CIPValue;
+
+	p = (u_char *)qi;
+	p += L3_EXTRA_SIZE + qi->hlc.off;
+	if ((CIPValue == 1) || (CIPValue == 4)) {
+		if (memcmp(p, HLC_TELEPHONY, 4) == 0) {
+			CIPValue = 16;
+		} else if (memcmp(p, HLC_FACSIMILE, 4) == 0) {
+			CIPValue = 17;
+		}
+	}
+	return CIPValue;
+}
+
+u_int plci_parse_channel_id(u_char *p)
+{
+	u_int	cid = -1;
+	int	l;
+
+	if (p) {
+		p++;
+		capidebug(CAPI_DBG_PLCI_INFO, "%s: l(%d) %x", __FUNCTION__, p[0], p[1]);
+		l = *p++;
+		if (l == 1) {
+			cid = *p;
+		} else if (l == 3) {
+			cid =  *p++ << 16;
+			cid |= *p++ << 8;
+			cid |= *p;
+		}
+	}
+	return(cid);
+}
+
+__u16 CIPValue2setup(__u16 CIPValue, struct sk_buff *skb)
+{
+	switch (CIPValue) {
+		case 16:
+			mISDN_AddvarIE(skb, BEARER_31AUDIO_64K_ALAW);
+			mISDN_AddvarIE(skb, HLC_TELEPHONY);
+			break;
+		case 17:
+			mISDN_AddvarIE(skb, BEARER_31AUDIO_64K_ALAW);
+			mISDN_AddvarIE(skb, HLC_FACSIMILE);
+			break;
+		case 1:
+			mISDN_AddvarIE(skb, BEARER_SPEECH_64K_ALAW);
+			break;
+		case 2:
+			mISDN_AddvarIE(skb, BEARER_UNRES_DIGITAL_64K);
+			break;
+		case 3:
+			mISDN_AddvarIE(skb, BEARER_RES_DIGITAL_64K);
+			break;
+		case 4:
+			mISDN_AddvarIE(skb, BEARER_31AUDIO_64K_ALAW);
+			break;
+		default:
+			return CapiIllMessageParmCoding;
+	}
+	return 0;
+}
+
+__u16 cmsg2setup_req(_cmsg *cmsg, struct sk_buff *skb)
+{
+	if (CIPValue2setup(cmsg->CIPValue, skb))
+		goto err;
+	mISDN_AddIE(skb, IE_CALLING_PN, cmsg->CallingPartyNumber);
+	mISDN_AddIE(skb, IE_CALLING_SUB, cmsg->CallingPartySubaddress);
+	mISDN_AddIE(skb, IE_CALLED_PN, cmsg->CalledPartyNumber);
+	mISDN_AddIE(skb, IE_CALLED_SUB, cmsg->CalledPartySubaddress);
+	mISDN_AddIE(skb, IE_BEARER, cmsg->BC);
+	mISDN_AddIE(skb, IE_LLC, cmsg->LLC);
+	mISDN_AddIE(skb, IE_HLC, cmsg->HLC);
+	return 0;
+ err:
+	return CapiIllMessageParmCoding;
+}
+
+__u16 cmsg2info_req(_cmsg *cmsg, struct sk_buff *skb)
+{
+	mISDN_AddIE(skb, IE_KEYPAD, cmsg->Keypadfacility);
+	mISDN_AddIE(skb, IE_CALLED_PN, cmsg->CalledPartyNumber);
+	return 0;
+}
+
+__u16 cmsg2alerting_req(_cmsg *cmsg, struct sk_buff *skb)
+{
+	mISDN_AddIE(skb, IE_USER_USER, cmsg->Useruserdata);
+	return 0;
+}
+
+__u16 AppPlciCheckBprotocol(AppPlci_t *aplci, _cmsg *cmsg)
+{
+	struct capi_ctr	*ctrl = aplci->contr->ctrl;
+	u_long		sprot;
+
+	sprot = le32_to_cpu(ctrl->profile.support1);
+	if (!test_bit(cmsg->B1protocol, &sprot))
+		return CapiB1ProtocolNotSupported;
+	sprot = le32_to_cpu(ctrl->profile.support2);
+	if (!test_bit(cmsg->B2protocol, &sprot))
+		return CapiB2ProtocolNotSupported;
+	sprot = le32_to_cpu(ctrl->profile.support3);
+	if (!test_bit(cmsg->B3protocol, &sprot))
+		return CapiB3ProtocolNotSupported;
+	aplci->Bprotocol.B1 = cmsg->B1protocol;
+	aplci->Bprotocol.B2 = cmsg->B2protocol;
+	aplci->Bprotocol.B3 = cmsg->B3protocol;
+	if (cmsg->B1configuration && cmsg->B1configuration[0]) {
+		if (cmsg->B1configuration[0] > 15) {
+			int_errtxt("B1cfg too large(%d)", cmsg->B1configuration[0]);
+			return CapiB1ProtocolParameterNotSupported;
+		}
+		memcpy(&aplci->Bprotocol.B1cfg[0], cmsg->B1configuration, cmsg->B1configuration[0] + 1);
+	} else
+		aplci->Bprotocol.B1cfg[0] = 0;
+	if (cmsg->B2configuration && cmsg->B2configuration[0]) {
+		if (cmsg->B2configuration[0] > 15) {
+			int_errtxt("B2cfg too large(%d)", cmsg->B2configuration[0]);
+			return CapiB2ProtocolParameterNotSupported;
+		}
+		memcpy(&aplci->Bprotocol.B2cfg[0], cmsg->B2configuration, cmsg->B2configuration[0] + 1);
+	} else
+		aplci->Bprotocol.B2cfg[0] = 0;
+	if (cmsg->B3configuration && cmsg->B3configuration[0]) {
+		if (cmsg->B3configuration[0] > 79) {
+			int_errtxt("B3cfg too large(%d)", cmsg->B3configuration[0]);
+			return CapiB3ProtocolParameterNotSupported;
+		}
+		memcpy(&aplci->Bprotocol.B3cfg[0], cmsg->B3configuration, cmsg->B3configuration[0] + 1);
+	} else
+		aplci->Bprotocol.B3cfg[0] = 0;
+	return 0;
+}
+
+// --------------------------------------------------------------------
+// PLCI state machine
+//
+// Some rules:
+//   *  EV_AP_*  events come from CAPI Application
+//   *  EV_L3_*  events come from the ISDN stack
+//   *  EV_PI_*  events generated in PLCI handling
+//   *  messages are send in the routine that handle the event
+//
+// --------------------------------------------------------------------
+
+enum {
+	ST_PLCI_P_0,
+	ST_PLCI_P_0_1,
+	ST_PLCI_P_1,
+	ST_PLCI_P_2,
+	ST_PLCI_P_3,
+	ST_PLCI_P_4,
+	ST_PLCI_P_ACT,
+	ST_PLCI_P_HELD,
+	ST_PLCI_P_5,
+	ST_PLCI_P_6,
+	ST_PLCI_P_RES,
+}
+
+const ST_PLCI_COUNT = ST_PLCI_P_RES + 1;
+
+static char *str_st_plci[] = {	
+	"ST_PLCI_P_0",
+	"ST_PLCI_P_0_1",
+	"ST_PLCI_P_1",
+	"ST_PLCI_P_2",
+	"ST_PLCI_P_3",
+	"ST_PLCI_P_4",
+	"ST_PLCI_P_ACT",
+	"ST_PLCI_P_HELD",
+	"ST_PLCI_P_5",
+	"ST_PLCI_P_6",
+	"ST_PLCI_P_RES",
+}; 
+
+enum {
+	EV_AP_CONNECT_REQ,
+	EV_PI_CONNECT_CONF,
+	EV_PI_CONNECT_IND,
+	EV_AP_CONNECT_RESP,
+	EV_PI_CONNECT_ACTIVE_IND,
+	EV_AP_CONNECT_ACTIVE_RESP,
+	EV_AP_ALERT_REQ,
+	EV_AP_INFO_REQ,
+	EV_PI_INFO_IND,
+	EV_PI_FACILITY_IND,
+	EV_AP_SELECT_B_PROTOCOL_REQ,
+	EV_AP_DISCONNECT_REQ,
+	EV_PI_DISCONNECT_IND,
+	EV_AP_DISCONNECT_RESP,
+	EV_AP_HOLD_REQ,
+	EV_AP_RETRIEVE_REQ,
+	EV_PI_HOLD_CONF,
+	EV_PI_RETRIEVE_CONF,
+	EV_AP_SUSPEND_REQ,
+	EV_PI_SUSPEND_CONF,
+	EV_AP_RESUME_REQ,
+	EV_PI_RESUME_CONF,
+	EV_PI_CHANNEL_ERR,
+	EV_L3_SETUP_IND,
+	EV_L3_SETUP_CONF_ERR,
+	EV_L3_SETUP_CONF,
+	EV_L3_SETUP_COMPL_IND,
+	EV_L3_DISCONNECT_IND,
+	EV_L3_RELEASE_IND,
+	EV_L3_RELEASE_PROC_IND,
+	EV_L3_NOTIFY_IND,
+	EV_L3_HOLD_IND,
+	EV_L3_HOLD_ACKNOWLEDGE,
+	EV_L3_HOLD_REJECT,
+	EV_L3_RETRIEVE_IND,
+	EV_L3_RETRIEVE_ACKNOWLEDGE,
+	EV_L3_RETRIEVE_REJECT,
+	EV_L3_SUSPEND_ERR,
+	EV_L3_SUSPEND_CONF,
+	EV_L3_RESUME_ERR,
+	EV_L3_RESUME_CONF,
+	EV_L3_REJECT_IND,
+	EV_PH_CONTROL_IND,
+	EV_AP_RELEASE,
+}
+
+const EV_PLCI_COUNT = EV_AP_RELEASE + 1;
+
+static char* str_ev_plci[] = {
+	"EV_AP_CONNECT_REQ",
+	"EV_PI_CONNECT_CONF",
+	"EV_PI_CONNECT_IND",
+	"EV_AP_CONNECT_RESP",
+	"EV_PI_CONNECT_ACTIVE_IND",
+	"EV_AP_CONNECT_ACTIVE_RESP",
+	"EV_AP_ALERT_REQ",
+	"EV_AP_INFO_REQ",
+	"EV_PI_INFO_IND",
+	"EV_PI_FACILITY_IND",
+	"EV_AP_SELECT_B_PROTOCOL_REQ",
+	"EV_AP_DISCONNECT_REQ",
+	"EV_PI_DISCONNECT_IND",
+	"EV_AP_DISCONNECT_RESP",
+	"EV_AP_HOLD_REQ",
+	"EV_AP_RETRIEVE_REQ",
+	"EV_PI_HOLD_CONF",
+	"EV_PI_RETRIEVE_CONF",
+	"EV_AP_SUSPEND_REQ",
+	"EV_PI_SUSPEND_CONF",
+	"EV_AP_RESUME_REQ",
+	"EV_PI_RESUME_CONF",
+	"EV_PI_CHANNEL_ERR",
+	"EV_L3_SETUP_IND",
+	"EV_L3_SETUP_CONF_ERR",
+	"EV_L3_SETUP_CONF",
+	"EV_L3_SETUP_COMPL_IND",
+	"EV_L3_DISCONNECT_IND",
+	"EV_L3_RELEASE_IND",
+	"EV_L3_RELEASE_PROC_IND",
+	"EV_L3_NOTIFY_IND",
+	"EV_L3_HOLD_IND",
+	"EV_L3_HOLD_ACKNOWLEDGE",
+	"EV_L3_HOLD_REJECT",
+	"EV_L3_RETRIEVE_IND",
+	"EV_L3_RETRIEVE_ACKNOWLEDGE",
+	"EV_L3_RETRIEVE_REJECT",
+	"EV_L3_SUSPEND_ERR",
+	"EV_L3_SUSPEND_CONF",
+	"EV_L3_RESUME_ERR",
+	"EV_L3_RESUME_CONF",
+	"EV_L3_REJECT_IND",
+	"EV_PH_CONTROL_IND",
+	"EV_AP_RELEASE",
+};
+
+static struct Fsm plci_fsm =
+{ 0, 0, 0, 0, 0 };
+
+static void
+AppPlci_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	char tmp[128];
+	char *p = tmp;
+	va_list args;
+	AppPlci_t *aplci = fi->userdata;
+  
+	va_start(args, fmt);
+	p += sprintf(p, "APLCI 0x%x: ", aplci->addr);
+	p += vsprintf(p, fmt, args);
+	*p = 0;
+	AppPlciDebug(aplci, CAPI_DBG_PLCI_STATE, tmp);
+	va_end(args);
+}
+
+static inline void
+Send2Application(AppPlci_t *aplci, _cmsg *cmsg)
+{
+	SendCmsg2Application(aplci->appl, cmsg);
+}
+
+static void
+SendingDelayedMsg(AppPlci_t *aplci)
+{
+	struct sk_buff  *skb;
+
+	while((skb = skb_dequeue(&aplci->delayedq))) {
+		if (test_bit(APPL_STATE_RELEASE, &aplci->appl->state)) {
+			printk(KERN_WARNING "%s: Application allready released\n", __FUNCTION__);
+			dev_kfree_skb(skb);
+		} else {
+#ifdef OLDCAPI_DRIVER_INTERFACE
+			aplci->appl->contr->ctrl->handle_capimsg(aplci->appl->contr->ctrl, aplci->appl->ApplId, skb);
+#else
+			capi_ctr_handle_message(aplci->appl->contr->ctrl, aplci->appl->ApplId, skb);
+#endif
+		}
+	}
+	test_and_clear_bit(PLCI_STATE_SENDDELAYED, &aplci->plci->state);
+}
+
+static void
+Send2ApplicationDelayed(AppPlci_t *aplci, _cmsg *cmsg)
+{
+	struct sk_buff	*skb;
+	
+	if (test_bit(APPL_STATE_RELEASE, &aplci->appl->state)) {
+		printk(KERN_WARNING "%s: Application allready released\n", __FUNCTION__);
+		cmsg_free(cmsg);
+		return;
+	}
+	if (!(skb = alloc_skb(CAPI_MSG_DEFAULT_LEN, GFP_ATOMIC))) {
+		printk(KERN_WARNING "%s: no mem for %d bytes\n", __FUNCTION__, CAPI_MSG_DEFAULT_LEN);
+		int_error();
+		cmsg_free(cmsg);
+		return;
+	}
+	capi_cmsg2message(cmsg, skb->data);
+	AppPlciDebug(aplci, CAPI_DBG_APPL_MSG, "%s: len(%d) applid(%x) %s msgnr(%d) addr(%08x)",
+		__FUNCTION__, CAPIMSG_LEN(skb->data), cmsg->ApplId, capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+		cmsg->Messagenumber, cmsg->adr.adrController);
+	cmsg_free(cmsg);
+	if (CAPI_MSG_DEFAULT_LEN < CAPIMSG_LEN(skb->data)) {
+		printk(KERN_ERR "%s: CAPI_MSG_DEFAULT_LEN overrun (%d/%d)\n", __FUNCTION__,
+			CAPIMSG_LEN(skb->data), CAPI_MSG_DEFAULT_LEN);
+		int_error();
+		dev_kfree_skb(skb);
+		return;
+	}
+	skb_put(skb, CAPIMSG_LEN(skb->data));
+	skb_queue_tail(&aplci->delayedq, skb);
+	if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state) &&
+		!test_and_set_bit(PLCI_STATE_SENDDELAYED, &aplci->plci->state))
+		SendingDelayedMsg(aplci);
+}
+
+static inline void
+AppPlciCmsgHeader(AppPlci_t *aplci, _cmsg *cmsg, __u8 cmd, __u8 subcmd)
+{
+	capi_cmsg_header(cmsg, aplci->appl->ApplId, cmd, subcmd, 
+			 aplci->appl->MsgId++, aplci->addr);
+}
+
+static void
+plci_connect_req(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Plci_t		*plci = aplci->plci;
+	struct sk_buff	*skb;
+	_cmsg		*cmsg = arg;
+	__u16		Info = 0;
+
+	mISDN_FsmChangeState(fi, ST_PLCI_P_0_1);
+	test_and_set_bit(PLCI_STATE_OUTGOING, &plci->state);
+
+	skb = mISDN_alloc_l3msg(260, MT_SETUP);
+	
+	if (!skb) {
+		Info = CapiNoPlciAvailable;
+		goto answer;
+	}
+	if ((Info = cmsg2setup_req(cmsg, skb))) {
+		goto answer;
+	}
+	if ((Info = AppPlciCheckBprotocol(aplci, cmsg))) {
+		goto answer;
+	}
+
+	plciNewCrReq(plci);
+	plciL4L3(plci, CC_SETUP | REQUEST, skb);
+answer:
+	capi_cmsg_answer(cmsg);
+	cmsg->Info = Info;
+	if (cmsg->Info == 0) 
+		cmsg->adr.adrPLCI = aplci->addr;
+	mISDN_FsmEvent(fi, EV_PI_CONNECT_CONF, cmsg);
+}
+
+static void
+plci_connect_conf(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	_cmsg		*cmsg = arg;
+  
+	if (cmsg->Info == 0) {
+		Send2Application(aplci, cmsg);
+		mISDN_FsmChangeState(fi, ST_PLCI_P_1);
+	} else {
+		Send2Application(aplci, cmsg);
+		mISDN_FsmChangeState(fi, ST_PLCI_P_0);
+		AppPlciDestr(aplci);
+	}
+}
+
+static void
+plci_connect_ind(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_PLCI_P_2);
+	Send2Application(fi->userdata, arg);
+}
+
+static void plci_hold_req(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Plci_t	*plci = aplci->plci;
+
+	plciL4L3(plci, CC_HOLD | REQUEST, arg); 
+}
+
+static void plci_retrieve_req(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Plci_t	*plci = aplci->plci;
+
+	plciL4L3(plci, CC_RETRIEVE | REQUEST, arg); 
+}
+
+static void plci_suspend_req(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Plci_t	*plci = aplci->plci;
+
+	plciL4L3(plci, CC_SUSPEND | REQUEST, arg); 
+}
+
+static void plci_resume_req(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Plci_t		*plci = aplci->plci;
+
+	// we already sent CONF with Info = SuppInfo = 0
+	mISDN_FsmChangeState(fi, ST_PLCI_P_RES);
+	plciNewCrReq(plci);
+	plciL4L3(plci, CC_RESUME | REQUEST, arg);
+}
+
+static void
+plci_alert_req(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Plci_t		*plci = aplci->plci;
+	_cmsg		*cmsg = arg;
+	__u16		Info = 0;
+	
+	if (test_and_set_bit(PLCI_STATE_ALERTING, &plci->state)) {
+		Info = 0x0003; // other app is already alerting
+	} else {
+		struct sk_buff	*skb = mISDN_alloc_l3msg(260, MT_ALERTING);
+		if (!skb) {
+			int_error();
+			goto answer;
+		}
+		Info = cmsg2alerting_req(cmsg, skb);
+		if (Info == 0) {
+			plciL4L3(plci, CC_ALERTING | REQUEST, skb);
+		}
+	}
+answer:	
+	capi_cmsg_answer(cmsg);
+	cmsg->Info = Info;
+	Send2Application(aplci, cmsg);
+}
+
+static void
+plci_connect_resp(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Plci_t		*plci = aplci->plci;
+	unsigned char	cause[4];
+	_cmsg		*cmsg = arg;
+	struct sk_buff	*skb;
+
+	if (cmsg->Reject == 0) { // accept
+		if (AppPlciCheckBprotocol(aplci, cmsg)) {
+			int_error();
+		}
+		AppPlciClearOtherApps(aplci);
+		plciL4L3(plci, CC_CONNECT | REQUEST, NULL);
+		mISDN_FsmChangeState(fi, ST_PLCI_P_4);
+		cmsg_free(cmsg);
+		return;
+	}
+	// ignore, reject 
+	memcpy(cause, "\x02\x80", 2); // IE CAUSE, location = local
+	switch (cmsg->Reject) {
+		case 2: cause[2] = 0x90; break; // normal call clearing
+		case 3: cause[2] = 0x91; break; // user busy
+		case 4: cause[2] = 0xac; break; // req circuit/channel not avail
+		case 5: cause[2] = 0x9d; break; // fac rejected
+		case 6: cause[2] = 0x86; break; // channel unacceptable
+		case 7: cause[2] = 0xd8; break; // incompatible dest
+		case 8: cause[2] = 0x9b; break; // dest out of order
+		default:
+			if ((cmsg->Reject & 0xff00) == 0x3400) {
+				cause[2] = cmsg->Reject & 0xff;
+			} else {
+				cause[2] = 0x90; break; // normal call clearing
+			}
+	}
+	// FIXME
+	// WHY ???
+	// if (cmsg->Reject != 1) {
+		// ignore
+	//	AppPlciClearOtherApps(aplci);
+	// }
+	// plciDetachAppPlci(plci, aplci);
+	if (plci->nAppl == 1) {
+		int prim;
+		if (test_bit(PLCI_STATE_ALERTING, &plci->state)) {
+			prim = CC_DISCONNECT | REQUEST;
+			skb = mISDN_alloc_l3msg(10, MT_DISCONNECT);
+		} else {
+			// if we already answered, we can't just ignore but must clear actively
+			prim = CC_RELEASE_COMPLETE | REQUEST;
+			skb = mISDN_alloc_l3msg(10, MT_RELEASE_COMPLETE);
+		}
+		if (!skb) {
+			plciL4L3(plci, prim, NULL);
+		} else {
+			mISDN_AddIE(skb, IE_CAUSE, cause);
+			plciL4L3(plci, prim, skb);
+		}
+	}
+	cmsg->Command = CAPI_DISCONNECT;
+	cmsg->Subcommand = CAPI_IND;
+	cmsg->Messagenumber = aplci->appl->MsgId++;
+	cmsg->Reject = 0x3400 | cause[2];
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+plci_connect_active_ind(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t *aplci = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_PLCI_P_ACT);
+	AppPlciLinkUp(aplci);
+	if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state))
+		Send2Application(aplci, arg);
+	else
+		Send2ApplicationDelayed(aplci, arg);
+}
+
+static void plci_connect_active_resp(struct FsmInst *fi, int event, void *arg)
+{
+	cmsg_free(arg);
+}
+
+static void plci_disconnect_req(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Plci_t		*plci = aplci->plci;
+	u_char		cause[4];
+	_cmsg		*cmsg = arg;
+
+	mISDN_FsmChangeState(fi, ST_PLCI_P_5);
+	
+	if (!plci) {
+		int_error();
+		return;
+	}
+	// FIXME handle additional Inf
+	capi_cmsg_answer(cmsg);
+	cmsg->Reason = 0; // disconnect initiated
+	Send2Application(aplci, cmsg);
+
+	AppPlciLinkDown(aplci);
+
+	if (!aplci->cause[0]) { // FIXME handle additional Info
+		struct sk_buff	*skb;
+
+		skb = mISDN_alloc_l3msg(10, MT_DISCONNECT);
+		if (!skb) {
+			plciL4L3(plci, CC_DISCONNECT | REQUEST, NULL);
+		} else {
+			memcpy(cause, "\x02\x80\x90", 3); // normal call clearing
+			mISDN_AddIE(skb, IE_CAUSE, cause);
+			plciL4L3(plci, CC_DISCONNECT | REQUEST, skb);
+		}
+	} else {
+		/* release physical link */
+		// FIXME
+		plciL4L3(plci, CC_RELEASE | REQUEST, NULL);
+	}
+}
+
+static void plci_suspend_conf(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_PLCI_P_5);
+}
+
+static void plci_resume_conf(struct FsmInst *fi, int event, void *arg)
+{
+	// facility_ind Resume: Reason = 0
+	AppPlci_t	*aplci = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_PLCI_P_ACT);
+	AppPlciLinkUp(aplci);
+	if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state))
+		Send2Application(aplci, arg);
+	else
+		Send2ApplicationDelayed(aplci, arg);
+}
+
+static void
+plci_disconnect_ind(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_PLCI_P_6);
+	Send2Application(fi->userdata, arg);
+}
+
+static void
+plci_disconnect_resp(struct FsmInst *fi, int event, void *arg)
+{
+	if (arg)
+		cmsg_free(arg);
+	mISDN_FsmChangeState(fi, ST_PLCI_P_0);
+	AppPlciDestr(fi->userdata);
+}
+
+static void
+plci_appl_release(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlciDestr(fi->userdata);
+}
+
+static void
+plci_appl_release_disc(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Plci_t		*plci = aplci->plci;
+
+	mISDN_FsmChangeState(fi, ST_PLCI_P_5);
+	
+	if (!plci) {
+		int_error();
+		return;
+	}
+
+	AppPlciLinkDown(aplci);
+
+	if (!aplci->cause[0]) {
+		struct sk_buff	*skb;
+
+		skb = mISDN_alloc_l3msg(10, MT_DISCONNECT);
+		if (!skb) {
+			plciL4L3(plci, CC_DISCONNECT | REQUEST, NULL);
+		} else {
+			u_char *cause = "\x02\x80\x9f";
+
+			mISDN_AddIE(skb, IE_CAUSE, cause);
+			plciL4L3(plci, CC_DISCONNECT | REQUEST, skb);
+		}
+	} else {
+		/* release physical link */
+		// FIXME
+		plciL4L3(plci, CC_RELEASE | REQUEST, NULL);
+	}
+}
+
+static void
+plci_cc_setup_conf(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	_cmsg		*cmsg;
+	Q931_info_t	*qi = arg;
+	u_char		*p;
+
+	if (aplci->channel == -1) {/* no valid channel set */
+		mISDN_FsmEvent(fi, EV_PI_CHANNEL_ERR, NULL);
+		return;
+	}
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_CONNECT_ACTIVE, CAPI_IND);
+	if (qi) {
+		p = (u_char *)qi;
+		p += L3_EXTRA_SIZE;
+		if (qi->connected_nr.off)
+			cmsg->ConnectedNumber = &p[qi->connected_nr.off + 1];
+		if (qi->connected_sub.off)
+			cmsg->ConnectedSubaddress = &p[qi->connected_sub.off + 1];
+		if (qi->llc.off)
+			cmsg->LLC = &p[qi->llc.off + 1];
+	}
+	if (mISDN_FsmEvent(fi, EV_PI_CONNECT_ACTIVE_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+plci_cc_setup_conf_err(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	_cmsg		*cmsg;
+
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND);
+	cmsg->Reason = CapiProtocolErrorLayer3;
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+plci_channel_err(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	_cmsg		*cmsg;
+	u_char		cause[4];
+	struct sk_buff	*skb;
+
+	skb = mISDN_alloc_l3msg(10, MT_RELEASE_COMPLETE);
+	if (skb) {
+		cause[0] = 2;
+		cause[1] = 0x80;
+		cause[2] = 0x86; /* channel unacceptable */
+		mISDN_AddIE(skb, IE_CAUSE, cause);
+		plciL4L3(aplci->plci, CC_RELEASE_COMPLETE | REQUEST, skb);
+	} else
+		int_error();
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND);
+	cmsg->Reason = CapiProtocolErrorLayer3;
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+plci_cc_setup_ind(struct FsmInst *fi, int event, void *arg)
+{ 
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t	*qi = arg;
+	_cmsg		*cmsg;
+	u_char		*p;
+
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_CONNECT, CAPI_IND);
+
+	// FIXME: CW
+	if (qi) {
+		p = (u_char *)qi;
+		p += L3_EXTRA_SIZE;
+		cmsg->CIPValue = q931CIPValue(qi);
+		if (qi->called_nr.off)
+			cmsg->CalledPartyNumber = &p[qi->called_nr.off + 1];
+		if (qi->called_sub.off)
+			cmsg->CalledPartySubaddress = &p[qi->called_sub.off + 1];
+		if (qi->calling_nr.off)
+			cmsg->CallingPartyNumber = &p[qi->calling_nr.off + 1];
+		if (qi->calling_sub.off)
+			cmsg->CallingPartySubaddress = &p[qi->calling_sub.off + 1];
+		if (qi->bearer_capability.off)
+			cmsg->BC = &p[qi->bearer_capability.off + 1];
+		if (qi->llc.off)
+			cmsg->LLC = &p[qi->llc.off + 1];
+		if (qi->hlc.off)
+			cmsg->HLC = &p[qi->hlc.off + 1];
+#if CAPIUTIL_VERSION > 1
+		/* ETS 300 092 Annex B */
+		if (qi->calling_nr.repeated) {
+			if (qi->ext[qi->calling_nr.ridx].ie.off)
+				cmsg->CallingPartyNumber2 = &p[qi->ext[qi->calling_nr.ridx].ie.off + 1];
+			else
+				int_error();
+		}
+#endif
+		// all else set to default
+	}
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_CONNECT_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+plci_cc_setup_compl_ind(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	_cmsg		*cmsg;
+
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_CONNECT_ACTIVE, CAPI_IND);
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_CONNECT_ACTIVE_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+plci_cc_disconnect_ind(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t	*qi = arg;
+	u_char		*p;
+
+	if (qi) {
+		p = (u_char *)qi;
+		p += L3_EXTRA_SIZE;
+		if (qi->cause.off)
+			memcpy(aplci->cause, &p[qi->cause.off + 1], 3);
+	}
+	if (aplci->appl->InfoMask & CAPI_INFOMASK_EARLYB3)
+		return;
+
+//	AppPlciLinkDown(aplci);
+	plciL4L3(aplci->plci, CC_RELEASE | REQUEST, NULL);
+}
+
+static void
+plci_cc_release_ind(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t	*qi = arg;
+	u_char		*p;
+	_cmsg		*cmsg;
+
+	AppPlciLinkDown(aplci);
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND);
+	if (qi) {
+		p = (u_char *)qi;
+		p += L3_EXTRA_SIZE;
+		if (qi->cause.off)
+			cmsg->Reason = 0x3400 | p[qi->cause.off + 3];
+		else if (aplci->cause[0]) // cause from CC_DISCONNECT IND
+			cmsg->Reason = 0x3400 | aplci->cause[2];
+		else
+			cmsg->Reason = 0;
+	} else {
+		cmsg->Reason = CapiProtocolErrorLayer1;
+	}
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+plci_cc_notify_ind(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t	*qi = arg;
+	__u8		*nf;
+
+	if (!qi || !qi->notify.off)
+		return;
+	nf = (u_char *)qi;
+	nf += L3_EXTRA_SIZE + qi->notify.off + 1;
+	if (nf[0] != 1) // len != 1
+		return;
+	switch (nf[1]) {
+		case 0xF9: // user hold
+			SendSSNotificationEvent(aplci, 0x8000);
+			break;
+		case 0xFA: // user retrieve
+			SendSSNotificationEvent(aplci, 0x8001);
+			break;
+		case 0x80: // user suspended
+			SendSSNotificationEvent(aplci, 0x8002);
+			break;
+		case 0x81: // user resumed
+			SendSSNotificationEvent(aplci, 0x8003);
+			break;
+		case 0xFB: // call is diverting
+			SendSSNotificationEvent(aplci, 0x8004);
+			break;
+		case 0xE8: // diversion activated
+			SendSSNotificationEvent(aplci, 0x8005);
+			break;
+		default:
+			int_errtxt("unhandled notification %x", nf[1]);
+	}
+}
+
+static void plci_hold_conf(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_PLCI_P_HELD);
+}
+
+static void
+AppPlci_hold_reply(AppPlci_t *aplci, __u16 SuppServiceReason)
+{
+	_cmsg	*cmsg;
+	__u8	tmp[10], *p;
+
+	if (aplci->appl) {
+		CMSG_ALLOC(cmsg);
+		AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND);
+		p = &tmp[1];
+		p += capiEncodeWord(p, 0x0002); // Hold
+		p += capiEncodeFacIndSuspend(p, SuppServiceReason);
+		tmp[0] = p - &tmp[1];
+		cmsg->FacilitySelector = 0x0003;
+		cmsg->FacilityIndicationParameter = tmp;
+		Send2Application(aplci, cmsg);
+	}
+	if (SuppServiceReason == CapiSuccess)
+		mISDN_FsmEvent(&aplci->plci_m, EV_PI_HOLD_CONF, NULL);
+}
+
+static void
+plci_cc_hold_rej(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t	*qi = arg;
+	u_char		*p;
+	__u16		SuppServiceReason;
+	
+	if (qi) { // reject from network
+		if (qi->cause.off) {
+			p = (u_char *)qi;
+			p += L3_EXTRA_SIZE + qi->cause.off;
+			SuppServiceReason = 0x3400 | p[3];
+		} else
+			SuppServiceReason = CapiProtocolErrorLayer3;
+	} else { // timeout
+		SuppServiceReason = CapiTimeOut;
+	}
+	AppPlci_hold_reply(aplci, SuppServiceReason);
+}
+
+static void
+plci_cc_hold_ack(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+
+	AppPlci_hold_reply(aplci, CapiSuccess);
+	AppPlciLinkDown(aplci);
+}
+
+static void
+plci_cc_hold_ind(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+
+	AppPlci_hold_reply(aplci, CapiSuccess);
+	AppPlciLinkDown(aplci);
+	plciL4L3(aplci->plci, CC_HOLD_ACKNOWLEDGE| REQUEST, NULL);
+}
+
+static void plci_retrieve_conf(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_PLCI_P_ACT);
+	AppPlciLinkUp(aplci);
+	if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state))
+		Send2Application(aplci, arg);
+	else
+		Send2ApplicationDelayed(aplci, arg);
+}
+
+static void
+AppPlci_retrieve_reply(AppPlci_t *aplci, __u16 SuppServiceReason)
+{
+	_cmsg	*cmsg;
+	__u8	tmp[10], *p;
+
+	if (aplci->appl) {
+		CMSG_ALLOC(cmsg);
+		AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND);
+		p = &tmp[1];
+		p += capiEncodeWord(p, 0x0003); // Retrieve
+		p += capiEncodeFacIndSuspend(p, SuppServiceReason);
+		tmp[0] = p - &tmp[1];
+		cmsg->FacilitySelector = 0x0003;
+		cmsg->FacilityIndicationParameter = tmp;
+
+		if (SuppServiceReason != CapiSuccess)
+			Send2Application(aplci, cmsg);
+		else 
+			if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_RETRIEVE_CONF, cmsg))
+				cmsg_free(cmsg);
+	}
+}
+
+static void
+plci_cc_retrieve_rej(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t	*qi = arg;
+	u_char		*p;
+	__u16		SuppServiceReason;
+	
+	if (qi) { // reject from network
+		if (qi->cause.off) {
+			p = (u_char *)qi;
+			p += L3_EXTRA_SIZE + qi->cause.off;
+			SuppServiceReason = 0x3400 | p[3];
+		} else
+			SuppServiceReason = CapiProtocolErrorLayer3;
+	} else { // timeout
+		SuppServiceReason = CapiTimeOut;
+	}
+	AppPlci_retrieve_reply(aplci, SuppServiceReason);
+}
+
+static void
+plci_cc_retrieve_ack(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t     *qi = arg;
+	u_char		*ie;
+
+	if (qi->channel_id.off) {
+		ie = (u_char *)qi;
+		ie += L3_EXTRA_SIZE + qi->channel_id.off;
+		aplci->channel = plci_parse_channel_id(ie);
+		AppPlci_retrieve_reply(aplci, CapiSuccess);
+	} else
+		AppPlci_retrieve_reply(aplci, 0x3711); /* resource Error */
+}
+
+static void
+plci_cc_retrieve_ind(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t     *qi = arg;
+	u_char		*ie;
+
+	if (qi->channel_id.off) {
+		ie = (u_char *)qi;
+		ie += L3_EXTRA_SIZE + qi->channel_id.off;
+		aplci->channel = plci_parse_channel_id(ie);
+		AppPlci_retrieve_reply(aplci, CapiSuccess);
+		plciL4L3(aplci->plci, CC_RETRIEVE_ACKNOWLEDGE | REQUEST, NULL);
+	} else {
+		AppPlci_retrieve_reply(aplci, 0x3711); /* resource Error */
+		plciL4L3(aplci->plci, CC_RETRIEVE_REJECT | REQUEST, NULL);
+	}
+}
+
+static void
+AppPlci_suspend_reply(AppPlci_t *aplci, __u16 SuppServiceReason)
+{
+	_cmsg	*cmsg;
+	__u8	tmp[10], *p;
+
+	if (aplci->appl) {
+		CMSG_ALLOC(cmsg);
+		AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND);
+		p = &tmp[1];
+		p += capiEncodeWord(p, 0x0004); // Suspend
+		p += capiEncodeFacIndSuspend(p, SuppServiceReason);
+		tmp[0] = p - &tmp[1];
+		cmsg->FacilitySelector = 0x0003;
+		cmsg->FacilityIndicationParameter = tmp;
+		Send2Application(aplci, cmsg);
+	}
+	if (SuppServiceReason == CapiSuccess)
+		mISDN_FsmEvent(&aplci->plci_m, EV_PI_SUSPEND_CONF, NULL);
+}
+
+static void
+plci_cc_suspend_err(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t	*qi = arg;
+	u_char		*p;
+	__u16		SuppServiceReason;
+	
+	if (qi) { // reject from network
+		if (qi->cause.off) {
+			p = (u_char *)qi;
+			p += L3_EXTRA_SIZE + qi->cause.off;
+			SuppServiceReason = 0x3400 | p[3];
+		} else
+			SuppServiceReason = CapiProtocolErrorLayer3;
+	} else { // timeout
+		SuppServiceReason = CapiTimeOut;
+	}
+	AppPlci_suspend_reply(aplci, SuppServiceReason);
+}
+
+static void
+plci_cc_suspend_conf(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	_cmsg		*cmsg;
+
+	AppPlciLinkDown(aplci);
+
+	AppPlci_suspend_reply(aplci, CapiSuccess);
+	
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND);
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+plci_cc_resume_err(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t	*qi = arg;
+	u_char		*p;
+	_cmsg		*cmsg;
+	
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND);
+	if (qi) { // reject from network
+		if (qi->cause.off) {
+			p = (u_char *)qi;
+			p += L3_EXTRA_SIZE + qi->cause.off;
+			cmsg->Reason = 0x3400 | p[3];
+		} else
+			cmsg->Reason = 0;
+	} else { // timeout
+		cmsg->Reason = CapiProtocolErrorLayer1;
+	}
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+plci_cc_resume_conf(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Q931_info_t	*qi = arg;
+	_cmsg		*cmsg;
+	__u8		tmp[10], *p;
+	
+	if (!qi || !qi->channel_id.off) {
+		int_error();
+		return;
+	}
+	p = (u_char *)qi;
+	p += L3_EXTRA_SIZE + qi->channel_id.off;
+	aplci->channel = plci_parse_channel_id(p);
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND);
+	p = &tmp[1];
+	p += capiEncodeWord(p, 0x0005); // Suspend
+	p += capiEncodeFacIndSuspend(p, CapiSuccess);
+	tmp[0] = p - &tmp[1];
+	cmsg->FacilitySelector = 0x0003;
+	cmsg->FacilityIndicationParameter = tmp;
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_RESUME_CONF, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+plci_select_b_protocol_req(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	_cmsg		*cmsg = arg;
+	__u16		Info;
+	int		ret;
+
+	Info = AppPlciCheckBprotocol(aplci, cmsg);
+	if (Info)
+		goto answer;
+
+	ret = AppPlciLinkDown(aplci);
+	if (ret) {
+		Info = CapiMessageNotSupportedInCurrentState;
+		goto answer;
+	}
+	ret = AppPlciLinkUp(aplci);
+	if (ret < 0)
+		Info = CapiMessageNotSupportedInCurrentState;
+	else
+		Info = ret;
+answer:
+	capi_cmsg_answer(cmsg);
+	cmsg->Info = Info;
+	if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state))
+		Send2Application(aplci, arg);
+	else
+		Send2ApplicationDelayed(aplci, arg);
+}
+
+static void
+plci_info_req_overlap(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	Plci_t		*plci = aplci->plci;
+	_cmsg		*cmsg = arg;
+	__u16		Info = 0;
+	struct sk_buff	*skb;
+
+	skb = mISDN_alloc_l3msg(100, MT_INFORMATION);
+	if (skb) {
+		Info = cmsg2info_req(cmsg, skb);
+		if (Info == CapiSuccess)
+			plciL4L3(plci, CC_INFORMATION | REQUEST, skb);
+		else
+			kfree_skb(skb);
+	}
+	capi_cmsg_answer(cmsg);
+	cmsg->Info = Info;
+	Send2Application(aplci, cmsg);
+}
+
+static void
+plci_cc_ph_control_ind(struct FsmInst *fi, int event, void *arg)
+{
+	AppPlci_t	*aplci = fi->userdata;
+	int		*tt = arg;
+	_cmsg		*cmsg;
+	__u8		tmp[2];
+
+	if (!arg)
+		return;
+	AppPlciDebug(aplci, CAPI_DBG_PLCI_INFO, "%s: tt(%x)", __FUNCTION__, *tt);
+	if ((*tt & ~DTMF_TONE_MASK) != DTMF_TONE_VAL)
+		return;
+
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND);
+	tmp[0] = 1;
+	tmp[1] = *tt & DTMF_TONE_MASK;
+	cmsg->FacilitySelector = 0x0001;
+	cmsg->FacilityIndicationParameter = tmp;
+	Send2Application(aplci, cmsg);
+}
+
+static void
+plci_info_req(struct FsmInst *fi, int event, void *arg)
+{
+	// FIXME handle INFO CONF
+	if (arg)
+		cmsg_free(arg);
+}
+
+static struct FsmNode fn_plci_list[] =
+{
+  {ST_PLCI_P_0,		EV_AP_CONNECT_REQ,		plci_connect_req},
+  {ST_PLCI_P_0,		EV_PI_CONNECT_IND,		plci_connect_ind},
+  {ST_PLCI_P_0,		EV_AP_RESUME_REQ,		plci_resume_req},
+  {ST_PLCI_P_0,		EV_L3_SETUP_IND,		plci_cc_setup_ind},
+  {ST_PLCI_P_0,		EV_AP_RELEASE,			plci_appl_release},
+
+  {ST_PLCI_P_0_1,	EV_PI_CONNECT_CONF,		plci_connect_conf},
+  {ST_PLCI_P_0_1,	EV_AP_RELEASE,			plci_appl_release},
+
+  {ST_PLCI_P_1,		EV_PI_CONNECT_ACTIVE_IND,	plci_connect_active_ind},
+  {ST_PLCI_P_1,		EV_AP_DISCONNECT_REQ,		plci_disconnect_req},
+  {ST_PLCI_P_1,		EV_PI_DISCONNECT_IND,		plci_disconnect_ind},
+  {ST_PLCI_P_1,		EV_AP_INFO_REQ,			plci_info_req_overlap},
+  {ST_PLCI_P_1,		EV_L3_SETUP_CONF,		plci_cc_setup_conf},
+  {ST_PLCI_P_1,		EV_L3_SETUP_CONF_ERR,		plci_cc_setup_conf_err},
+  {ST_PLCI_P_1,		EV_L3_DISCONNECT_IND,		plci_cc_disconnect_ind},
+  {ST_PLCI_P_1,		EV_L3_RELEASE_PROC_IND,		plci_cc_setup_conf_err},
+  {ST_PLCI_P_1,		EV_L3_RELEASE_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_1,		EV_L3_REJECT_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_1,		EV_PI_CHANNEL_ERR,		plci_channel_err},
+  {ST_PLCI_P_1,		EV_AP_RELEASE,			plci_appl_release_disc},
+
+  {ST_PLCI_P_2,		EV_AP_ALERT_REQ,		plci_alert_req},
+  {ST_PLCI_P_2,		EV_AP_CONNECT_RESP,		plci_connect_resp},
+  {ST_PLCI_P_2,		EV_AP_DISCONNECT_REQ,		plci_disconnect_req},
+  {ST_PLCI_P_2,		EV_PI_DISCONNECT_IND,		plci_disconnect_ind},
+  {ST_PLCI_P_2,		EV_L3_RELEASE_PROC_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_2,		EV_AP_INFO_REQ,			plci_info_req},
+  {ST_PLCI_P_2,		EV_L3_RELEASE_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_2,		EV_AP_RELEASE,			plci_appl_release_disc},
+
+  {ST_PLCI_P_4,		EV_PI_CONNECT_ACTIVE_IND,	plci_connect_active_ind},
+  {ST_PLCI_P_4,		EV_AP_DISCONNECT_REQ,		plci_disconnect_req},
+  {ST_PLCI_P_4,		EV_PI_DISCONNECT_IND,		plci_disconnect_ind},
+  {ST_PLCI_P_4,		EV_AP_INFO_REQ,			plci_info_req},
+  {ST_PLCI_P_4,		EV_L3_SETUP_COMPL_IND,		plci_cc_setup_compl_ind},
+  {ST_PLCI_P_4,		EV_L3_RELEASE_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_4,		EV_L3_RELEASE_PROC_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_4,		EV_PI_CHANNEL_ERR,		plci_channel_err},
+  {ST_PLCI_P_4,		EV_AP_RELEASE,			plci_appl_release_disc},
+
+  {ST_PLCI_P_ACT,	EV_AP_CONNECT_ACTIVE_RESP,	plci_connect_active_resp},
+  {ST_PLCI_P_ACT,	EV_AP_DISCONNECT_REQ,		plci_disconnect_req},
+  {ST_PLCI_P_ACT,	EV_PI_DISCONNECT_IND,		plci_disconnect_ind},
+  {ST_PLCI_P_ACT,	EV_AP_INFO_REQ,			plci_info_req},
+  {ST_PLCI_P_ACT,	EV_AP_SELECT_B_PROTOCOL_REQ,	plci_select_b_protocol_req},
+  {ST_PLCI_P_ACT,	EV_AP_HOLD_REQ,			plci_hold_req},
+  {ST_PLCI_P_ACT,	EV_AP_SUSPEND_REQ,		plci_suspend_req},
+  {ST_PLCI_P_ACT,	EV_PI_SUSPEND_CONF,		plci_suspend_conf},
+  {ST_PLCI_P_ACT,	EV_L3_DISCONNECT_IND,		plci_cc_disconnect_ind},
+  {ST_PLCI_P_ACT,	EV_L3_RELEASE_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_ACT,	EV_L3_RELEASE_PROC_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_ACT,	EV_L3_NOTIFY_IND,		plci_cc_notify_ind},
+  {ST_PLCI_P_ACT,	EV_L3_HOLD_IND,			plci_cc_hold_ind},
+  {ST_PLCI_P_ACT,	EV_L3_HOLD_ACKNOWLEDGE,		plci_cc_hold_ack},
+  {ST_PLCI_P_ACT,	EV_L3_HOLD_REJECT,		plci_cc_hold_rej},
+  {ST_PLCI_P_ACT,	EV_PI_HOLD_CONF,		plci_hold_conf},
+  {ST_PLCI_P_ACT,	EV_L3_SUSPEND_ERR,		plci_cc_suspend_err},
+  {ST_PLCI_P_ACT,	EV_L3_SUSPEND_CONF,		plci_cc_suspend_conf},
+  {ST_PLCI_P_ACT,	EV_PH_CONTROL_IND,		plci_cc_ph_control_ind},
+  {ST_PLCI_P_ACT,	EV_AP_RELEASE,			plci_appl_release_disc},
+
+  {ST_PLCI_P_HELD,	EV_AP_RETRIEVE_REQ,		plci_retrieve_req},
+  {ST_PLCI_P_HELD,	EV_L3_RETRIEVE_ACKNOWLEDGE,	plci_cc_retrieve_ack},
+  {ST_PLCI_P_HELD,	EV_L3_RETRIEVE_REJECT,		plci_cc_retrieve_rej},
+  {ST_PLCI_P_HELD,	EV_PI_RETRIEVE_CONF,		plci_retrieve_conf},
+  {ST_PLCI_P_HELD,	EV_AP_DISCONNECT_REQ,		plci_disconnect_req},
+  {ST_PLCI_P_HELD,	EV_AP_INFO_REQ,			plci_info_req},
+  {ST_PLCI_P_HELD,	EV_L3_RETRIEVE_IND,		plci_cc_retrieve_ind},
+  {ST_PLCI_P_HELD,	EV_L3_DISCONNECT_IND,		plci_cc_disconnect_ind},
+  {ST_PLCI_P_HELD,	EV_L3_RELEASE_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_HELD,	EV_L3_RELEASE_PROC_IND,		plci_cc_release_ind},  
+  {ST_PLCI_P_HELD,	EV_L3_NOTIFY_IND,		plci_cc_notify_ind},
+  {ST_PLCI_P_HELD,	EV_PI_DISCONNECT_IND,		plci_disconnect_ind},
+  {ST_PLCI_P_HELD,	EV_AP_RELEASE,			plci_appl_release_disc},
+
+  {ST_PLCI_P_5,		EV_PI_DISCONNECT_IND,		plci_disconnect_ind},
+  {ST_PLCI_P_5,		EV_L3_RELEASE_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_5,		EV_L3_RELEASE_PROC_IND,		plci_cc_release_ind},
+  {ST_PLCI_P_5,		EV_AP_RELEASE,			plci_appl_release},
+
+  {ST_PLCI_P_6,		EV_AP_DISCONNECT_RESP,		plci_disconnect_resp},
+  {ST_PLCI_P_6,		EV_AP_RELEASE,			plci_disconnect_resp},
+
+  {ST_PLCI_P_RES,	EV_PI_RESUME_CONF,		plci_resume_conf},
+  {ST_PLCI_P_RES,	EV_PI_DISCONNECT_IND,		plci_disconnect_ind},
+  {ST_PLCI_P_RES,	EV_L3_RESUME_ERR,		plci_cc_resume_err},
+  {ST_PLCI_P_RES,	EV_L3_RESUME_CONF,		plci_cc_resume_conf},
+  {ST_PLCI_P_RES,	EV_AP_RELEASE,			plci_appl_release_disc},
+};
+
+const int FN_PLCI_COUNT = sizeof(fn_plci_list)/sizeof(struct FsmNode);
+
+int
+AppPlciConstr(AppPlci_t **aplci, Application_t *appl, Plci_t *plci)
+{
+	AppPlci_t	*apl = AppPlci_alloc();	
+
+	if (!apl)
+		return(-ENOMEM);
+	memset(apl, 0, sizeof(AppPlci_t));
+	INIT_LIST_HEAD(&apl->head);
+	INIT_LIST_HEAD(&apl->Nccis);
+	apl->addr = plci->addr;
+	apl->appl = appl;
+	apl->plci = plci;
+	apl->contr = plci->contr;
+	apl->plci_m.fsm        = &plci_fsm;
+	apl->plci_m.state      = ST_PLCI_P_0;
+	apl->plci_m.debug      = plci->contr->debug & CAPI_DBG_PLCI_STATE;
+	apl->plci_m.userdata   = apl;
+	apl->plci_m.printdebug = AppPlci_debug;
+	apl->channel = -1;
+	skb_queue_head_init(&apl->delayedq);
+	*aplci = apl;
+	return(0);
+}
+
+void AppPlciDestr(AppPlci_t *aplci)
+{
+	struct list_head	*item, *next;
+	
+	if (aplci->plci) {
+		AppPlciDebug(aplci, CAPI_DBG_PLCI, "%s plci state %s", __FUNCTION__,
+			str_st_plci[aplci->plci_m.state]);
+		if (aplci->plci_m.state != ST_PLCI_P_0) {
+			struct sk_buff	*skb = mISDN_alloc_l3msg(10, MT_RELEASE_COMPLETE);
+			unsigned char cause[] = {2,0x80,0x80| CAUSE_RESOURCES_UNAVAIL};
+
+			if (skb) {
+				mISDN_AddIE(skb, IE_CAUSE, cause);
+				plciL4L3(aplci->plci, CC_RELEASE_COMPLETE | REQUEST, skb);
+			}
+		}
+ 		plciDetachAppPlci(aplci->plci, aplci);
+	}
+	list_for_each_safe(item, next, &aplci->Nccis) {
+		ncciDelAppPlci((Ncci_t *)item);
+	}
+	if (aplci->appl)
+		ApplicationDelAppPlci(aplci->appl, aplci);
+	skb_queue_purge(&aplci->delayedq);
+	AppPlci_free(aplci);
+}
+
+void
+AppPlciRelease(AppPlci_t *aplci)
+{
+	struct list_head	*item, *next;
+
+	list_for_each_safe(item, next, &aplci->Nccis) {
+		ncciApplRelease((Ncci_t *)item);
+	}
+	mISDN_FsmEvent(&aplci->plci_m, EV_AP_RELEASE, NULL);
+}
+
+static __inline__ Ncci_t *
+get_single_NCCI(AppPlci_t *aplci)
+{
+	struct list_head	*item = aplci->Nccis.next;
+
+	if (item == &aplci->Nccis)
+		return(NULL);
+	if (item->next != &aplci->Nccis)
+		return(NULL);	// more as one NCCI
+	return((Ncci_t *)item);	
+}
+
+static int
+PL_l3l4(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	AppPlci_t		*aplci;
+	Ncci_t 			*ncci;
+	mISDN_head_t		*hh;
+
+	hh = mISDN_HEAD_P(skb);
+	aplci = inst->privat;
+	if (!aplci)
+		return(-EINVAL);
+	ncci = get_single_NCCI(aplci);
+	capidebug(CAPI_DBG_NCCI_L3, "%s: prim(%x) dinfo (%x) skb(%p) APLCI(%x) ncci(%p)",
+		__FUNCTION__, hh->prim, hh->dinfo, skb, aplci->addr, ncci);
+	if (hh->prim == CAPI_MESSAGE_REQUEST) {
+		if (!ncci) {
+			int_error();
+			return(-EINVAL);
+		}
+		ncciSendMessage(ncci, skb);
+		return(0);
+	}
+	if (!ncci) {
+		if ((hh->prim != (DL_ESTABLISH | INDICATION)) && (hh->prim != (DL_ESTABLISH | CONFIRM))) {
+			int_error();
+			return(-ENODEV);
+		}
+		ncci = ncciConstr(aplci);
+		if (!ncci) {
+			int_error();
+			return(-ENOMEM);
+		}
+	}
+	return(ncci_l3l4(ncci, hh, skb));
+}
+
+static int
+PL_l3l4mux(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	AppPlci_t	*aplci;
+	Ncci_t 		*ncci;
+	mISDN_head_t	*hh;
+	__u32		addr;
+
+	hh = mISDN_HEAD_P(skb);
+	aplci = inst->privat;
+	if (!aplci)
+		return(-EINVAL);
+	
+	capidebug(CAPI_DBG_NCCI_L3, "%s: prim(%x) dinfo (%x) skb->len(%d)",
+		__FUNCTION__, hh->prim, hh->dinfo, skb->len);
+	if (skb->len < 4) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (hh->prim == CAPI_MESSAGE_REQUEST) {
+		ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_EXACT);
+		if (!ncci) {
+			int_error();
+			return(-EINVAL);
+		}
+		ncciSendMessage(ncci, skb);
+		return(0);
+	}
+	addr = CAPIMSG_U32(skb->data, 0);
+	ncci = getNCCI4addr(aplci, addr, GET_NCCI_ONLY_PLCI);
+	if (hh->prim == CAPI_CONNECT_B3_IND) {
+		if (ncci) {
+			int_error();
+			return(-EBUSY);
+		}
+		ncci = ncciConstr(aplci);
+		if (!ncci) {
+			int_error();
+			return(-ENOMEM);
+		}
+		addr &= 0xffff0000;
+		addr |= aplci->addr;
+		ncci->addr = addr;
+		capimsg_setu32(skb->data, 0, addr);
+#ifdef OLDCAPI_DRIVER_INTERFACE
+		ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, addr, ncci->window);
+#endif
+	} else if (hh->prim == CAPI_CONNECT_B3_CONF) {
+		if (ncci && ((addr & 0xffff0000) != 0)) {
+			if (ncci->addr != addr) {
+				ncci->addr = addr;
+#ifdef OLDCAPI_DRIVER_INTERFACE
+				ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, addr, ncci->window);
+#endif
+			} else
+				int_error();
+		}
+	}
+	if (!ncci) {
+		int_error();
+		return(-ENODEV);
+	}
+	return(ncci_l3l4_direct(ncci, hh, skb));
+}
+
+static int
+AppPlciLinkUp(AppPlci_t *aplci)
+{
+	mISDN_pid_t	pid;
+	mISDN_stPara_t	stpara;
+	int		retval;
+
+	if (aplci->channel == -1) {/* no valid channel set */
+		int_error();
+		return -EINVAL;
+	}
+	memset(&pid, 0, sizeof(mISDN_pid_t));
+	pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2) | ISDN_LAYER(3) |
+		ISDN_LAYER(4);
+	if (test_bit(PLCI_STATE_OUTGOING, &aplci->plci->state))
+		pid.global = 1; // DTE, orginate
+	else
+		pid.global = 2; // DCE, answer
+	if (aplci->Bprotocol.B1 > 23) {
+		int_errtxt("wrong B1 prot %x", aplci->Bprotocol.B1);
+		return 0x3001;
+	}
+	pid.protocol[1] = (1 << aplci->Bprotocol.B1) |
+		ISDN_PID_LAYER(1) | ISDN_PID_BCHANNEL_BIT;
+	retval = mISDN_add_pid_parameter(&pid, 1, &aplci->Bprotocol.B1cfg[0]);
+	if (retval) {/* ressource error */
+		kfree(pid.pbuf);
+		return 0x1008;
+	}
+
+	if (aplci->Bprotocol.B2 > 23) {
+		int_errtxt("wrong B2 prot %x", aplci->Bprotocol.B2);
+		kfree(pid.pbuf);
+		return 0x3002;
+	}
+	pid.protocol[2] = (1 << aplci->Bprotocol.B2) |
+		ISDN_PID_LAYER(2) | ISDN_PID_BCHANNEL_BIT;
+	retval = mISDN_add_pid_parameter(&pid, 2, &aplci->Bprotocol.B2cfg[0]);
+	if (retval) {/* ressource error */
+		kfree(pid.pbuf);
+		return 0x1008;
+	}
+
+	/* handle DTMF TODO */
+	if ((pid.protocol[2] == ISDN_PID_L2_B_TRANS) &&
+		(pid.protocol[1] == ISDN_PID_L1_B_64TRANS))
+		pid.protocol[2] = ISDN_PID_L2_B_TRANSDTMF;
+	if (aplci->Bprotocol.B3 > 23) {
+		int_errtxt("wrong B3 prot %x", aplci->Bprotocol.B3);
+		kfree(pid.pbuf);
+		return 0x3003;
+	}
+	pid.protocol[3] = (1 << aplci->Bprotocol.B3) |
+		ISDN_PID_LAYER(3) | ISDN_PID_BCHANNEL_BIT;
+	retval = mISDN_add_pid_parameter(&pid, 3, &aplci->Bprotocol.B3cfg[0]);
+	if (retval) {/* ressource error */
+		kfree(pid.pbuf);
+		return 0x1008;
+	}
+
+	capidebug(CAPI_DBG_PLCI, "AppPlciLinkUp B1(%x) B2(%x) B3(%x) global(%d) ch(%x)",
+		pid.protocol[1], pid.protocol[2], pid.protocol[3], pid.global, 
+		aplci->channel);
+	capidebug(CAPI_DBG_PLCI, "AppPlciLinkUp B1cfg(%d) B2cfg(%d) B3cfg(%d) maxplen(%d)",
+		aplci->Bprotocol.B1cfg[0], aplci->Bprotocol.B2cfg[0],
+		aplci->Bprotocol.B3cfg[0], pid.maxplen);
+	capidebug(CAPI_DBG_PLCI, "AppPlciLinkUp ch(%d) aplci->contr->linklist(%p)",
+		aplci->channel & 3, aplci->contr->linklist);
+	pid.protocol[4] = ISDN_PID_L4_B_CAPI20;
+	aplci->link = ControllerSelChannel(aplci->contr, aplci->channel);
+	if (!aplci->link) {
+		int_error();
+		kfree(pid.pbuf);
+		return(-EBUSY);
+	}
+	capidebug(CAPI_DBG_NCCI, "AppPlciLinkUp aplci->link(%p)", aplci->link);
+	memset(&aplci->link->inst.pid, 0, sizeof(mISDN_pid_t));
+	aplci->link->inst.privat = aplci;
+	aplci->link->inst.pid.layermask = ISDN_LAYER(4);
+	aplci->link->inst.pid.protocol[4] = ISDN_PID_L4_B_CAPI20;
+	if (pid.protocol[3] == ISDN_PID_L3_B_TRANS) {
+		aplci->link->inst.pid.protocol[3] = ISDN_PID_L3_B_TRANS;
+		aplci->link->inst.pid.layermask |= ISDN_LAYER(3);
+	}
+	if (aplci->link->inst.function)
+		int_errtxt("id(%08x) overwrite function (%p)", aplci->link->inst.id, aplci->link->inst.function);
+	if (aplci->Bprotocol.B3 == 0) // transparent
+		aplci->link->inst.function = PL_l3l4;
+	else
+		aplci->link->inst.function = PL_l3l4mux;
+	retval = mISDN_ctrl(aplci->link->st, MGR_ADDLAYER | REQUEST, &aplci->link->inst); 
+	if (retval) {
+		printk(KERN_WARNING "%s MGR_ADDLAYER | REQUEST ret(%d)\n",
+			__FUNCTION__, retval);
+		return(retval);
+	}
+	stpara.maxdatalen = aplci->appl->reg_params.datablklen;
+	stpara.up_headerlen = CAPI_B3_DATA_IND_HEADER_SIZE;
+	stpara.down_headerlen = 0;
+                        
+	retval = mISDN_ctrl(aplci->link->st, MGR_ADDSTPARA | REQUEST, &stpara);
+	if (retval) {
+		printk(KERN_WARNING "%s MGR_SETSTACK | REQUEST ret(%d)\n",
+			__FUNCTION__, retval);
+	}
+	retval = mISDN_ctrl(aplci->link->st, MGR_SETSTACK | REQUEST, &pid);
+	kfree(pid.pbuf);
+	if (retval) {
+		printk(KERN_WARNING "%s MGR_SETSTACK | REQUEST ret(%d)\n",
+			__FUNCTION__, retval);
+		return(retval);
+	}
+	return(0);
+}
+
+static int
+ReleaseLink(AppPlci_t *aplci)
+{
+	int retval = 0;
+
+	if (aplci->link) {
+#if 0
+		if (ncci->ncci_m.state != ST_NCCI_N_0)
+			ncciL4L3(ncci, DL_RELEASE | REQUEST, 0, 0, NULL, NULL);
+#endif
+		retval = mISDN_ctrl(aplci->link->inst.st, MGR_CLEARSTACK | REQUEST, NULL);
+		if (retval)
+			int_error();
+		aplci->link = NULL;
+		skb_queue_purge(&aplci->delayedq);
+		test_and_clear_bit(PLCI_STATE_STACKREADY, &aplci->plci->state);
+	}
+	return(retval);
+}
+
+Ncci_t	*
+getNCCI4addr(AppPlci_t *aplci, __u32 addr, int mode)
+{
+	Ncci_t			*ncci = NULL;
+	struct list_head	*item;
+	int			cnt = 0;
+
+	list_for_each(item, &aplci->Nccis) {
+		cnt++;
+		ncci = (Ncci_t *)item;
+		if (ncci->addr == addr)
+			return(ncci);
+		if (mode == GET_NCCI_ONLY_PLCI) {
+			if (ncci->addr == (addr & 0xffff))
+				return(ncci);
+		}
+	}
+	if (!cnt)
+		return(NULL);
+	if (mode != GET_NCCI_PLCI)
+		return(NULL);
+	if (1 == cnt) {
+		if (!(addr & 0xffff0000))
+			return(ncci);
+	}
+	return(NULL);
+}
+
+void
+AppPlciDelNCCI(Ncci_t *ncci) {
+	list_del_init(&ncci->head);
+}
+
+int
+AppPlcimISDN_Active(AppPlci_t *aplci)
+{
+	if (!aplci) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (!test_and_set_bit(PLCI_STATE_SENDDELAYED, &aplci->plci->state)) {
+		test_and_set_bit(PLCI_STATE_STACKREADY, &aplci->plci->state);
+		SendingDelayedMsg(aplci);
+	} else
+		test_and_set_bit(PLCI_STATE_STACKREADY, &aplci->plci->state);
+	return(0);
+}
+
+void
+AppPlci_l3l4(AppPlci_t *aplci, int pr, void *arg)
+{
+	Q931_info_t	*qi = arg;
+	u_char		*ie;
+
+	AppPlciDebug(aplci, CAPI_DBG_PLCI_L3, "%s: aplci(%x) pr(%x) arg(%p)",
+		__FUNCTION__, aplci->addr, pr, arg);
+	switch (pr) {
+		case CC_SETUP | INDICATION:
+			if (!qi)
+				return;
+			if (qi->channel_id.off) {
+				ie = (u_char *)qi;
+				ie += L3_EXTRA_SIZE + qi->channel_id.off;
+				aplci->channel = plci_parse_channel_id(ie);
+			}
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_IND, arg);
+			if (qi) {
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
+				AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi);
+				AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
+				AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
+				AppPlciInfoIndIE(aplci, IE_CALLED_PN, CAPI_INFOMASK_CALLEDPN, qi);
+				AppPlciInfoIndIE(aplci, IE_COMPLETE, CAPI_INFOMASK_COMPLETE, qi);
+			}
+			break;
+		case CC_TIMEOUT | INDICATION:
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_CONF_ERR, arg); 
+			break;
+		case CC_CONNECT | INDICATION:
+			if (qi) {	
+				AppPlciInfoIndIE(aplci, IE_DATE, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
+				AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi);
+				AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
+				AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
+				if (qi->channel_id.off) {
+					ie = (u_char *)qi;
+					ie += L3_EXTRA_SIZE + qi->channel_id.off;
+					aplci->channel = plci_parse_channel_id(ie);
+				}
+			}
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_CONF, arg); 
+			break;
+		case CC_CONNECT_ACKNOWLEDGE | INDICATION:
+			if (qi) {
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
+				if (qi->channel_id.off) {
+					ie = (u_char *)qi;
+					ie += L3_EXTRA_SIZE + qi->channel_id.off;
+					aplci->channel = plci_parse_channel_id(ie);
+				}
+			}
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_COMPL_IND, arg); 
+			break;
+		case CC_DISCONNECT | INDICATION:
+			if (qi) {
+				AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_EARLYB3, MT_DISCONNECT);
+				AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
+				AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi);
+				AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
+			}
+		  	mISDN_FsmEvent(&aplci->plci_m, EV_L3_DISCONNECT_IND, arg); 
+			break;
+		case CC_RELEASE | INDICATION:
+			if (qi) {
+				AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
+				AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
+			}
+		        mISDN_FsmEvent(&aplci->plci_m, EV_L3_RELEASE_IND, arg); 
+			break;
+		case CC_RELEASE_COMPLETE | INDICATION:
+			if (qi) {
+				AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
+				AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
+			}
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_RELEASE_IND, arg);
+			break;
+		case CC_RELEASE_CR | INDICATION:
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_RELEASE_PROC_IND, arg); 
+			break;
+		case CC_SETUP_ACKNOWLEDGE | INDICATION:
+			if (qi) {
+				AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_SETUP_ACKNOWLEDGE);
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_PROGRESS,
+					CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi);
+				AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
+				if (qi->channel_id.off) {
+					ie = (u_char *)qi;
+					ie += L3_EXTRA_SIZE + qi->channel_id.off;
+					aplci->channel = plci_parse_channel_id(ie);
+				}
+			}
+			break;
+		case CC_PROCEEDING | INDICATION:
+			if (qi) {
+				AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_CALL_PROCEEDING);
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_PROGRESS,
+					CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi);
+				AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
+				if (qi->channel_id.off) {
+					ie = (u_char *)qi;
+					ie += L3_EXTRA_SIZE + qi->channel_id.off;
+					aplci->channel = plci_parse_channel_id(ie);
+				}
+			}
+			break;
+		case CC_ALERTING | INDICATION:
+			if (qi) {
+				AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_ALERTING);
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
+				AppPlciInfoIndIE(aplci, IE_PROGRESS,
+					CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi);
+				AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
+				AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
+				if (qi->channel_id.off) {
+					ie = (u_char *)qi;
+					ie += L3_EXTRA_SIZE + qi->channel_id.off;
+					aplci->channel = plci_parse_channel_id(ie);
+				}
+			}
+			break;
+		case CC_PROGRESS | INDICATION:
+			if (qi) {
+				AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_PROGRESS);
+				AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
+				AppPlciInfoIndIE(aplci, IE_PROGRESS,
+					CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi);
+			}
+			break;
+		case CC_HOLD | INDICATION:
+			if (qi)
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+			if (mISDN_FsmEvent(&aplci->plci_m, EV_L3_HOLD_IND, arg)) {
+				/* no routine reject L3 */
+				plciL4L3(aplci->plci, CC_HOLD_REJECT | REQUEST, NULL);
+			}
+			break;
+		case CC_HOLD_ACKNOWLEDGE | INDICATION:
+			if (qi)
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_HOLD_ACKNOWLEDGE, arg);
+			break;
+		case CC_HOLD_REJECT | INDICATION:
+			if (qi) {
+				AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+			}
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_HOLD_REJECT, arg);
+			break;
+		case CC_RETRIEVE | INDICATION:
+			if (qi) {
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
+			}
+			if (mISDN_FsmEvent(&aplci->plci_m, EV_L3_RETRIEVE_IND, arg)) {
+				/* no routine reject L3 */
+				plciL4L3(aplci->plci, CC_RETRIEVE_REJECT | REQUEST, NULL);
+			}
+			break;
+		case CC_RETRIEVE_ACKNOWLEDGE | INDICATION:
+			if (qi) {
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+				AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
+			}
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_RETRIEVE_ACKNOWLEDGE, arg);
+			break;
+		case CC_RETRIEVE_REJECT | INDICATION:
+			if (qi) {
+				AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
+				AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
+			}
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_RETRIEVE_REJECT, arg);
+			break;
+		case CC_SUSPEND_ACKNOWLEDGE | INDICATION:
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_SUSPEND_CONF, arg); 
+			break;
+		case CC_SUSPEND_REJECT | INDICATION:
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_SUSPEND_ERR, arg); 
+			break;
+		case CC_RESUME_ACKNOWLEDGE | INDICATION:
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_RESUME_CONF, arg); 
+			break;
+		case CC_RESUME_REJECT | INDICATION:
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_RESUME_ERR, arg); 
+			break;
+		case CC_NOTIFY | INDICATION:
+			mISDN_FsmEvent(&aplci->plci_m, EV_L3_NOTIFY_IND, arg); 
+			break;
+		case PH_CONTROL | INDICATION:
+			/* TOUCH TONE */
+			mISDN_FsmEvent(&aplci->plci_m, EV_PH_CONTROL_IND, arg);
+			break;
+		default:
+			AppPlciDebug(aplci, CAPI_DBG_WARN, 
+			   "%s: pr 0x%x not handled", __FUNCTION__, pr);
+			break;
+	}
+}
+
+void
+AppPlciGetCmsg(AppPlci_t *aplci, _cmsg *cmsg)
+{
+	int	retval = 0;
+
+	switch (CMSGCMD(cmsg)) {
+		case CAPI_INFO_REQ:
+			retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_INFO_REQ, cmsg);
+			break;
+		case CAPI_ALERT_REQ:
+			retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_ALERT_REQ, cmsg);
+			break;
+		case CAPI_CONNECT_REQ:
+			retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_CONNECT_REQ, cmsg);
+			break;
+		case CAPI_CONNECT_RESP:
+			retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_CONNECT_RESP, cmsg);
+			break;
+		case CAPI_DISCONNECT_REQ:
+			retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_DISCONNECT_REQ, cmsg);
+			break;
+		case CAPI_DISCONNECT_RESP:
+			retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_DISCONNECT_RESP, cmsg);
+			break;
+		case CAPI_CONNECT_ACTIVE_RESP:
+			retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_CONNECT_ACTIVE_RESP, cmsg);
+			break;
+		case CAPI_SELECT_B_PROTOCOL_REQ:
+			retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_SELECT_B_PROTOCOL_REQ, cmsg);
+			break;
+		default:
+			int_error();
+			retval = -1;
+	}
+	if (retval) { 
+		if (cmsg->Command == CAPI_REQ) {
+			capi_cmsg_answer(cmsg);
+			cmsg->Info = CapiMessageNotSupportedInCurrentState;
+			Send2Application(aplci, cmsg);
+		} else
+			cmsg_free(cmsg);
+	}
+}
+
+__u16
+AppPlciSendMessage(AppPlci_t *aplci, struct sk_buff *skb)
+{
+	_cmsg	*cmsg;
+	__u16	ret;
+
+	cmsg = cmsg_alloc();
+	if (!cmsg) {
+		int_error();
+		ret = CAPI_REGOSRESOURCEERR;
+	} else {
+		capi_message2cmsg(cmsg, skb->data);
+		AppPlciGetCmsg(aplci, cmsg);
+		dev_kfree_skb(skb);
+		ret = CAPI_NOERROR;
+	}
+	return(ret);
+}
+
+void
+ConnectB3Request(AppPlci_t *aplci, struct sk_buff *skb)
+{
+	Ncci_t	*ncci = ncciConstr(aplci);
+	int	err;
+
+	if (!ncci) {
+		int_error();
+		dev_kfree_skb(skb);
+		return;
+	}
+	if (!ncci->link) {
+		int_error();
+		dev_kfree_skb(skb);
+		return;
+	}
+	err = mISDN_queue_message(&ncci->link->inst, 0, skb);
+	if (err) {
+		int_errtxt("mISDN_queue_message return(%d)", err);
+		dev_kfree_skb(skb);
+	}
+}
+
+void
+DisconnectB3Request(AppPlci_t *aplci, struct sk_buff *skb)
+{
+	Ncci_t	*ncci;
+	int	err;
+
+	ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_EXACT);
+	if ((!ncci) || (!ncci->link)) {
+		int_error();
+		if (aplci->appl)
+			AnswerMessage2Application(aplci->appl, skb, CapiIllContrPlciNcci);
+		dev_kfree_skb(skb);
+		return;
+	}
+	if (ncci->link->inst.id == 0) {
+		/* stack is already cleared and so we cannot handle this via the stack */
+		ncciSendMessage(ncci, skb);
+		return;
+	}
+	err = mISDN_queue_message(&ncci->link->inst, 0, skb);
+	if (err) {
+		int_errtxt("mISDN_queue_message return(%d)", err);
+		dev_kfree_skb(skb);
+	}
+}
+
+static int
+AppPlciLinkDown(AppPlci_t *aplci)
+{
+	struct list_head	*item, *next;
+
+	list_for_each_safe(item, next, &aplci->Nccis) {
+		ncciReleaseLink((Ncci_t *)item);
+	}
+	ReleaseLink(aplci);
+	return(0);
+}
+
+int
+AppPlciFacHoldReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	struct sk_buff	*skb;
+
+	skb = mISDN_alloc_l3msg(20, MT_HOLD);
+	if (!skb) {
+		int_error();
+		return CapiIllMessageParmCoding;
+	}
+
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_HOLD_REQ, skb)) {
+		// no routine
+		facConfParm->u.Info.SupplementaryServiceInfo = 
+			CapiRequestNotAllowedInThisState;
+		dev_kfree_skb(skb);
+		return CapiMessageNotSupportedInCurrentState;
+	} else {
+		facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
+	}
+	return CapiSuccess;
+}
+
+int
+AppPlciFacRetrieveReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	struct sk_buff	*skb;
+
+	skb = mISDN_alloc_l3msg(20, MT_RETRIEVE);
+	if (!skb) {
+		int_error();
+		return CapiIllMessageParmCoding;
+	}
+
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_RETRIEVE_REQ, skb)) {
+		// no routine
+		facConfParm->u.Info.SupplementaryServiceInfo = 
+			CapiRequestNotAllowedInThisState;
+		dev_kfree_skb(skb);
+		return CapiMessageNotSupportedInCurrentState;
+	} else {
+		facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
+	}
+	return CapiSuccess;
+}
+
+int
+AppPlciFacSuspendReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	__u8		*CallIdentity;
+	struct sk_buff	*skb;
+
+	CallIdentity = facReqParm->u.Suspend.CallIdentity;
+	if (CallIdentity && CallIdentity[0] > 8) 
+		return CapiIllMessageParmCoding;
+	skb = mISDN_alloc_l3msg(20, MT_SUSPEND);
+	if (!skb) {
+		int_error();
+		return CapiIllMessageParmCoding;
+	}
+	if (CallIdentity && CallIdentity[0])
+		mISDN_AddIE(skb, IE_CALL_ID, CallIdentity);
+
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_SUSPEND_REQ, skb)) {
+		// no routine
+		facConfParm->u.Info.SupplementaryServiceInfo = 
+			CapiRequestNotAllowedInThisState;
+		dev_kfree_skb(skb);
+		return CapiMessageNotSupportedInCurrentState;
+	} else {
+		facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
+	}
+	return CapiSuccess;
+}
+
+int
+AppPlciFacResumeReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	__u8		*CallIdentity;
+	struct sk_buff	*skb;
+
+	CallIdentity = facReqParm->u.Resume.CallIdentity;
+	if (CallIdentity && CallIdentity[0] > 8) {
+		AppPlciDestr(aplci);
+		return CapiIllMessageParmCoding;
+	}
+	skb = mISDN_alloc_l3msg(20, MT_RESUME);
+	if (!skb) {
+		int_error();
+		AppPlciDestr(aplci);
+		return CapiIllMessageParmCoding;
+	}
+	if (CallIdentity && CallIdentity[0])
+		mISDN_AddIE(skb, IE_CALL_ID, CallIdentity);
+	if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_RESUME_REQ, skb))
+		dev_kfree_skb(skb);
+
+	facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
+	return CapiSuccess;
+}
+
+static void
+AppPlciClearOtherApps(AppPlci_t *aplci)
+{
+	AppPlci_t		*o_aplci;
+	_cmsg			*cm;
+	struct list_head	*item, *next;
+
+	if (!aplci->plci)
+		return;
+	if (aplci->plci->nAppl <= 1)
+		return;
+	list_for_each_safe(item, next, &aplci->plci->AppPlcis) {
+		o_aplci = (AppPlci_t *)item;
+		if (o_aplci != aplci) {
+			CMSG_ALLOC(cm);
+			AppPlciCmsgHeader(o_aplci, cm, CAPI_DISCONNECT, CAPI_IND);
+			cm->Reason = 0x3304; // other application got the call
+			mISDN_FsmEvent(&o_aplci->plci_m, EV_PI_DISCONNECT_IND, cm);
+		}
+	} 
+}
+
+static void
+AppPlciInfoIndMsg(AppPlci_t *aplci,  __u32 mask, unsigned char mt)
+{
+	_cmsg	*cmsg;
+
+	if ((!aplci->appl) || (!(aplci->appl->InfoMask & mask)))
+		return;
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_INFO, CAPI_IND);
+	cmsg->InfoNumber = 0x8000 | mt;
+	cmsg->InfoElement = 0;
+	Send2Application(aplci, cmsg);
+}
+
+static void
+AppPlciInfoIndIE(AppPlci_t *aplci, unsigned char ie, __u32 mask, Q931_info_t *qi)
+{
+	_cmsg		*cmsg;
+	u_char		*iep = NULL;
+	ie_info_t	*ies;
+	
+
+	if ((!aplci->appl) || (!(aplci->appl->InfoMask & mask)))
+		return;
+	if (!qi)
+		return;
+	ies = &qi->bearer_capability;
+	if (ie & 0x80) { /* single octett */
+		if (ie == IE_COMPLETE) {
+			if (!qi->sending_complete.off)
+				return;
+		 } else {
+		 	int_error();
+		 	return;
+		}
+	} else {
+		if (mISDN_l3_ie2pos(ie) < 0)
+			return;
+		ies += mISDN_l3_ie2pos(ie);
+		if (!ies->off)
+			return;
+		iep = (u_char *)qi;
+		iep += L3_EXTRA_SIZE + ies->off +1;
+	}
+	CMSG_ALLOC(cmsg);
+	AppPlciCmsgHeader(aplci, cmsg, CAPI_INFO, CAPI_IND);
+	cmsg->InfoNumber = ie;
+	cmsg->InfoElement = iep;
+	if (ie == IE_PROGRESS && aplci->appl->InfoMask & CAPI_INFOMASK_EARLYB3) {
+		if (iep[0] == 0x02 && iep[2] == 0x88) { // in-band information available
+			AppPlciLinkUp(aplci);
+			if (!test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state)) {
+				Send2ApplicationDelayed(aplci,cmsg);
+				return;
+			}
+		}
+	}
+	Send2Application(aplci, cmsg);
+}
+
+void init_AppPlci(void)
+{
+	plci_fsm.state_count = ST_PLCI_COUNT;
+	plci_fsm.event_count = EV_PLCI_COUNT;
+	plci_fsm.strEvent = str_ev_plci;
+	plci_fsm.strState = str_st_plci;
+	
+	mISDN_FsmNew(&plci_fsm, fn_plci_list, FN_PLCI_COUNT);
+}
+
+
+void free_AppPlci(void)
+{
+	mISDN_FsmFree(&plci_fsm);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/appl.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/appl.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/appl.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,535 @@
+/* $Id: appl.c,v 1.14 2006/03/06 12:52:07 keil Exp $
+ *
+ *  Applications are owned by the controller and only
+ *  handle this controller, multiplexing multiple
+ *  controller with one application is done in the higher
+ *  driver independ CAPI driver. The application contain
+ *  the Listen state machine.
+ *
+ */
+
+#include "m_capi.h"
+#include "helper.h"
+#include "debug.h"
+#include "mISDNManufacturer.h"
+
+#define applDebug(appl, lev, fmt, args...) \
+        capidebug(lev, fmt, ## args)
+
+static struct list_head	garbage_applications = LIST_HEAD_INIT(garbage_applications);
+
+int
+ApplicationConstr(Controller_t *contr, __u16 ApplId, capi_register_params *rp)
+{
+	Application_t	*appl = kmalloc(sizeof(Application_t), GFP_ATOMIC);
+
+	if (!appl) {
+		return(-ENOMEM);
+	}
+	memset(appl, 0, sizeof(Application_t));
+	INIT_LIST_HEAD(&appl->head);
+	appl->contr = contr;
+	appl->maxplci = contr->maxplci;
+	appl->AppPlcis  = kmalloc(appl->maxplci * sizeof(AppPlci_t *), GFP_ATOMIC);
+	if (!appl->AppPlcis) {
+		kfree(appl);
+		return(-ENOMEM);
+	}
+	memset(appl->AppPlcis, 0, appl->maxplci * sizeof(AppPlci_t *));
+	appl->ApplId = ApplId;
+	appl->MsgId = 1;
+	appl->NotificationMask = 0;
+	memcpy(&appl->reg_params, rp, sizeof(capi_register_params));
+	listenConstr(appl);
+	list_add(&appl->head, &contr->Applications);
+	test_and_set_bit(APPL_STATE_ACTIV, &appl->state);
+	return(0);
+}
+
+/*
+ * Destroy the Application
+ *
+ * depending who initiate this we cannot release imediatly, if
+ * any AppPlci is still in use.
+ *
+ * @who:   0 - a AppPlci is released in state APPL_STATE_RELEASE
+ *         1 - Application is released from CAPI application
+ *         2 - the controller is resetted
+ *         3 - the controller is removed
+ *         4 - the CAPI module will be unload
+ */
+int
+ApplicationDestr(Application_t *appl, int who)
+{
+	int		i, used = 0;
+	AppPlci_t	**aplci_p = appl->AppPlcis;
+
+	if (test_and_set_bit(APPL_STATE_DESTRUCTOR, &appl->state)) {
+		// we are allready in this function
+		return(-EBUSY);
+	}
+	test_and_set_bit(APPL_STATE_RELEASE, &appl->state);
+	test_and_clear_bit(APPL_STATE_ACTIV, &appl->state);
+	listenDestr(appl);
+	if (who > 2) {
+		appl->contr = NULL;
+	}
+	if (aplci_p) {
+		for (i = 0; i < appl->maxplci; i++) {
+			if (*aplci_p) {
+				switch (who) {
+					case 4:
+						AppPlciDestr(*aplci_p);
+						*aplci_p = NULL;
+						break;
+					case 1:
+					case 2:
+					case 3:
+						AppPlciRelease(*aplci_p);
+					case 0:
+						if ((volatile AppPlci_t *)(*aplci_p))
+							used++;
+						break;
+				}
+			}
+			aplci_p++;
+		}
+	}
+	if (used) {
+		if (who == 3) {
+			list_del_init(&appl->head);
+			list_add(&appl->head, &garbage_applications);
+		}
+		test_and_clear_bit(APPL_STATE_DESTRUCTOR, &appl->state);
+		return(-EBUSY);
+	}
+	list_del_init(&appl->head);
+	appl->maxplci = 0;
+	kfree(appl->AppPlcis);
+	appl->AppPlcis = NULL;
+	kfree(appl);
+	return(0);
+}
+
+AppPlci_t *
+getAppPlci4addr(Application_t *appl, __u32 addr)
+{
+	int plci_idx = (addr >> 8) & 0xff;
+
+	if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
+		int_error();
+		return NULL;
+	}
+	return(appl->AppPlcis[plci_idx - 1]);
+}
+
+static void
+FacilityReq(Application_t *appl, struct sk_buff *skb)
+{
+	_cmsg		*cmsg;
+	AppPlci_t	*aplci;
+	Ncci_t		*ncci;
+
+	cmsg = cmsg_alloc();
+	if (!cmsg) {
+		int_error();
+		dev_kfree_skb(skb);
+		return;
+	}
+	capi_message2cmsg(cmsg, skb->data);
+	switch (cmsg->FacilitySelector) {
+		case 0x0000: // Handset
+		case 0x0001: // DTMF
+			aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
+			if (aplci) {
+				ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_PLCI);
+				if (ncci) {
+					ncciGetCmsg(ncci, cmsg);
+					break;
+				}
+			}
+			SendCmsgAnswer2Application(appl, cmsg, CapiIllContrPlciNcci);
+			break;
+		case 0x0003: // SupplementaryServices
+			SupplementaryFacilityReq(appl, cmsg);
+			break;
+		default:
+			int_error();
+			SendCmsgAnswer2Application(appl, cmsg, CapiFacilityNotSupported);
+			break;
+	}
+	dev_kfree_skb(skb);
+}
+
+void
+ApplicationSendMessage(Application_t *appl, struct sk_buff *skb)
+{
+	Plci_t		*plci;
+	AppPlci_t	*aplci;
+	__u16		ret;
+
+	switch (CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data))) {
+		// new NCCI
+		case CAPI_CONNECT_B3_REQ:
+			aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
+			if (!aplci) {
+				AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
+				goto free;
+			}
+			ConnectB3Request(aplci, skb);
+			break;
+		// maybe already down NCCI
+		case CAPI_DISCONNECT_B3_RESP:
+			aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
+			if (!aplci) {
+				AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
+				goto free;
+			}
+			DisconnectB3Request(aplci, skb);
+			break;
+		// for PLCI state machine
+		case CAPI_INFO_REQ:
+		case CAPI_ALERT_REQ:
+		case CAPI_CONNECT_RESP:
+		case CAPI_CONNECT_ACTIVE_RESP:
+		case CAPI_DISCONNECT_REQ:
+		case CAPI_DISCONNECT_RESP:
+		case CAPI_SELECT_B_PROTOCOL_REQ:
+			aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
+			if (!aplci) {
+				AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
+				goto free;
+			}
+			ret = AppPlciSendMessage(aplci, skb);
+			if (ret) {
+				int_error();
+			}
+			break;
+		case CAPI_CONNECT_REQ:
+			if (ControllerNewPlci(appl->contr, &plci, MISDN_ID_ANY)) {
+				AnswerMessage2Application(appl, skb, CapiNoPlciAvailable);
+				goto free;
+			}
+			aplci = ApplicationNewAppPlci(appl, plci);
+			if (!aplci) {
+				AnswerMessage2Application(appl, skb, CapiNoPlciAvailable);
+				goto free;
+			}
+			ret = AppPlciSendMessage(aplci, skb);
+			if (ret) {
+				int_error();
+			}
+			break;
+
+		// for LISTEN state machine
+		case CAPI_LISTEN_REQ:
+			ret = listenSendMessage(appl, skb);
+			if (ret) {
+				int_error();
+			}
+			break;
+
+		// other
+		case CAPI_FACILITY_REQ:
+			FacilityReq(appl, skb);
+			break;
+		case CAPI_FACILITY_RESP:
+			goto free;
+		case CAPI_MANUFACTURER_REQ:
+			applManufacturerReq(appl, skb);
+			break;
+		case CAPI_INFO_RESP:
+			goto free;
+		default:
+			applDebug(appl, CAPI_DBG_WARN, "applSendMessage: %#x %#x not handled!", 
+				CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
+			break;
+	}
+	return;
+ free:
+	dev_kfree_skb(skb);
+	return;
+}
+
+AppPlci_t *
+ApplicationNewAppPlci(Application_t *appl, Plci_t *plci)
+{
+	AppPlci_t	*aplci;
+	int		plci_idx = (plci->addr >> 8) & 0xff;
+
+	if (test_bit(APPL_STATE_RELEASE, &appl->state))
+		return(NULL);
+	if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
+		int_error();
+		return(NULL);
+	}
+	if (appl->AppPlcis[plci_idx - 1]) {
+		int_error();
+		return(NULL);
+	}
+	if (AppPlciConstr(&aplci, appl, plci)) {
+		int_error();
+		return(NULL);
+	}
+	applDebug(appl, CAPI_DBG_APPL_INFO, "ApplicationNewAppPlci: idx(%d) aplci(%p) appl(%p) plci(%p)",
+		plci_idx, aplci, appl, plci);
+	appl->AppPlcis[plci_idx - 1] = aplci;
+	plciAttachAppPlci(plci, aplci);
+	return(aplci);
+}
+
+void
+ApplicationDelAppPlci(Application_t *appl, AppPlci_t *aplci)
+{
+	int	plci_idx = (aplci->addr >> 8) & 0xff;
+
+	if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
+		int_error();
+		return;
+	}
+	if (appl->AppPlcis[plci_idx - 1] != aplci) {
+		int_error();
+		return;
+	}
+	appl->AppPlcis[plci_idx - 1] = NULL;
+	if (test_bit(APPL_STATE_RELEASE, &appl->state) &&
+		!test_bit(APPL_STATE_DESTRUCTOR, &appl->state))
+		ApplicationDestr(appl, 0);
+}
+
+void
+SendCmsg2Application(Application_t *appl, _cmsg *cmsg)
+{
+	struct sk_buff	*skb;
+	
+	if (test_bit(APPL_STATE_RELEASE, &appl->state)) {
+		/* Application is released and cannot receive messages
+		 * anymore. To avoid stalls in the state machines we
+		 * must answer INDICATIONS.
+		 */
+		AppPlci_t	*aplci;
+		Ncci_t		*ncci;
+
+		if (CAPI_IND != cmsg->Subcommand)
+			goto free;
+		switch(cmsg->Command) {
+			// for NCCI state machine
+			case CAPI_CONNECT_B3:
+				cmsg->Reject = 2;
+			case CAPI_CONNECT_B3_ACTIVE:
+			case CAPI_DISCONNECT_B3:
+				aplci = getAppPlci4addr(appl, (cmsg->adr.adrNCCI & 0xffff));
+				if (!aplci)
+					goto free;
+				ncci = getNCCI4addr(aplci, cmsg->adr.adrNCCI, GET_NCCI_EXACT); 
+				if (!ncci) {
+					int_error();
+					goto free;
+				}
+				capi_cmsg_answer(cmsg);
+				ncciGetCmsg(ncci, cmsg);
+				break;
+			// for PLCI state machine
+			case CAPI_CONNECT:
+				cmsg->Reject = 2;
+			case CAPI_CONNECT_ACTIVE:
+			case CAPI_DISCONNECT:
+				aplci = getAppPlci4addr(appl, (cmsg->adr.adrPLCI & 0xffff));
+				if (!aplci)
+					goto free;
+				capi_cmsg_answer(cmsg);
+				AppPlciGetCmsg(aplci, cmsg);
+				break;
+			case CAPI_FACILITY:
+			case CAPI_MANUFACTURER:
+			case CAPI_INFO:
+				goto free;
+			default:
+				int_error();
+				goto free;
+		}
+		return;
+	}
+	if (!(skb = alloc_skb(CAPI_MSG_DEFAULT_LEN, GFP_ATOMIC))) {
+		printk(KERN_WARNING "%s: no mem for %d bytes\n", __FUNCTION__, CAPI_MSG_DEFAULT_LEN);
+		int_error();
+		goto free;
+	}
+	capi_cmsg2message(cmsg, skb->data);
+	applDebug(appl, CAPI_DBG_APPL_MSG, "%s: len(%d) applid(%x) %s msgnr(%d) addr(%08x)",
+		__FUNCTION__, CAPIMSG_LEN(skb->data), cmsg->ApplId, capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+		cmsg->Messagenumber, cmsg->adr.adrController);
+	if (CAPI_MSG_DEFAULT_LEN < CAPIMSG_LEN(skb->data)) {
+		printk(KERN_ERR "%s: CAPI_MSG_DEFAULT_LEN overrun (%d/%d)\n",  __FUNCTION__,
+			CAPIMSG_LEN(skb->data), CAPI_MSG_DEFAULT_LEN);
+		int_error();
+		dev_kfree_skb(skb);
+		goto free; 
+	}
+	skb_put(skb, CAPIMSG_LEN(skb->data));
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	appl->contr->ctrl->handle_capimsg(appl->contr->ctrl, cmsg->ApplId, skb);
+#else
+	capi_ctr_handle_message(appl->contr->ctrl, cmsg->ApplId, skb);
+#endif
+free:
+	cmsg_free(cmsg);
+}
+
+void
+SendCmsgAnswer2Application(Application_t *appl, _cmsg *cmsg, __u16 Info)
+{
+	capi_cmsg_answer(cmsg);
+	cmsg->Info = Info;
+	SendCmsg2Application(appl, cmsg);
+}
+
+void
+AnswerMessage2Application(Application_t *appl, struct sk_buff *skb, __u16 Info)
+{
+	_cmsg	*cmsg;
+
+	CMSG_ALLOC(cmsg);
+	capi_message2cmsg(cmsg, skb->data);
+	SendCmsgAnswer2Application(appl, cmsg, Info);
+}
+
+#define AVM_MANUFACTURER_ID	0x214D5641 /* "AVM!" */
+#define CLASS_AVM		0x00
+#define FUNCTION_AVM_D2_TRACE	0x01
+
+struct AVMD2Trace {
+	__u8 Length;
+	__u8 data[4];
+};
+
+void applManufacturerReqAVM(Application_t *appl, _cmsg *cmsg, struct sk_buff *skb)
+{
+	struct AVMD2Trace *at;
+
+	if (cmsg->Class != CLASS_AVM) {
+		applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown class %#x\n", cmsg->Class);
+		cmsg_free(cmsg);
+		dev_kfree_skb(skb);
+		return;
+	}
+	switch (cmsg->Function) {
+		case FUNCTION_AVM_D2_TRACE:
+			at = (struct AVMD2Trace *)cmsg->ManuData;
+			if (!at || at->Length != 4) {
+				int_error();
+				break;
+			}
+			if (memcmp(at->data, "\200\014\000\000", 4) == 0) {
+				test_and_set_bit(APPL_STATE_D2TRACE, &appl->state);
+			} else if (memcmp(at->data, "\000\000\000\000", 4) == 0) {
+				test_and_clear_bit(APPL_STATE_D2TRACE, &appl->state);
+			} else {
+				int_error();
+			}
+			break;
+		default:
+			applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown function %#x\n", cmsg->Function);
+	}
+	cmsg_free(cmsg);
+	dev_kfree_skb(skb);
+}
+
+void applManufacturerReqmISDN(Application_t *appl, _cmsg *cmsg, struct sk_buff *skb)
+{
+	AppPlci_t	*aplci;
+	Ncci_t		*ncci;
+
+	switch (cmsg->Class) {
+		case mISDN_MF_CLASS_HANDSET:
+			/* Note normally MANUFATURER messages are only defined for
+			 * controller address we extent it here to PLCI/NCCI
+			 */
+			aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
+			if (aplci) {
+				ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_PLCI);
+				if (ncci) {
+					cmsg_free(cmsg);
+					ncciSendMessage(ncci, skb);
+					return;
+				}
+			}
+			SendCmsgAnswer2Application(appl, cmsg, CapiIllContrPlciNcci);
+			break;
+		default:
+			cmsg_free(cmsg);
+			break;
+	}
+	dev_kfree_skb(skb);
+}
+
+void
+applManufacturerReq(Application_t *appl, struct sk_buff *skb)
+{
+	_cmsg	*cmsg;
+
+	if (skb->len < 16 + 8) {
+		dev_kfree_skb(skb);
+		return;
+	}
+	cmsg = cmsg_alloc();
+	if (!cmsg) {
+		int_error();
+		dev_kfree_skb(skb);
+		return;
+	}
+	capi_message2cmsg(cmsg, skb->data);
+	switch (cmsg->ManuID) {
+		case mISDN_MANUFACTURER_ID:
+			applManufacturerReqmISDN(appl, cmsg, skb);
+			break;
+		case AVM_MANUFACTURER_ID:
+			applManufacturerReqAVM(appl, cmsg, skb);
+			break;
+		default:
+			applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown ManuID %#x\n", cmsg->ManuID);
+			cmsg_free(cmsg);
+			dev_kfree_skb(skb);
+			break;
+	}
+}
+
+void applD2Trace(Application_t *appl, u_char *buf, int len)
+{
+	_cmsg	*cmsg;
+	__u8	manuData[255];
+
+	if (!test_bit(APPL_STATE_D2TRACE, &appl->state))
+		return;
+	
+	CMSG_ALLOC(cmsg);
+	capi_cmsg_header(cmsg, appl->ApplId, CAPI_MANUFACTURER, CAPI_IND, 
+			 appl->MsgId++, appl->contr->addr);
+	cmsg->ManuID = AVM_MANUFACTURER_ID;
+	cmsg->Class = CLASS_AVM;
+	cmsg->Function = FUNCTION_AVM_D2_TRACE;
+	cmsg->ManuData = (_cstruct) &manuData;
+	manuData[0] = 2 + len; // length
+	manuData[1] = 0x80;
+	manuData[2] = 0x0f;
+	memcpy(&manuData[3], buf, len);
+	
+	SendCmsg2Application(appl, cmsg);
+}
+
+void
+free_Application(void)
+{
+	struct list_head	*item, *next;
+	int			n = 0;
+
+	if (list_empty(&garbage_applications)) {
+		printk(KERN_DEBUG "%s: no garbage\n", __FUNCTION__);
+		return;
+	}
+	list_for_each_safe(item, next, &garbage_applications) {
+		ApplicationDestr((Application_t *)item, 4);
+		n++;
+	}
+	printk(KERN_WARNING"%s: %d garbage items\n", __FUNCTION__, n);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/arcofi.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/arcofi.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/arcofi.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,149 @@
+/* $Id: arcofi.c,v 1.7 2006/03/06 12:52:07 keil Exp $
+ *
+ * arcofi.c   Ansteuerung ARCOFI 2165
+ *
+ * Author     Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+ 
+#include "channel.h"
+#include "layer1.h"
+#include "isac.h"
+#include "arcofi.h"
+#include "debug.h"
+#include "helper.h"
+
+#define ARCOFI_TIMER_VALUE	20
+
+static void
+add_arcofi_timer(channel_t *dch) {
+	isac_chip_t	*isac = dch->hw;
+
+	if (test_and_set_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
+		del_timer(&isac->arcofitimer);
+	}	
+	init_timer(&isac->arcofitimer);
+	isac->arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ)/1000);
+	add_timer(&isac->arcofitimer);
+}
+
+static void
+send_arcofi(channel_t *dch) {
+	u_char		val;
+	isac_chip_t	*isac = dch->hw;
+	
+	add_arcofi_timer(dch);
+	isac->mon_txp = 0;
+	isac->mon_txc = isac->arcofi_list->len;
+	memcpy(isac->mon_tx, isac->arcofi_list->msg, isac->mon_txc);
+	switch(isac->arcofi_bc) {
+		case 0: break;
+		case 1: isac->mon_tx[1] |= 0x40;
+			break;
+		default: break;
+	}
+	isac->mocr &= 0x0f;
+	isac->mocr |= 0xa0;
+	dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+	val = dch->read_reg(dch->inst.privat, ISAC_MOSR);
+	dch->write_reg(dch->inst.privat, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
+	isac->mocr |= 0x10;
+	dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+}
+
+int
+arcofi_fsm(channel_t *dch, int event, void *data) {
+	isac_chip_t	*isac = dch->hw;
+
+	if (dch->debug & L1_DEB_MONITOR) {
+		mISDN_debugprint(&dch->inst, "arcofi state %d event %d", isac->arcofi_state, event);
+	}
+	if (event == ARCOFI_TIMEOUT) {
+		isac->arcofi_state = ARCOFI_NOP;
+		test_and_set_bit(FLG_ARCOFI_ERROR, &dch->Flags);
+		wake_up(&isac->arcofi_wait);
+ 		return(1);
+	}
+	switch (isac->arcofi_state) {
+		case ARCOFI_NOP:
+			if (event == ARCOFI_START) {
+				isac->arcofi_list = data;
+				isac->arcofi_state = ARCOFI_TRANSMIT;
+				send_arcofi(dch);
+			}
+			break;
+		case ARCOFI_TRANSMIT:
+			if (event == ARCOFI_TX_END) {
+				if (isac->arcofi_list->receive) {
+					add_arcofi_timer(dch);
+					isac->arcofi_state = ARCOFI_RECEIVE;
+				} else {
+					if (isac->arcofi_list->next) {
+						isac->arcofi_list =
+							isac->arcofi_list->next;
+						send_arcofi(dch);
+					} else {
+						if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
+							del_timer(&isac->arcofitimer);
+						}
+						isac->arcofi_state = ARCOFI_NOP;
+						wake_up(&isac->arcofi_wait);
+					}
+				}
+			}
+			break;
+		case ARCOFI_RECEIVE:
+			if (event == ARCOFI_RX_END) {
+				struct sk_buff	*skb = data;
+				
+				// FIXME handle message
+				if (skb)
+					kfree_skb(skb);
+				else
+					int_error();
+				if (isac->arcofi_list->next) {
+					isac->arcofi_list =
+						isac->arcofi_list->next;
+					isac->arcofi_state = ARCOFI_TRANSMIT;
+					send_arcofi(dch);
+				} else {
+					if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
+						del_timer(&isac->arcofitimer);
+					}
+					isac->arcofi_state = ARCOFI_NOP;
+					wake_up(&isac->arcofi_wait);
+				}
+			}
+			break;
+		default:
+			mISDN_debugprint(&dch->inst, "Arcofi unknown state %x", isac->arcofi_state);
+			return(2);
+	}
+	return(0);
+}
+
+static void
+arcofi_timer(channel_t *dch) {
+	arcofi_fsm(dch, ARCOFI_TIMEOUT, NULL);
+}
+
+void
+clear_arcofi(channel_t *dch) {
+	isac_chip_t	*isac = dch->hw;
+
+	if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
+		del_timer(&isac->arcofitimer);
+	}
+}
+
+void
+init_arcofi(channel_t *dch) {
+	isac_chip_t	*isac = dch->hw;
+
+	isac->arcofitimer.function = (void *) arcofi_timer;
+	isac->arcofitimer.data = (long) dch;
+	init_timer(&isac->arcofitimer);
+	dch->type |= ISAC_TYPE_ARCOFI;
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/arcofi.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/arcofi.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/arcofi.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,32 @@
+/* $Id: arcofi.h,v 1.2 2006/03/06 12:52:07 keil Exp $
+ *
+ * arcofi.h   Ansteuerung ARCOFI 2165
+ *
+ * Author     Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+ 
+#define ARCOFI_USE	1
+
+/* states */
+#define ARCOFI_NOP	0
+#define ARCOFI_TRANSMIT	1
+#define ARCOFI_RECEIVE	2
+/* events */
+#define ARCOFI_START	1
+#define ARCOFI_TX_END	2
+#define ARCOFI_RX_END	3
+#define ARCOFI_TIMEOUT	4
+
+struct arcofi_msg {
+	struct arcofi_msg	*next;
+	u_char			receive;
+	u_char			len;
+	u_char			msg[10];
+};
+
+extern int arcofi_fsm(channel_t *, int, void *);
+extern void init_arcofi(channel_t *);
+extern void clear_arcofi(channel_t *);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,133 @@
+/* $Id: asn1.c,v 1.1 2003/11/09 09:12:28 keil Exp $
+ *
+ */
+
+#include "asn1.h"
+
+int ParseTag(u_char *p, u_char *end, int *tag)
+{
+	*tag = *p;
+	return 1;
+}
+
+int ParseLen(u_char *p, u_char *end, int *len)
+{
+	int l, i;
+
+	if (*p == 0x80) { // indefinite
+		*len = -1;
+		return 1;
+	}
+	if (!(*p & 0x80)) { // one byte
+		*len = *p;
+		return 1;
+	}
+	*len = 0;
+	l = *p & ~0x80;
+	p++;
+	for (i = 0; i < l; i++) {
+		*len = (*len << 8) + *p; 
+		p++;
+	}
+	return l+1;
+}
+
+int
+ParseASN1(u_char *p, u_char *end, int level)
+{
+	int tag, len;
+	int ret;
+	int j;
+	u_char *tag_end, *beg;
+
+	beg = p;
+
+	CallASN1(ret, p, end, ParseTag(p, end, &tag));
+	CallASN1(ret, p, end, ParseLen(p, end, &len));
+#ifdef ASN1_DEBUG
+	for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
+	print_asn1msg(PRT_DEBUG_DECODE, "TAG 0x%02x LEN %3d\n", tag, len);
+#endif
+	
+	if (tag & ASN1_TAG_CONSTRUCTED) {
+		if (len == -1) { // indefinite
+			while (*p) {
+				CallASN1(ret, p, end, ParseASN1(p, end, level + 1));
+			}
+			p++;
+			if (*p) 
+				return -1;
+			p++;
+		} else {
+			tag_end = p + len;
+			while (p < tag_end) {
+				CallASN1(ret, p, end, ParseASN1(p, end, level +1));
+			}
+		}
+	} else {
+		for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
+		while (len--) {
+			print_asn1msg(PRT_DEBUG_DECODE, "%02x ", *p);
+			p++;
+		}
+		print_asn1msg(PRT_DEBUG_DECODE, "\n");
+	}
+	for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
+	print_asn1msg(PRT_DEBUG_DECODE, "END (%d)\n", p - beg - 2);
+	return p - beg;
+}
+
+#if 0
+
+#if 0
+u_char data[] = {"\xA2\x03\x02\x01\xA3"};
+#endif
+#if 0 // ActNotDiv
+u_char data[] = {"\xA1\x2C\x02\x01\x7E\x02\x01\x09\x30\x24\x0A"
+		 "\x01\x02\x0A\x01\x03\x30\x0C\x80\x0A\x30\x31"
+		 "\x33\x30\x31\x34\x34\x37\x37\x30\xA1\x0E\x0A"
+		 "\x01\x02\x12\x09\x32\x31\x31\x33\x34\x31\x38\x33\x30"};
+#endif
+#if 0 // ActDiv
+u_char data[] = {"\xA1\x24\x02\x01\xA1\x02\x01\x07\x30\x1C\x0A"
+		 "\x01\x02\x0A\x01\x01\x30\x0C\x80\x0A\x30"
+		 "\x31\x33\x30\x31\x34\x34\x37\x37\x30\x80"
+		 "\x06\x33\x34\x31\x38\x33\x30"};
+#endif
+#if 0 // DeactNotDiv
+u_char data[] = {"\xA1\x1E\x02\x01\x08\x02\x01\x0A\x30\x16\x0A"
+		 "\x01\x02\x0A\x01\x03\xA1\x0E\x0A\x01\x02\x12"
+		 "\x09\x32\x31\x31\x33\x34\x31\x38\x33\x30"};
+#endif
+#if 1 // DeactDiv
+u_char data[] = {"\xA1\x16\x02\x01\xB1\x02\x01\x08\x30\x0E\x0A"
+		 "\x01\x02\x0A\x01\x01\x80\x06\x33\x34\x31\x38\x33\x30"};
+#endif
+#if 0 // AOCE, 0 Einheiten
+u_char data[] = {"\xA1\x15\x02\x02\x00\xDC\x02\x01\x24\x30\x0C"
+		 "\x30\x0A\xA1\x05\x30\x03\x02\x01\x00\x82\x01\x00"};
+#endif
+#if 0 // AOCE, 1 Einheit
+u_char data[] = {"\xA1\x15\x02\x02\x00\xBC\x02\x01\x24\x30\x0C\x30"
+		 "\x0A\xA1\x05\x30\x03\x02\x01\x01\x82\x01\x00"};
+#endif
+#if 0 // AOCD currency
+u_char data[] = {"\xA1\x1A\x02\x02\x1C\x65\x02\x01\x21\x30\x11\xA1\x0C\x81\x02\x44\x4D\xA2\x06\x81\x01\x18\x82\x01\x01\x82\x01\x00"};
+#endif
+u_char *end = data + 47;
+
+#include "asn1_component.h"
+
+void
+main()
+{
+	struct Aoc chan;
+
+#ifdef ASN1_DEBUG
+	ParseASN1(data, end, 0);
+#endif
+
+	ParseComponent(&chan, data, end);
+}
+
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,250 @@
+/* $Id: asn1.h,v 1.3 2006/03/06 12:52:07 keil Exp $
+ *
+ */
+
+#include <linux/mISDNif.h>
+#include "helper.h"
+
+#ifndef __ASN1_H__
+#define __ASN1_H__
+
+typedef enum {
+	invoke       = 1,
+	returnResult = 2,
+	returnError  = 3,
+	reject       = 4,
+} asn1Component;
+
+typedef enum {
+	GeneralP     = 0,
+	InvokeP      = 1,
+	ReturnResultP= 2,
+	ReturnErrorP = 3,
+} asn1Problem;
+
+struct PublicPartyNumber {
+	int publicTypeOfNumber;
+	char numberDigits[30];
+};
+
+struct PartyNumber {
+	int type;
+	union {
+		char unknown[30];
+		struct PublicPartyNumber publicPartyNumber;
+	} p;
+};
+
+struct Address {
+	struct PartyNumber partyNumber;
+	char partySubaddress[30];
+};
+
+struct ServedUserNr {
+	int all;
+	struct PartyNumber partyNumber;
+};
+
+struct ActDivNotification {
+	int procedure;
+	int basicService;
+	struct ServedUserNr servedUserNr;
+	struct Address address;
+};
+
+struct DeactDivNotification {
+	int procedure;
+	int basicService;
+	struct ServedUserNr servedUserNr;
+};
+
+struct ServedUserNumberList {
+	struct PartyNumber partyNumber[10];
+};
+
+struct IntResult {
+	struct ServedUserNr servedUserNr;
+	int procedure;
+	int basicService;
+	struct Address address;
+};
+
+struct IntResultList {
+	struct IntResult intResult[10];
+};
+
+struct asn1Invoke {
+	__u16 invokeId;
+	__u16 operationValue;
+	union {
+		struct ActDivNotification actNot;
+		struct DeactDivNotification deactNot;
+	} o;
+};
+
+struct asn1ReturnResult {
+	__u16 invokeId;
+	union {
+		struct ServedUserNumberList list;
+		struct IntResultList resultList;
+	} o;
+};
+
+struct asn1ReturnError {
+	__u16 invokeId;
+	__u16 errorValue;
+};
+
+struct asn1Reject {
+	int invokeId;
+	asn1Problem problem;
+	__u16 problemValue;
+};
+
+struct asn1_parm {
+	asn1Component comp;
+	union {
+		struct asn1Invoke       inv;
+		struct asn1ReturnResult retResult;
+		struct asn1ReturnError  retError;
+		struct asn1Reject	reject;
+	} u;
+};
+
+
+#undef ASN1_DEBUG
+// #define ASN1_DEBUG
+
+#ifdef ASN1_DEBUG
+#define print_asn1msg(dummy, fmt, args...) printk(KERN_DEBUG fmt, ## args)
+#else
+#define print_asn1msg(dummy, fmt, args...) 
+#endif
+
+int ParseASN1(u_char *p, u_char *end, int level);
+
+int ParseTag(u_char *p, u_char *end, int *tag);
+int ParseLen(u_char *p, u_char *end, int *len);
+
+#define ASN1_TAG_BOOLEAN           (0x01) // is that true?
+#define ASN1_TAG_INTEGER           (0x02)
+#define ASN1_TAG_BIT_STRING        (0x03)
+#define ASN1_TAG_OCTET_STRING      (0x04)
+#define ASN1_TAG_NULL              (0x05)
+#define ASN1_TAG_OBJECT_IDENTIFIER (0x06)
+#define ASN1_TAG_ENUM              (0x0a)
+#define ASN1_TAG_SEQUENCE          (0x30)
+#define ASN1_TAG_SET               (0x31)
+#define ASN1_TAG_NUMERIC_STRING    (0x12)
+#define ASN1_TAG_PRINTABLE_STRING  (0x13)
+#define ASN1_TAG_IA5_STRING        (0x16)
+#define ASN1_TAG_UTC_TIME          (0x17)
+
+#define ASN1_TAG_CONSTRUCTED       (0x20)
+#define ASN1_TAG_CONTEXT_SPECIFIC  (0x80)
+
+#define ASN1_TAG_EXPLICIT          (0x100)
+#define ASN1_TAG_OPT               (0x200)
+#define ASN1_NOT_TAGGED            (0x400)
+
+#define CallASN1(ret, p, end, todo) do { \
+        ret = todo; \
+	if (ret < 0) { \
+                int_error(); \
+                return -1; \
+        } \
+        p += ret; \
+} while (0)
+
+#define INIT \
+	int tag, len; \
+	int ret; \
+	u_char *beg; \
+        \
+        print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> %s\n", __FUNCTION__); \
+	beg = p; \
+	CallASN1(ret, p, end, ParseTag(p, end, &tag)); \
+	CallASN1(ret, p, end, ParseLen(p, end, &len)); \
+        if (len >= 0) { \
+                if (p + len > end) \
+                        return -1; \
+                end = p + len; \
+        }
+
+#define XSEQUENCE_1(todo, act_tag, the_tag, arg1) do { \
+	if (p < end) { \
+  	        if (((the_tag) &~ ASN1_TAG_OPT) == ASN1_NOT_TAGGED) { \
+		        if (((u_char)act_tag == *p) || ((act_tag) == ASN1_NOT_TAGGED)) { \
+			        CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
+                        } else { \
+                                if (!((the_tag) & ASN1_TAG_OPT)) { \
+                                        print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 1 %s:%d\n", __FUNCTION__, __LINE__); \
+                	    	        return -1; \
+                                } \
+                        } \
+	        } else { \
+                        if ((the_tag) & ASN1_TAG_EXPLICIT) { \
+		                if ((u_char)(((the_tag) & 0xff) | (ASN1_TAG_CONTEXT_SPECIFIC | ASN1_TAG_CONSTRUCTED)) == *p) { \
+                                        int xtag, xlen; \
+	                                CallASN1(ret, p, end, ParseTag(p, end, &xtag)); \
+			                CallASN1(ret, p, end, ParseLen(p, end, &xlen)); \
+  	                                CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
+                                } else { \
+                                        if (!(the_tag) & ASN1_TAG_OPT) { \
+                                                print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 2 %s:%d\n", __FUNCTION__, __LINE__); \
+                        	    	        return -1; \
+                                        } \
+                                } \
+                        } else { \
+		                if ((u_char)(((the_tag) & 0xff) | (ASN1_TAG_CONTEXT_SPECIFIC | (act_tag & ASN1_TAG_CONSTRUCTED))) == *p) { \
+  	                                CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
+                                } else { \
+                                        if (!(the_tag) & ASN1_TAG_OPT) { \
+                                                print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 3 %s:%d\n", __FUNCTION__, __LINE__); \
+                        	    	        return -1; \
+                                        } \
+                                } \
+		        } \
+		} \
+        } else { \
+                if (!(the_tag) & ASN1_TAG_OPT) { \
+                        print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 4 %s:%d\n", __FUNCTION__, __LINE__); \
+			return -1; \
+                } \
+        } \
+} while (0)
+
+#define XSEQUENCE_OPT_1(todo, act_tag, the_tag, arg1) \
+        XSEQUENCE_1(todo, act_tag, (the_tag | ASN1_TAG_OPT), arg1)
+
+#define XSEQUENCE(todo, act_tag, the_tag) XSEQUENCE_1(todo, act_tag, the_tag, -1)
+#define XSEQUENCE_OPT(todo, act_tag, the_tag) XSEQUENCE_OPT_1(todo, act_tag, the_tag, -1)
+
+#define XCHOICE_1(todo, act_tag, the_tag, arg1) \
+	if (act_tag == ASN1_NOT_TAGGED) { \
+		return todo(pc, beg, end, arg1); \
+        } \
+        if (the_tag == ASN1_NOT_TAGGED) { \
+		  if (act_tag == tag) { \
+                            return todo(pc, beg, end, arg1); \
+                  } \
+         } else { \
+		  if ((the_tag | (0x80 | (act_tag & 0x20))) == tag) { \
+                            return todo(pc, beg, end, arg1); \
+                  } \
+	 }
+
+#define XCHOICE(todo, act_tag, the_tag) XCHOICE_1(todo, act_tag, the_tag, -1)
+
+#define XCHOICE_DEFAULT do {\
+          print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 5 %s:%d\n", __FUNCTION__, __LINE__); \
+          return -1; \
+	  } while (0)
+
+#define CHECK_P do { \
+        if (p >= end) \
+                 return -1; \
+        } while (0) 
+
+
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_address.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_address.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_address.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,233 @@
+/* $Id: asn1_address.c,v 1.0 2001/11/02 23:42:26 kkeil Exp $
+ *
+ */
+
+#include "asn1.h"
+#include "asn1_generic.h"
+#include "asn1_address.h"
+
+void buildnumber(char *num, int oc3, int oc3a, char *result, int version,
+		 int *provider, int *sondernummer, int *intern, int *local,
+		 int dir, int who);
+
+
+// ======================================================================
+// Address Types EN 300 196-1 D.3
+
+int ParsePresentationRestricted(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int ret;
+
+	ret = ParseNull(pc, p, end, -1);
+	if (ret < 0)
+		return ret;
+	strcpy(str, "(presentation restricted)");
+	return ret;
+}
+
+int ParseNotAvailInterworking(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int ret;
+
+	ret = ParseNull(pc, p, end, -1);
+	if (ret < 0)
+		return ret;
+	strcpy(str, "(not available)");
+	return ret;
+}
+
+int ParsePresentedAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	XCHOICE_1(ParseAddressScreened, ASN1_TAG_SEQUENCE, 0, str);
+	XCHOICE_1(ParsePresentationRestricted, ASN1_TAG_NULL, 1, str);
+	XCHOICE_1(ParseNotAvailInterworking, ASN1_TAG_NULL, 2, str);
+	XCHOICE_1(ParseAddressScreened, ASN1_TAG_NULL, 3, str);
+	XCHOICE_DEFAULT;
+}
+
+int ParsePresentedNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	XCHOICE_1(ParseNumberScreened, ASN1_TAG_SEQUENCE, 0, str);
+	XCHOICE_1(ParsePresentationRestricted, ASN1_TAG_NULL, 1, str);
+	XCHOICE_1(ParseNotAvailInterworking, ASN1_TAG_NULL, 2, str);
+	XCHOICE_1(ParseNumberScreened, ASN1_TAG_NULL, 3, str);
+	XCHOICE_DEFAULT;
+}
+
+int ParsePresentedNumberUnscreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	struct PartyNumber partyNumber;
+	INIT;
+
+	XCHOICE_1(ParsePartyNumber, ASN1_TAG_SEQUENCE, 0, &partyNumber); // FIXME EXP
+	XCHOICE_1(ParsePresentationRestricted, ASN1_TAG_NULL, 1, str);
+	XCHOICE_1(ParseNotAvailInterworking, ASN1_TAG_NULL, 2, str);
+	XCHOICE_1(ParsePartyNumber, ASN1_TAG_SEQUENCE, 3, &partyNumber); // FIXME EXP
+	XCHOICE_DEFAULT;
+}
+
+int ParseNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	struct PartyNumber partyNumber;
+	char screeningIndicator[30];
+	INIT;
+
+	XSEQUENCE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &partyNumber);
+	XSEQUENCE_1(ParseScreeningIndicator, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, screeningIndicator);
+
+//	str += sprintf(str, "%s", partyNumber);
+
+	return p - beg;
+}
+
+int ParseAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	struct PartyNumber partyNumber;
+	char partySubaddress[30] = { 0, };
+	char screeningIndicator[30];
+	INIT;
+
+	XSEQUENCE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &partyNumber);
+	XSEQUENCE_1(ParseScreeningIndicator, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, screeningIndicator);
+	XSEQUENCE_OPT_1(ParsePartySubaddress, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, partySubaddress);
+
+//	str += sprintf(str, "%s", partyNumber);
+	if (strlen(partySubaddress))
+		str += sprintf(str, ".%s", partySubaddress);
+
+	return p - beg;
+}
+
+int ParseAddress(struct asn1_parm *pc, u_char *p, u_char *end, struct Address *address)
+{
+	INIT;
+
+	address->partySubaddress[0] = 0;
+	XSEQUENCE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &address->partyNumber);
+	
+	XSEQUENCE_OPT_1(ParsePartySubaddress, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, address->partySubaddress);
+
+	return p - beg;
+}
+
+int ParsePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PartyNumber *partyNumber)
+{
+	INIT;
+
+	partyNumber->type = 0;
+	XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 0, partyNumber->p.unknown); // unknownPartyNumber
+	partyNumber->type = 1;
+	XCHOICE_1(ParsePublicPartyNumber, ASN1_TAG_SEQUENCE, 1, &partyNumber->p.publicPartyNumber); 
+#if 0
+	XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 3, str); // dataPartyNumber
+	XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 4, str); // telexPartyNumber
+	XCHOICE_1(ParsePrivatePartyNumber, ASN1_TAG_SEQUENCE, 5, str);
+	XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 8, str); // nationalStandardPartyNumber
+#endif
+	XCHOICE_DEFAULT;
+}
+
+int ParsePublicPartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PublicPartyNumber *publicPartyNumber)
+{
+	INIT;
+
+	XSEQUENCE_1(ParsePublicTypeOfNumber, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &publicPartyNumber->publicTypeOfNumber);
+	XSEQUENCE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, ASN1_NOT_TAGGED, publicPartyNumber->numberDigits);
+
+	return p - beg;
+}
+
+#if 0
+int ParsePrivatePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int privateTypeOfNumber;
+	char numberDigits[20];
+	INIT;
+
+	XSEQUENCE_1(ParsePrivateTypeOfNumber, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &privateTypeOfNumber); 
+	XSEQUENCE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, ASN1_NOT_TAGGED, numberDigits); 
+
+	switch (privateTypeOfNumber) {
+	case 0: str += sprintf(str, "(unknown)"); break;
+	case 1: str += sprintf(str, "(regional2)"); break;
+	case 2: str += sprintf(str, "(regional1)"); break;
+	case 3: str += sprintf(str, "(ptn)"); break;
+	case 4: str += sprintf(str, "(local)"); break;
+	case 6: str += sprintf(str, "(abbrev)"); break;
+	}
+	str += sprintf(str, numberDigits);
+
+	return p - beg;
+}
+#endif
+
+int ParsePublicTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *publicTypeOfNumber)
+{
+	return ParseEnum(pc, p, end, publicTypeOfNumber);
+}
+
+#if 0
+int ParsePrivateTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *privateTypeOfNumber)
+{
+	return ParseEnum(pc, p, end, privateTypeOfNumber);
+}
+#endif
+
+int ParsePartySubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	XCHOICE_1(ParseUserSpecifiedSubaddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, str);
+	XCHOICE_1(ParseNSAPSubaddress, ASN1_TAG_OCTET_STRING, ASN1_NOT_TAGGED, str);
+	XCHOICE_DEFAULT;
+}
+
+int ParseUserSpecifiedSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int oddCountIndicator;
+	INIT;
+
+	XSEQUENCE_1(ParseSubaddressInformation, ASN1_TAG_OCTET_STRING, ASN1_NOT_TAGGED, str);
+	XSEQUENCE_OPT_1(ParseBoolean, ASN1_TAG_BOOLEAN, ASN1_NOT_TAGGED, &oddCountIndicator);
+	
+	return p - beg;
+}
+
+int ParseNSAPSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	return ParseOctetString(pc, p, end, str);
+}
+
+int ParseSubaddressInformation(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	return ParseOctetString(pc, p, end, str);
+}
+
+int ParseScreeningIndicator(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int ret;
+	int screeningIndicator;
+
+	ret = ParseEnum(pc, p, end, &screeningIndicator);
+	if (ret < 0)
+		return ret;
+	
+	switch (screeningIndicator) {
+	case 0: sprintf(str, "user provided, not screened"); break;
+	case 1: sprintf(str, "user provided, passed"); break;
+	case 2: sprintf(str, "user provided, failed"); break;
+	case 3: sprintf(str, "network provided"); break;
+	default: sprintf(str, "(%d)", screeningIndicator); break;
+	}
+
+	return ret;
+}
+
+int ParseNumberDigits(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	return ParseNumericString(pc, p, end, str);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_address.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_address.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_address.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,25 @@
+/* $Id: asn1_address.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
+ *
+ */
+
+// ======================================================================
+// Address Types EN 300 196-1 D.3
+
+int ParsePresentedAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParsePresentedNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParsePresentedNumberUnscreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseAddress(struct asn1_parm *pc, u_char *p, u_char *end, struct Address *address);
+int ParsePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PartyNumber *partyNumber);
+int ParsePublicPartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PublicPartyNumber *publicPartyNumber);
+int ParsePrivatePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParsePublicTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *publicTypeOfNumber);
+int ParsePrivateTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *privateTypeOfNumber);
+int ParsePartySubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseUserSpecifiedSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseNSAPSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseSubaddressInformation(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseScreeningIndicator(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseNumberDigits(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_aoc.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_aoc.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_aoc.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,355 @@
+/* $Id: asn1_aoc.c,v 1.0 2001/11/02 23:42:26 kkeil Exp $
+ *
+ */
+
+#include "asn1.h"
+#include "asn1_generic.h"
+#if 0
+#include "asn1_address.h"
+#endif
+#include "asn1_aoc.h"
+
+// ======================================================================
+// AOC EN 300 182-1 V1.3.3
+
+#if 0
+// AOCDCurrency
+
+int
+ParseAOCDCurrency(struct Channel *chanp, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
+	XCHOICE(ParseAOCDCurrencyInfo, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE_DEFAULT;
+}
+#endif
+// AOCDChargingUnit
+
+int
+ParseAOCDChargingUnit(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
+	XCHOICE(ParseAOCDChargingUnitInfo, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE_DEFAULT;
+}
+
+#if 0
+// AOCECurrency
+
+int
+ParseAOCECurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
+	XCHOICE(ParseAOCECurrencyInfo, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE_DEFAULT;
+}
+#endif
+
+// AOCEChargingUnit
+
+int
+ParseAOCEChargingUnit(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
+	XCHOICE(ParseAOCEChargingUnitInfo, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE_DEFAULT;
+}
+
+#if 0
+// AOCDCurrencyInfo
+
+int
+ParseAOCDSpecificCurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int typeOfChargingInfo;
+	int billingId;
+	INIT;
+
+	XSEQUENCE(ParseRecordedCurrency, ASN1_TAG_SEQUENCE, 1);
+	XSEQUENCE_1(ParseTypeOfChargingInfo, ASN1_TAG_ENUM, 2, &typeOfChargingInfo);
+	XSEQUENCE_OPT_1(ParseAOCDBillingId, ASN1_TAG_ENUM, 3, &billingId);
+
+	return p - beg;
+}
+
+int
+ParseAOCDCurrencyInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseAOCDSpecificCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
+	XCHOICE_DEFAULT;
+}
+#endif
+
+// AOCDChargingUnitInfo
+
+int
+ParseAOCDSpecificChargingUnits(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int recordedUnits;
+	int typeOfChargingInfo;
+	int billingId;
+	INIT;
+
+	XSEQUENCE_1(ParseRecordedUnitsList, ASN1_TAG_SEQUENCE, 1, &recordedUnits);
+	XSEQUENCE_1(ParseTypeOfChargingInfo, ASN1_TAG_ENUM, 2, &typeOfChargingInfo);
+	XSEQUENCE_OPT_1(ParseAOCDBillingId, ASN1_TAG_ENUM, 3, &billingId);
+
+//	p_L3L4(pc, CC_CHARGE | INDICATION, &recordedUnits);
+
+	return p - beg;
+}
+
+int
+ParseAOCDChargingUnitInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseAOCDSpecificChargingUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
+	XCHOICE_DEFAULT;
+}
+
+#if 0
+// RecordedCurrency
+
+int
+ParseRecordedCurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	char currency[11];
+	INIT;
+
+	XSEQUENCE_1(ParseCurrency, ASN1_TAG_IA5_STRING, 1, currency);
+	XSEQUENCE(ParseAmount, ASN1_TAG_SEQUENCE, 2);
+
+	return p - beg;
+}
+#endif
+
+// RecordedUnitsList
+
+int
+ParseRecordedUnitsList(struct asn1_parm *pc, u_char *p, u_char *end, int *recordedUnits)
+{
+	int i;
+	INIT;
+
+	XSEQUENCE_1(ParseRecordedUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, recordedUnits);
+	for (i = 0; i < 31; i++) 
+		XSEQUENCE_OPT_1(ParseRecordedUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, recordedUnits);
+
+	return p - beg;
+}
+
+// TypeOfChargingInfo
+
+int
+ParseTypeOfChargingInfo(struct asn1_parm *pc, u_char *p, u_char *end, int *typeOfChargingInfo)
+{
+	return ParseEnum(pc, p, end, typeOfChargingInfo);
+}
+
+// RecordedUnits
+
+int
+ParseRecordedUnitsChoice(struct asn1_parm *pc, u_char *p, u_char *end, int *recordedUnits)
+{
+	INIT;
+
+	XCHOICE_1(ParseNumberOfUnits, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, recordedUnits);
+	XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // not available
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseRecordedUnits(struct asn1_parm *pc, u_char *p, u_char *end, int *recordedUnits)
+{
+	int typeOfUnit;
+	INIT;
+
+	XSEQUENCE_1(ParseRecordedUnitsChoice, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, recordedUnits);
+	XSEQUENCE_OPT_1(ParseTypeOfUnit, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &typeOfUnit);
+
+	return p - beg;
+}
+
+// AOCDBillingId
+
+int
+ParseAOCDBillingId(struct asn1_parm *pc, u_char *p, u_char *end, int *billingId)
+{
+	return ParseEnum(pc, p, end, billingId);
+}
+
+#if 0
+// AOCECurrencyInfo
+
+int
+ParseAOCESpecificCurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int billingId;
+	INIT;
+
+	XSEQUENCE(ParseRecordedCurrency, ASN1_TAG_SEQUENCE, 1);
+	XSEQUENCE_OPT_1(ParseAOCEBillingId, ASN1_TAG_ENUM, 2, &billingId);
+
+	return p - beg;
+}
+
+int
+ParseAOCECurrencyInfoChoice(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseAOCESpecificCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseAOCECurrencyInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XSEQUENCE(ParseAOCECurrencyInfoChoice, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
+	XSEQUENCE_OPT(ParseChargingAssociation, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
+	XCHOICE_DEFAULT;
+}
+#endif
+
+// AOCEChargingUnitInfo
+
+int
+ParseAOCESpecificChargingUnits(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int recordedUnits;
+	int billingId;
+	INIT;
+
+	XSEQUENCE_1(ParseRecordedUnitsList, ASN1_TAG_SEQUENCE, 1, &recordedUnits);
+	XSEQUENCE_OPT_1(ParseAOCEBillingId, ASN1_TAG_ENUM, 2, &billingId);
+
+//	p_L3L4(pc, CC_CHARGE | INDICATION, &recordedUnits);
+
+	return p - beg;
+}
+
+int
+ParseAOCEChargingUnitInfoChoice(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XCHOICE(ParseAOCESpecificChargingUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseAOCEChargingUnitInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	XSEQUENCE(ParseAOCEChargingUnitInfoChoice, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
+	XSEQUENCE_OPT(ParseChargingAssociation, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
+
+	return p - beg;
+}
+
+// AOCEBillingId
+
+int
+ParseAOCEBillingId(struct asn1_parm *pc, u_char *p, u_char *end, int *billingId)
+{
+	return ParseEnum(pc, p, end, billingId);
+}
+
+#if 0
+// Currency
+
+int
+ParseCurrency(struct asn1_parm *pc, u_char *p, u_char *end, char *currency)
+{
+	return ParseIA5String(chanp, p, end, currency);
+}
+
+// Amount
+
+int
+ParseAmount(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int amount;
+	int multiplier;
+	INIT;
+
+	XSEQUENCE_1(ParseCurrencyAmount, ASN1_TAG_INTEGER, 1, &amount);
+	XSEQUENCE_1(ParseMultiplier, ASN1_TAG_INTEGER, 2, &multiplier);
+
+	return p - beg;
+}
+
+// CurrencyAmount
+
+int
+ParseCurrencyAmount(struct asn1_parm *pc, u_char *p, u_char *end, int *currencyAmount)
+{
+	return ParseInteger(chanp, p, end, currencyAmount);
+}
+
+// Multiplier
+
+int
+ParseMultiplier(struct asn1_parm *pc, u_char *p, u_char *end, int *multiplier)
+{
+	return ParseEnum(chanp, p, end, multiplier);
+}
+#endif
+
+// TypeOfUnit
+
+int
+ParseTypeOfUnit(struct asn1_parm *pc, u_char *p, u_char *end, int *typeOfUnit)
+{
+	return ParseInteger(pc, p, end, typeOfUnit);
+}
+
+// NumberOfUnits
+
+int
+ParseNumberOfUnits(struct asn1_parm *pc, u_char *p, u_char *end, int *numberOfUnits)
+{
+	return ParseInteger(pc, p, end, numberOfUnits);
+}
+
+// Charging Association
+
+int
+ParseChargingAssociation(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+//	char partyNumber[30];
+	INIT;
+
+//	XCHOICE_1(ParsePartyNumber, ASN1_TAG_SEQUENCE, 0, partyNumber);
+	XCHOICE(ParseChargeIdentifier, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED);
+	XCHOICE_DEFAULT;
+}
+
+// ChargeIdentifier
+
+int
+ParseChargeIdentifier(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int chargeIdentifier;
+
+	return ParseInteger(pc, p, end, &chargeIdentifier);
+}
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_aoc.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_aoc.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_aoc.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,30 @@
+/* $Id: asn1_aoc.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
+ *
+ */
+
+// ======================================================================
+// AOC EN 300 182-1 V1.3.3
+
+int ParseAOCDCurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
+int ParseAOCDChargingUnit(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+int ParseAOCECurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
+int ParseAOCEChargingUnit(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+int ParseAOCDCurrencyInfo(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+int ParseAOCDChargingUnitInfo(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+int ParseRecordedCurrency(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+int ParseRecordedUnitsList(struct asn1_parm *pc,u_char *p, u_char *end, int *recordedUnits);
+int ParseTypeOfChargingInfo(struct asn1_parm *pc,u_char *p, u_char *end, int *typeOfChargingInfo);
+int ParseRecordedUnits(struct asn1_parm *pc,u_char *p, u_char *end, int *recordedUnits);
+int ParseAOCDBillingId(struct asn1_parm *pc, u_char *p, u_char *end, int *billingId);
+int ParseAOCECurrencyInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
+int ParseAOCEChargingUnitInfo(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+int ParseAOCEBillingId(struct asn1_parm *pc,u_char *p, u_char *end, int *billingId);
+int ParseCurrency(struct asn1_parm *pc,u_char *p, u_char *end, char *currency);
+int ParseAmount(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+int ParseCurrencyAmount(struct asn1_parm *pc,u_char *p, u_char *end, int *currencyAmount);
+int ParseMultiplier(struct asn1_parm *pc,u_char *p, u_char *end, int *multiplier);
+int ParseTypeOfUnit(struct asn1_parm *pc,u_char *p, u_char *end, int *typeOfUnit);
+int ParseNumberOfUnits(struct asn1_parm *pc,u_char *p, u_char *end, int *numberOfUnits);
+int ParseChargingAssociation(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+int ParseChargeIdentifier(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_basic_service.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_basic_service.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_basic_service.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,16 @@
+/* $Id: asn1_basic_service.c,v 1.0 2001/11/02 23:42:26 kkeil Exp $
+ *
+ */
+
+#include "asn1.h"
+#include "asn1_generic.h"
+#include "asn1_basic_service.h"
+
+// ======================================================================
+// Basic Service Elements EN 300 196-1 D.6
+
+int ParseBasicService(struct asn1_parm *pc, u_char *p, u_char *end, int *basicService)
+{
+	return ParseEnum(pc, p, end, basicService);
+}
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_basic_service.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_basic_service.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_basic_service.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,9 @@
+/* $Id: asn1_basic_service.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
+ *
+ */
+
+// ======================================================================
+// Basic Service Elements EN 300 196-1 D.6
+
+int ParseBasicService(struct asn1_parm *pc, u_char *p, u_char *end, int *basicService);
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_comp.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_comp.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_comp.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,223 @@
+/* $Id: asn1_comp.c,v 1.3 2006/11/14 12:17:02 crich Exp $
+ *
+ */
+
+#include "asn1.h"
+#include "asn1_comp.h"
+#include "asn1_generic.h"
+#include "asn1_aoc.h"
+#include "asn1_diversion.h"
+
+// ======================================================================
+// Component EN 300 196-1 D.1
+
+int
+ParseInvokeId(struct asn1_parm *pc, u_char *p, u_char *end, int *invokeId)
+{
+	return ParseInteger(pc, p, end, invokeId);
+}
+
+int
+ParseErrorValue(struct asn1_parm *pc, u_char *p, u_char *end, int *errorValue)
+{
+	return ParseInteger(pc, p, end, errorValue);
+}
+
+int
+ParseOperationValue(struct asn1_parm *pc, u_char *p, u_char *end, int *operationValue)
+{
+	return ParseInteger(pc, p, end, operationValue);
+}
+
+int
+ParseInvokeComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int invokeId, operationValue;
+	INIT;
+
+	pc->comp = invoke;
+	XSEQUENCE_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
+//	XSEQUENCE_OPT(ParseLinkedId, ASN1_TAG_INTEGER, 0);
+	XSEQUENCE_1(ParseOperationValue, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &operationValue);
+	pc->u.inv.invokeId = invokeId;
+	pc->u.inv.operationValue = operationValue;
+	switch (operationValue) {
+#if 0
+	case 7:	 XSEQUENCE(ParseARGActivationDiversion, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+	case 8:	 XSEQUENCE(ParseARGDeactivationDiversion, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+#endif
+ 	case 9:	 XSEQUENCE_1(ParseARGActivationStatusNotificationDiv, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &pc->u.inv.o.actNot); break;
+ 	case 10: XSEQUENCE_1(ParseARGDeactivationStatusNotificationDiv, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &pc->u.inv.o.deactNot); break;
+#if 0
+ 	case 11: XSEQUENCE(ParseARGInterrogationDiversion, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+ 	case 12: XSEQUENCE(ParseARGDiversionInformation, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+ 	case 17: XSEQUENCE(ParseARGInterrogateServedUserNumbers, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+//	case 30: XSEQUENCE(ParseChargingRequest, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+//	case 31: XSEQUENCE(ParseAOCSCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+//	case 32: XSEQUENCE(ParseAOCSSpecialArr, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+	case 33: XSEQUENCE(ParseAOCDCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+	case 34: XSEQUENCE(ParseAOCDChargingUnit, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+	case 35: XSEQUENCE(ParseAOCECurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+	case 36: XSEQUENCE(ParseAOCEChargingUnit, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
+#endif
+	default:
+		return -1;
+	}
+
+	return p - beg;
+}
+
+int
+ParseReturnResultComponentSequence(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int operationValue;
+	INIT;
+
+	XSEQUENCE_1(ParseOperationValue, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &operationValue);
+	switch (operationValue) {
+ 	case 11: XSEQUENCE(ParseRESInterrogationDiversion, ASN1_TAG_SET, ASN1_NOT_TAGGED); break;
+ 	case 17: XSEQUENCE(ParseRESInterrogateServedUserNumbers, ASN1_TAG_SET, ASN1_NOT_TAGGED); break;
+	default: return -1;
+	}
+		
+	return p - beg;
+}
+
+int
+ParseReturnResultComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int invokeId;
+	INIT;
+
+	pc->comp = returnResult;
+	XSEQUENCE_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
+	XSEQUENCE_OPT(ParseReturnResultComponentSequence, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
+	pc->u.retResult.invokeId = invokeId;
+
+	return p - beg;
+}
+
+int
+ParseReturnErrorComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+        int invokeId;
+        int errorValue;
+        char error[80];
+        INIT;
+
+	pc->comp = returnError;
+
+	XSEQUENCE_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
+	XSEQUENCE_1(ParseErrorValue, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &errorValue);
+
+	pc->u.retError.invokeId = invokeId;
+	pc->u.retError.errorValue = errorValue;
+
+	switch (errorValue) {
+		case 0: sprintf(error, "not subscribed"); break;
+		case 3: sprintf(error, "not available"); break;
+		case 4: sprintf(error, "not implemented"); break;
+		case 6: sprintf(error, "invalid served user nr"); break;
+		case 7: sprintf(error, "invalid call state"); break;
+		case 8: sprintf(error, "basic service not provided"); break;
+		case 9: sprintf(error, "not incoming call"); break;
+		case 10: sprintf(error, "supplementary service interaction not allowed"); break;
+		case 11: sprintf(error, "resource unavailable"); break;
+		case 12: sprintf(error, "invalid diverted-to nr"); break;
+		case 14: sprintf(error, "special service nr"); break;
+		case 15: sprintf(error, "diversion to served user nr"); break;
+		case 23: sprintf(error, "incoming call accepted"); break;
+		case 24: sprintf(error, "number of diversions exceeded"); break;
+		case 46: sprintf(error, "not activated"); break;
+		case 48: sprintf(error, "request already accepted"); break;
+		default: sprintf(error, "(%d)", errorValue); break;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, "ReturnError: %s\n", error);
+
+	return p - beg;
+}
+
+int
+ParseProblemValue(struct asn1_parm *pc, u_char *p, u_char *end, asn1Problem prob)
+{
+	INIT;
+	
+	pc->u.reject.problem = prob;
+	
+	print_asn1msg(PRT_DEBUG_DECODE, "ParseProblemValue: %d %d\n", prob, *p);
+	pc->u.reject.problemValue = *p++;
+	return p - beg;
+}
+
+int
+ParseRejectProblem(struct asn1_parm *pc, u_char *p, u_char *end)
+{
+        INIT;
+
+	XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 0, GeneralP);
+	XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 1, InvokeP);
+	XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 2, ReturnResultP);
+	XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 3, ReturnErrorP);
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseRejectComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+        int invokeId = -1;
+        int rval;
+        INIT;
+
+	pc->comp = reject;
+
+	XSEQUENCE_OPT_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
+	XSEQUENCE_OPT(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED);
+	
+	print_asn1msg(PRT_DEBUG_DECODE, "ParseRejectComponent: invokeId %d\n", invokeId);
+
+	pc->u.reject.invokeId = invokeId;
+	
+	rval = ParseRejectProblem(pc, p, end);
+
+	print_asn1msg(PRT_DEBUG_DECODE, "ParseRejectComponent: rval %d\n", rval);
+
+	if (rval > 0)
+		p += rval;
+	else
+		return(-1);
+
+	return p - beg;
+}
+
+int
+ParseUnknownComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	//int invokeId;
+	INIT;
+	
+	pc->comp = tag;
+	return end - beg;
+}
+
+int
+ParseComponent(struct asn1_parm *pc, u_char *p, u_char *end)
+{
+        INIT;
+
+	XCHOICE(ParseInvokeComponent, ASN1_TAG_SEQUENCE, 1);
+	XCHOICE(ParseReturnResultComponent, ASN1_TAG_SEQUENCE, 2);
+	XCHOICE(ParseReturnErrorComponent, ASN1_TAG_SEQUENCE, 3);
+	XCHOICE(ParseRejectComponent, ASN1_TAG_SEQUENCE, 4);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 5);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 6);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 7);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 8);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 9);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 10);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 11);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 12);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 13);
+	XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 14);
+	XCHOICE_DEFAULT;
+}
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_comp.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_comp.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_comp.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,13 @@
+/* $Id: asn1_comp.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
+ *
+ */
+
+#include "asn1.h"
+
+int ParseInvokeId(struct asn1_parm *parm, u_char *p, u_char *end, int *invokeId);
+int ParseOperationValue(struct asn1_parm *parm, u_char *p, u_char *end, int *operationValue);
+int ParseInvokeComponent(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseReturnResultComponent(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseComponent(struct asn1_parm *parm, u_char *p, u_char *end);
+int XParseComponent(struct asn1_parm *parm, u_char *p, u_char *end);
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_diversion.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_diversion.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_diversion.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,248 @@
+/* $Id: asn1_diversion.c,v 1.1 2003/11/09 09:12:28 keil Exp $
+ *
+ */
+
+#include "asn1.h"
+#include "asn1_generic.h"
+#include "asn1_address.h"
+#include "asn1_basic_service.h"
+#include "asn1_diversion.h"
+
+// ======================================================================
+// Diversion Supplementary Services ETS 300 207-1 Table 3
+
+#if 0
+int
+ParseARGActivationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int procedure, basicService;
+	struct ServedUserNr servedUserNr;
+	struct Address address;
+	INIT;
+
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &procedure);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
+	XSEQUENCE_1(ParseAddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &address);
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
+
+	return p - beg;
+}
+
+int
+ParseARGDeactivationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int procedure, basicService;
+	struct ServedUserNr servedUserNr;
+	INIT;
+
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &procedure);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
+
+	print_asn1msg(PRT_SHOWNUMBERS, "Deactivation Diversion %d (%d), \n",
+		  procedure, basicService);
+	return p - beg;
+}
+#endif
+
+int
+ParseARGActivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct ActDivNotification *actNot)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &actNot->procedure);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &actNot->basicService);
+	XSEQUENCE_1(ParseAddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &actNot->address);
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &actNot->servedUserNr);
+
+	return p - beg;
+}
+
+int
+ParseARGDeactivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct DeactDivNotification *deactNot)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &deactNot->procedure);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &deactNot->basicService);
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &deactNot->servedUserNr);
+
+	return p - beg;
+}
+
+#if 0
+int 
+ParseARGInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int procedure, basicService;
+	struct ServedUserNr servedUserNr;
+	INIT;
+
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &procedure);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
+
+	print_asn1msg(PRT_SHOWNUMBERS, "Interrogation Diversion %d (%d), \n",
+		procedure, basicService);
+	return p - beg;
+}
+#endif
+
+int 
+ParseRESInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	print_asn1msg(PRT_SHOWNUMBERS, "Interrogation Diversion Result\n");
+	return ParseIntResultList(pc, p,  end, &pc->u.retResult.o.resultList);
+}
+
+#if 0
+int 
+ParseARGInterrogateServedUserNumbers(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	print_asn1msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers\n");
+	return 0;
+}
+#endif
+
+int 
+ParseRESInterrogateServedUserNumbers(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	int ret;
+
+	ret = ParseServedUserNumberList(pc, p, end, &pc->u.retResult.o.list);
+	if (ret < 0)
+		return ret;
+
+	print_asn1msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers:\n");
+	
+	return ret;
+}
+
+int 
+ParseARGDiversionInformation(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	char diversionReason[20];
+	int basicService;
+	char servedUserSubaddress[30];
+	char callingAddress[80];
+	char originalCalledNr[80];
+	char lastDivertingNr[80];
+	char lastDivertingReason[20];
+	INIT;
+	
+	servedUserSubaddress[0] = 0;
+	callingAddress[0] = 0;
+	originalCalledNr[0] = 0;
+	lastDivertingNr[0] = 0;
+	lastDivertingReason[0] = 0;
+
+	XSEQUENCE_1(ParseDiversionReason, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, diversionReason);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
+	XSEQUENCE_OPT_1(ParsePartySubaddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, servedUserSubaddress);
+	XSEQUENCE_OPT_1(ParsePresentedAddressScreened, ASN1_NOT_TAGGED, 0 | ASN1_TAG_EXPLICIT, callingAddress);
+	XSEQUENCE_OPT_1(ParsePresentedNumberUnscreened, ASN1_NOT_TAGGED, 1 | ASN1_TAG_EXPLICIT, originalCalledNr);
+	XSEQUENCE_OPT_1(ParsePresentedNumberUnscreened, ASN1_NOT_TAGGED, 2 | ASN1_TAG_EXPLICIT, lastDivertingNr);
+	XSEQUENCE_OPT_1(ParseDiversionReason, ASN1_TAG_ENUM, 3 | ASN1_TAG_EXPLICIT, lastDivertingReason);
+//	XSEQUENCE_OPT_1(ParseQ931InformationElement, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, userInfo);
+	print_asn1msg(PRT_SHOWNUMBERS, "Diversion Information %s(%d) %s\n"
+		  "  callingAddress %s originalCalled Nr %s\n"
+		  "  lastDivertingNr %s lastDiverting Reason %s\n",
+		  diversionReason, basicService, servedUserSubaddress, callingAddress,
+		  originalCalledNr, lastDivertingNr, lastDivertingReason);
+	return p - beg;
+}
+
+int 
+ParseIntResultList(struct asn1_parm *pc, u_char *p, u_char *end, struct IntResultList *intResultList)
+{
+	int i;
+	INIT;
+
+	for (i = 0; i < 10; i++) {
+		intResultList->intResult[i].basicService = -1;
+		XSEQUENCE_OPT_1(ParseIntResult, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, 
+				&intResultList->intResult[i] );
+	}
+
+	return p - beg;
+}
+
+int 
+ParseIntResult(struct asn1_parm *pc, u_char *p, u_char *end, struct IntResult *intResult)
+{
+	INIT;
+
+	XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &intResult->servedUserNr);
+	XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &intResult->basicService);
+	XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &intResult->procedure);
+	XSEQUENCE_1(ParseAddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &intResult->address);
+
+	return p - beg;
+}
+
+int
+ParseServedUserNrAll(struct asn1_parm *pc, u_char *p, u_char *end, struct ServedUserNr *servedUserNr)
+{
+	int ret;
+
+	ret = ParseNull(pc, p, end, 0);
+	if (ret < 0)
+		return ret;
+	servedUserNr->all = 1;
+
+	return ret;
+}
+
+int
+ParseServedUserNr(struct asn1_parm *pc, u_char *p, u_char *end, struct ServedUserNr *servedUserNr)
+{
+	INIT;
+
+	servedUserNr->all = 0;
+	XCHOICE_1(ParseServedUserNrAll, ASN1_TAG_NULL, ASN1_NOT_TAGGED, servedUserNr);
+	XCHOICE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr->partyNumber);
+	XCHOICE_DEFAULT;
+}
+
+int
+ParseProcedure(struct asn1_parm *pc, u_char *p, u_char *end, int *procedure)
+{
+	return ParseEnum(pc, p, end, procedure);
+}
+
+int ParseServedUserNumberList(struct asn1_parm *pc, u_char *p, u_char *end, struct ServedUserNumberList *list)
+{
+	int i;
+	INIT;
+
+	for (i = 0; i < 10; i++) {
+		list->partyNumber[i].type = -1;
+		XSEQUENCE_OPT_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &list->partyNumber[i]);
+	}
+
+	return p - beg;
+}
+
+int
+ParseDiversionReason(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	int ret;
+	int diversionReason;
+
+	ret = ParseEnum(pc, p, end, &diversionReason);
+	if (ret < 0)
+		return ret;
+	
+	switch (diversionReason) {
+	case 0: sprintf(str, "unknown"); break;
+	case 1: sprintf(str, "CFU"); break;
+	case 2: sprintf(str, "CFB"); break;
+	case 3: sprintf(str, "CFNR"); break;
+	case 4: sprintf(str, "CD (Alerting)"); break;
+	case 5: sprintf(str, "CD (Immediate)"); break;
+	default: sprintf(str, "(%d)", diversionReason); break;
+	}
+
+	return ret;
+}
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_diversion.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_diversion.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_diversion.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,22 @@
+/* $Id: asn1_diversion.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
+ *
+ */
+
+#if 0
+int ParseARGActivationDiversion(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseARGDeactivationDiversion(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+#endif
+int ParseARGActivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct ActDivNotification *actNot);
+int ParseARGDeactivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct DeactDivNotification *deactNot);
+int ParseARGInterrogationDiversion(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseRESInterrogationDiversion(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseARGInterrogateServedUserNumbers(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseRESInterrogateServedUserNumbers(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseARGDiversionInformation(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
+int ParseIntResult(struct asn1_parm *parm, u_char *p, u_char *end, struct IntResult *intResult);
+int ParseIntResultList(struct asn1_parm *parm, u_char *p, u_char *end, struct IntResultList *intResultList);
+int ParseServedUserNr(struct asn1_parm *parm, u_char *p, u_char *end, struct ServedUserNr *servedUserNr);
+int ParseProcedure(struct asn1_parm *pc, u_char *p, u_char *end, int *procedure);
+int ParseServedUserNumberList(struct asn1_parm *parm, u_char *p, u_char *end, struct ServedUserNumberList *list);
+int ParseDiversionReason(struct asn1_parm *parm, u_char *p, u_char *end, char *str);
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_enc.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_enc.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_enc.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,201 @@
+/* $Id: asn1_enc.c,v 1.4 2006/03/06 12:52:07 keil Exp $
+ *
+ */
+
+#include "m_capi.h"
+#include "helper.h"
+#include "asn1_enc.h"
+
+int encodeNull(__u8 *dest)
+{
+	dest[0] = 0x05;  // null
+	dest[1] = 0;     // length
+	return 2;
+}
+
+int encodeBoolean(__u8 *dest, __u32 i)
+{
+	dest[0] = 0x01;  // BOOLEAN
+	dest[1] = 1;     // length 1
+	dest[3] = i ? 1:0;  // Value
+	return 3;
+}
+
+int encodeInt(__u8 *dest, __u32 i)
+{
+	__u8 *p;
+
+	dest[0] = 0x02;  // integer
+	dest[1] = 0;     // length
+	p = &dest[2];
+	do {
+		*p++ = i;
+		i >>= 8;
+	} while (i);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeEnum(__u8 *dest, __u32 i)
+{
+	__u8 *p;
+
+	dest[0] = 0x0a;  // integer
+	dest[1] = 0;     // length
+	p = &dest[2];
+	do {
+		*p++ = i;
+		i >>= 8;
+	} while (i);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeNumberDigits(__u8 *dest, __u8 *nd, __u8 len)
+{
+	__u8 *p;
+	int i;
+
+	dest[0] = 0x12;    // numeric string
+	dest[1] = 0x0;     // length
+	p = &dest[2];
+	for (i = 0; i < len; i++)
+		*p++ = *nd++;
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodePublicPartyNumber(__u8 *dest, __u8 *facilityPartyNumber)
+{
+	__u8 *p;
+
+	dest[0] = 0x20;  // sequence
+	dest[1] = 0;     // length
+	p = &dest[2];
+	p += encodeEnum(p, (facilityPartyNumber[2] & 0x70) >> 4);
+	p += encodeNumberDigits(p, &facilityPartyNumber[4], facilityPartyNumber[0] - 3);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodePartyNumber(__u8 *dest, __u8 *facilityPartyNumber)
+{
+	__u8 *p = dest;
+
+	p = dest;
+	switch (facilityPartyNumber[1]) {
+	case 0: // unknown
+		p += encodeNumberDigits(p, &facilityPartyNumber[4], facilityPartyNumber[0] - 3);
+		dest[0] &= 0x20;
+		dest[0] |= 0x81;
+		break;
+	case 1: // publicPartyNumber
+		p += encodePublicPartyNumber(p, facilityPartyNumber);
+		dest[0] &= 0x20;
+		dest[0] |= 0x81;
+		break;
+	default:
+		int_error();
+		return -1;
+	}
+	return p - dest;
+}
+
+int encodeServedUserNumber(__u8 *dest, __u8 *servedUserNumber)
+{
+	if (servedUserNumber[0])
+		return encodePartyNumber(dest, servedUserNumber);
+        else
+		return encodeNull(dest);
+}
+
+int encodeAddress(__u8 *dest, __u8 *facilityPartyNumber, __u8 *calledPartySubaddress)
+{
+	__u8 *p = dest;
+
+	dest[0] = 0x30;  // invoke id tag, integer
+	dest[1] = 0;     // length
+	p = &dest[2];
+
+	p += encodePartyNumber(p, facilityPartyNumber);
+#if 0 // FIXME
+	if (calledPartySubaddress[0])
+		p += encodePartySubaddress(p, calledPartySubaddress);
+#endif
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeActivationDiversion(__u8 *dest, struct FacReqCFActivate *CFActivate)
+{
+	__u8 *p;
+
+	dest[0] = 0x30;  // sequence
+	dest[1] = 0;     // length
+	p = &dest[2];
+
+	p += encodeEnum(p, CFActivate->Procedure);
+	p += encodeEnum(p, CFActivate->BasicService);
+	p += encodeAddress(p, CFActivate->ForwardedToNumber, CFActivate->ForwardedToSubaddress);
+	p += encodeServedUserNumber(p, CFActivate->ServedUserNumber);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeDeactivationDiversion(__u8 *dest, struct FacReqCFDeactivate *CFDeactivate)
+{
+	__u8 *p;
+
+	dest[0] = 0x30;  // sequence
+	dest[1] = 0;     // length
+	p = &dest[2];
+
+	p += encodeEnum(p, CFDeactivate->Procedure);
+	p += encodeEnum(p, CFDeactivate->BasicService);
+	p += encodeServedUserNumber(p, CFDeactivate->ServedUserNumber);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeInterrogationDiversion(__u8 *dest, struct FacReqCFInterrogateParameters *params)
+{
+	__u8 *p;
+
+	dest[0] = 0x30;  // sequence
+	dest[1] = 0;     // length
+	p = &dest[2];
+
+	p += encodeEnum(p, params->Procedure);
+#if 0
+	if (basicService == 0)
+		p += encodeNull(p);
+	else
+#endif
+	p += encodeEnum(p, params->BasicService);
+	p += encodeServedUserNumber(p, params->ServedUserNumber);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+
+int encodeInvokeDeflection(__u8 *dest, struct FacReqCDeflection *CD)
+{
+	__u8 *p;
+
+	dest[0] = 0x30;  // sequence
+	dest[1] = 0;     // length
+	p = &dest[2];
+
+	p += encodeAddress(p, CD->DeflectedToNumber, CD->DeflectedToSubaddress);
+	p += encodeBoolean(p, CD->PresentationAllowed);
+
+	dest[1] = p - &dest[2];
+	return p - dest;
+}
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_enc.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_enc.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_enc.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,19 @@
+/* $Id: asn1_enc.h,v 1.1 2006/03/06 12:52:07 keil Exp $
+ *
+ */
+
+#include "asn1.h"
+
+int encodeNull(__u8 *dest);
+int encodeBoolean(__u8 *dest, __u32 i);
+int encodeInt(__u8 *dest, __u32 i);
+int encodeEnum(__u8 *dest, __u32 i);
+int encodeNumberDigits(__u8 *dest, __u8 *nd, __u8 len);
+int encodePublicPartyNumber(__u8 *dest, __u8 *facilityPartyNumber);
+int encodePartyNumber(__u8 *dest, __u8 *facilityPartyNumber);
+int encodeServedUserNumber(__u8 *dest, __u8 *servedUserNumber);
+int encodeAddress(__u8 *dest, __u8 *facilityPartyNumber, __u8 *calledPartySubaddress);
+int encodeActivationDiversion(__u8 *dest, struct FacReqCFActivate *CFActivate);
+int encodeDeactivationDiversion(__u8 *dest,struct FacReqCFDeactivate *CFDeactivate);
+int encodeInterrogationDiversion(__u8 *dest, struct FacReqCFInterrogateParameters *params);
+int encodeInvokeDeflection(__u8 *dest, struct FacReqCDeflection *CD);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_generic.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_generic.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_generic.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,115 @@
+/* $Id: asn1_generic.c,v 1.1 2003/11/09 09:12:28 keil Exp $
+ *
+ */
+
+#include "asn1.h"
+#include "asn1_generic.h"
+
+// ======================================================================
+// general ASN.1
+
+int
+ParseBoolean(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
+{
+	INIT;
+
+	*i = 0;
+	while (len--) {
+		CHECK_P;
+		*i = (*i >> 8) + *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> BOOL = %d %#x\n", *i, *i);
+	return p - beg;
+}
+
+int
+ParseNull(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
+{
+	INIT;
+
+	return p - beg;
+}
+
+int
+ParseInteger(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
+{
+	INIT;
+
+	*i = 0;
+	while (len--) {
+		CHECK_P;
+		*i = (*i << 8) + *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> INT = %d %#x\n", *i, *i);
+	return p - beg;
+}
+
+int
+ParseEnum(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
+{
+	INIT;
+
+	*i = 0;
+	while (len--) {
+		CHECK_P;
+		*i = (*i << 8) + *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> ENUM = %d %#x\n", *i, *i);
+	return p - beg;
+}
+
+#if 0
+int
+ParseIA5String(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> IA5 = ");
+	while (len--) {
+		CHECK_P;
+		print_asn1msg(PRT_DEBUG_DECODE, "%c", *p);
+		*str++ = *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, "\n");
+	*str = 0;
+	return p - beg;
+}
+#endif
+
+int
+ParseNumericString(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> NumStr = ");
+	while (len--) {
+		CHECK_P;
+		print_asn1msg(PRT_DEBUG_DECODE, "%c", *p);
+		*str++ = *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, "\n");
+	*str = 0;
+	return p - beg;
+}
+
+int
+ParseOctetString(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
+{
+	INIT;
+
+	print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> Octets = ");
+	while (len--) {
+		CHECK_P;
+		print_asn1msg(PRT_DEBUG_DECODE, " %02x", *p);
+		*str++ = *p;
+		p++;
+	}
+	print_asn1msg(PRT_DEBUG_DECODE, "\n");
+	*str = 0;
+	return p - beg;
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_generic.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_generic.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/asn1_generic.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,17 @@
+/* $Id: asn1_generic.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
+ *
+ */
+
+#include "asn1.h"
+
+// ======================================================================
+// general ASN.1
+
+int ParseBoolean(struct asn1_parm *pc, u_char *p, u_char *end, int *i);
+int ParseNull(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
+int ParseInteger(struct asn1_parm *pc, u_char *p, u_char *end, int *i);
+int ParseEnum(struct asn1_parm *pc, u_char *p, u_char *end, int *i);
+int ParseIA5String(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseNumericString(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+int ParseOctetString(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/avm_fritz.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/avm_fritz.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/avm_fritz.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1490 @@
+/* $Id: avm_fritz.c,v 1.43 2007/02/13 10:43:45 crich Exp $
+ *
+ * fritz_pci.c    low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
+ *              Thanks to AVM, Berlin for informations
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#ifdef NEW_ISAPNP
+#include <linux/pnp.h>
+#else
+#include <linux/isapnp.h>
+#endif
+#include <linux/delay.h>
+#include "core.h"
+#include "channel.h"
+#include "isac.h"
+#include "layer1.h"
+#include "debug.h"
+
+
+static const char *avm_fritz_rev = "$Revision: 1.43 $";
+
+enum {
+	AVM_FRITZ_PCI,
+	AVM_FRITZ_PNP,
+	AVM_FRITZ_PCIV2,
+};
+
+#ifndef PCI_VENDOR_ID_AVM
+#define PCI_VENDOR_ID_AVM	0x1244
+#endif
+#ifndef PCI_DEVICE_ID_AVM_FRITZ
+#define PCI_DEVICE_ID_AVM_FRITZ	0xa00
+#endif
+#ifndef PCI_DEVICE_ID_AVM_A1_V2
+#define PCI_DEVICE_ID_AVM_A1_V2	0xe00
+#endif
+
+#define HDLC_FIFO		0x0
+#define HDLC_STATUS		0x4
+#define CHIP_WINDOW		0x10
+
+#define CHIP_INDEX		0x4
+#define AVM_HDLC_1		0x00
+#define AVM_HDLC_2		0x01
+#define AVM_ISAC_FIFO		0x02
+#define AVM_ISAC_REG_LOW	0x04
+#define AVM_ISAC_REG_HIGH	0x06
+
+#define AVM_STATUS0_IRQ_ISAC	0x01
+#define AVM_STATUS0_IRQ_HDLC	0x02
+#define AVM_STATUS0_IRQ_TIMER	0x04
+#define AVM_STATUS0_IRQ_MASK	0x07
+
+#define AVM_STATUS0_RESET	0x01
+#define AVM_STATUS0_DIS_TIMER	0x02
+#define AVM_STATUS0_RES_TIMER	0x04
+#define AVM_STATUS0_ENA_IRQ	0x08
+#define AVM_STATUS0_TESTBIT	0x10
+
+#define AVM_STATUS1_INT_SEL	0x0f
+#define AVM_STATUS1_ENA_IOM	0x80
+
+#define HDLC_MODE_ITF_FLG	0x01
+#define HDLC_MODE_TRANS	0x02
+#define HDLC_MODE_CCR_7	0x04
+#define HDLC_MODE_CCR_16	0x08
+#define HDLC_MODE_TESTLOOP	0x80
+
+#define HDLC_INT_XPR		0x80
+#define HDLC_INT_XDU		0x40
+#define HDLC_INT_RPR		0x20
+#define HDLC_INT_MASK		0xE0
+
+#define HDLC_STAT_RME		0x01
+#define HDLC_STAT_RDO		0x10
+#define HDLC_STAT_CRCVFRRAB	0x0E
+#define HDLC_STAT_CRCVFR	0x06
+#define HDLC_STAT_RML_MASK	0x3f00
+
+#define HDLC_CMD_XRS		0x80
+#define HDLC_CMD_XME		0x01
+#define HDLC_CMD_RRS		0x20
+#define HDLC_CMD_XML_MASK	0x3f00
+
+/* Fritz PCI v2.0 */
+
+#define  AVM_HDLC_FIFO_1        0x10
+#define  AVM_HDLC_FIFO_2        0x18
+
+#define  AVM_HDLC_STATUS_1      0x14
+#define  AVM_HDLC_STATUS_2      0x1c
+
+#define  AVM_ISACSX_INDEX       0x04
+#define  AVM_ISACSX_DATA        0x08
+
+/* data struct */
+
+struct hdlc_stat_reg {
+#ifdef __BIG_ENDIAN
+	u_char fill;
+	u_char mode;
+	u_char xml;
+	u_char cmd;
+#else
+	u_char cmd;
+	u_char xml;
+	u_char mode;
+	u_char fill;
+#endif
+} __attribute__((packed));
+
+typedef struct hdlc_hw {
+	union {
+		u_int ctrl;
+		struct hdlc_stat_reg sr;
+	} ctrl;
+	u_int stat;
+} hdlc_hw_t;
+
+
+typedef struct _fritzpnppci {
+	struct list_head	list;
+	union {
+#if defined(CONFIG_PNP)
+#ifdef NEW_ISAPNP
+		struct pnp_dev	*pnp;
+#else
+		struct pci_dev	*pnp;
+#endif
+#endif
+		struct pci_dev	*pci;
+	}			dev;
+	u_int			type;
+	u_int			irq;
+	u_int			irqcnt;
+	u_int			addr;
+	spinlock_t		lock;
+	isac_chip_t		isac;
+	hdlc_hw_t		hdlc[2];
+	channel_t		dch;
+	channel_t		bch[2];
+	u_char			ctrlreg;
+} fritzpnppci;
+
+
+/* Interface functions */
+
+static u_char
+ReadISAC(void *fc, u_char offset)
+{
+	register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
+	register long addr = ((fritzpnppci *)fc)->addr;
+	register u_char val;
+
+	outb(idx, addr + CHIP_INDEX);
+	val = inb(addr + CHIP_WINDOW + (offset & 0xf));
+	return (val);
+}
+
+static void
+WriteISAC(void *fc, u_char offset, u_char value)
+{
+	register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
+	register long addr = ((fritzpnppci *)fc)->addr;
+
+	outb(idx, addr + CHIP_INDEX);
+	outb(value, addr + CHIP_WINDOW + (offset & 0xf));
+}
+
+static void
+ReadISACfifo(void *fc, u_char * data, int size)
+{
+	register long addr = ((fritzpnppci *)fc)->addr;
+
+	outb(AVM_ISAC_FIFO, addr + CHIP_INDEX);
+	insb(addr + CHIP_WINDOW, data, size);
+}
+
+static void
+WriteISACfifo(void *fc, u_char * data, int size)
+{
+	register long addr = ((fritzpnppci *)fc)->addr;
+
+	outb(AVM_ISAC_FIFO, addr + CHIP_INDEX);
+	outsb(addr + CHIP_WINDOW, data, size);
+}
+
+static unsigned char
+fcpci2_read_isac(void *fc, unsigned char offset)
+{
+	register long addr = ((fritzpnppci *)fc)->addr;
+	unsigned char val;
+
+	outl(offset, addr + AVM_ISACSX_INDEX);
+	val = inl(addr + AVM_ISACSX_DATA);
+	return val;
+}
+
+static void
+fcpci2_write_isac(void *fc, unsigned char offset, unsigned char value)
+{
+	register long addr = ((fritzpnppci *)fc)->addr;
+
+	outl(offset, addr + AVM_ISACSX_INDEX);
+	outl(value, addr + AVM_ISACSX_DATA);
+}
+
+static void
+fcpci2_read_isac_fifo(void *fc, unsigned char * data, int size)
+{
+	register long addr = ((fritzpnppci *)fc)->addr;
+	int i;
+
+	outl(0, addr + AVM_ISACSX_INDEX);
+	for (i = 0; i < size; i++)
+		data[i] = inl(addr + AVM_ISACSX_DATA);
+}
+
+static void
+fcpci2_write_isac_fifo(void *fc, unsigned char * data, int size)
+{
+	register long addr = ((fritzpnppci *)fc)->addr;
+	int i;
+
+	outl(0, addr + AVM_ISACSX_INDEX);
+	for (i = 0; i < size; i++)
+		outl(data[i], addr + AVM_ISACSX_DATA);
+}
+
+static inline
+channel_t *Sel_BCS(fritzpnppci *fc, int channel)
+{
+	if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) && (fc->bch[0].channel == channel))
+		return(&fc->bch[0]);
+	else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) && (fc->bch[1].channel == channel))
+		return(&fc->bch[1]);
+	else
+		return(NULL);
+}
+
+static inline void
+__write_ctrl_pnp(fritzpnppci *fc, hdlc_hw_t *hdlc, int channel, int which) {
+	register u_char idx = channel ? AVM_HDLC_2 : AVM_HDLC_1;
+
+	outb(idx, fc->addr + CHIP_INDEX);
+	if (which & 4)
+		outb(hdlc->ctrl.sr.mode, fc->addr + CHIP_WINDOW + HDLC_STATUS + 2);
+	if (which & 2)
+		outb(hdlc->ctrl.sr.xml, fc->addr + CHIP_WINDOW + HDLC_STATUS + 1);
+	if (which & 1)
+		outb(hdlc->ctrl.sr.cmd, fc->addr + CHIP_WINDOW + HDLC_STATUS);
+}
+
+static inline void
+__write_ctrl_pci(fritzpnppci *fc, hdlc_hw_t *hdlc, int channel) {
+	register u_int idx = channel ? AVM_HDLC_2 : AVM_HDLC_1;
+
+	outl(idx, fc->addr + CHIP_INDEX);
+	outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS);
+}
+
+static inline void
+__write_ctrl_pciv2(fritzpnppci *fc, hdlc_hw_t *hdlc, int channel) {
+	outl(hdlc->ctrl.ctrl, fc->addr + (channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1));
+}
+
+void
+write_ctrl(channel_t *bch, int which) {
+	fritzpnppci	*fc = bch->inst.privat;
+	hdlc_hw_t	*hdlc = bch->hw;
+
+	if (fc->dch.debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "hdlc %c wr%x ctrl %x",
+			'A' + bch->channel, which, hdlc->ctrl.ctrl);
+	switch(fc->type) {
+		case AVM_FRITZ_PCIV2:
+			__write_ctrl_pciv2(fc, hdlc, bch->channel);
+			break;
+		case AVM_FRITZ_PCI:
+			__write_ctrl_pci(fc, hdlc, bch->channel);
+			break;
+		case AVM_FRITZ_PNP:
+			__write_ctrl_pnp(fc, hdlc, bch->channel, which);
+			break;
+	}
+}
+
+
+static inline u_int
+__read_status_pnp(u_long addr, u_int channel)
+{
+	register u_int stat;
+
+	outb(channel ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX);
+	stat = inb(addr + CHIP_WINDOW + HDLC_STATUS);
+	if (stat & HDLC_INT_RPR)
+		stat |= (inb(addr + CHIP_WINDOW + HDLC_STATUS + 1)) << 8;
+	return (stat);
+}
+
+static inline u_int
+__read_status_pci(u_long addr, u_int channel)
+{
+	outl(channel ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX);
+	return inl(addr + CHIP_WINDOW + HDLC_STATUS);
+}
+
+static inline u_int
+__read_status_pciv2(u_long addr, u_int channel)
+{
+	return inl(addr + (channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1));
+}
+
+
+static u_int
+read_status(fritzpnppci *fc, int channel)
+{
+	switch(fc->type) {
+		case AVM_FRITZ_PCIV2:
+			return(__read_status_pciv2(fc->addr, channel));
+		case AVM_FRITZ_PCI:
+			return(__read_status_pci(fc->addr, channel));
+		case AVM_FRITZ_PNP:
+			return(__read_status_pnp(fc->addr, channel));
+	}
+	/* dummy */
+	return(0);
+}
+
+static void
+enable_hwirq(fritzpnppci *fc)
+{
+	fc->ctrlreg |= AVM_STATUS0_ENA_IRQ;
+	outb(fc->ctrlreg, fc->addr + 2);
+}
+
+static void
+disable_hwirq(fritzpnppci *fc)
+{
+	fc->ctrlreg &= ~((u_char)AVM_STATUS0_ENA_IRQ);
+	outb(fc->ctrlreg, fc->addr + 2);
+}
+
+static int
+modehdlc(channel_t *bch, int bc, int protocol)
+{
+	hdlc_hw_t	*hdlc = bch->hw;
+
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "hdlc %c protocol %x-->%x ch %d-->%d",
+			'A' + bch->channel, bch->state, protocol, bch->channel, bc);
+	if ((protocol != -1) && (bc != bch->channel))
+		printk(KERN_WARNING "%s: fritzcard mismatch channel(%d/%d)\n", __FUNCTION__, bch->channel, bc);
+	hdlc->ctrl.ctrl = 0;
+	switch (protocol) {
+		case (-1): /* used for init */
+			bch->state = -1;
+			bch->channel = bc;
+		case (ISDN_PID_NONE):
+			if (bch->state == ISDN_PID_NONE)
+				break;
+			hdlc->ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
+			hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
+			write_ctrl(bch, 5);
+			bch->state = ISDN_PID_NONE;
+			test_and_clear_bit(FLG_HDLC, &bch->Flags);
+			test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
+			break;
+		case (ISDN_PID_L1_B_64TRANS):
+			bch->state = protocol;
+			hdlc->ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
+			hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
+			write_ctrl(bch, 5);
+			hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
+			write_ctrl(bch, 1);
+			hdlc->ctrl.sr.cmd = 0;
+			test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
+			break;
+		case (ISDN_PID_L1_B_64HDLC):
+			bch->state = protocol;
+			hdlc->ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
+			hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+			write_ctrl(bch, 5);
+			hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
+			write_ctrl(bch, 1);
+			hdlc->ctrl.sr.cmd = 0;
+			test_and_set_bit(FLG_HDLC, &bch->Flags);
+			break;
+		default:
+			mISDN_debugprint(&bch->inst, "prot not known %x", protocol);
+			return(-ENOPROTOOPT);
+	}
+	return(0);
+}
+
+static void
+hdlc_empty_fifo(channel_t *bch, int count)
+{
+	register u_int *ptr;
+	u_char *p;
+	u_char idx = bch->channel ? AVM_HDLC_2 : AVM_HDLC_1;
+	int cnt=0;
+	fritzpnppci *fc = bch->inst.privat;
+
+	if ((fc->dch.debug & L1_DEB_HSCX) && !(fc->dch.debug & L1_DEB_HSCX_FIFO))
+		mISDN_debugprint(&bch->inst, "hdlc_empty_fifo %d", count);
+	if (!bch->rx_skb) {
+		if (!(bch->rx_skb = alloc_stack_skb(bch->maxlen, bch->up_headerlen))) {
+			printk(KERN_WARNING "mISDN: B receive out of memory\n");
+			return;
+		}
+	}
+	if ((bch->rx_skb->len + count) > bch->maxlen) {
+		if (bch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&bch->inst, "hdlc_empty_fifo overrun %d",
+				bch->rx_skb->len + count);
+		return;
+	}
+	p = skb_put(bch->rx_skb, count);
+	ptr = (u_int *)p;
+	if (fc->type == AVM_FRITZ_PCIV2) {
+		while (cnt < count) {
+#ifdef __powerpc__
+#ifdef CONFIG_APUS
+			*ptr++ = in_le32((unsigned *)(fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1) +_IO_BASE));
+#else
+			*ptr++ = in_be32((unsigned *)(fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1) +_IO_BASE));
+#endif /* CONFIG_APUS */
+#else
+			*ptr++ = inl(fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1));
+#endif /* __powerpc__ */
+			cnt += 4;
+		}
+	} else if (fc->type == AVM_FRITZ_PCI) {
+		outl(idx, fc->addr + CHIP_INDEX);
+		while (cnt < count) {
+#ifdef __powerpc__
+#ifdef CONFIG_APUS
+			*ptr++ = in_le32((unsigned *)(fc->addr + CHIP_WINDOW +_IO_BASE));
+#else
+			*ptr++ = in_be32((unsigned *)(fc->addr + CHIP_WINDOW +_IO_BASE));
+#endif /* CONFIG_APUS */
+#else
+			*ptr++ = inl(fc->addr + CHIP_WINDOW);
+#endif /* __powerpc__ */
+			cnt += 4;
+		}
+	} else {
+		outb(idx, fc->addr + CHIP_INDEX);
+		while (cnt < count) {
+			*p++ = inb(fc->addr + CHIP_WINDOW);
+			cnt++;
+		}
+	}
+	if (fc->dch.debug & L1_DEB_HSCX_FIFO) {
+		char *t = bch->log;
+
+		if (fc->type == AVM_FRITZ_PNP)
+			p = (u_char *) ptr;
+		t += sprintf(t, "hdlc_empty_fifo %c cnt %d",
+			     bch->channel ? 'B' : 'A', count);
+		mISDN_QuickHex(t, p, count);
+		mISDN_debugprint(&bch->inst, bch->log);
+	}
+}
+
+#define HDLC_FIFO_SIZE	32
+
+static void
+hdlc_fill_fifo(channel_t *bch)
+{
+	fritzpnppci	*fc = bch->inst.privat;
+	hdlc_hw_t	*hdlc = bch->hw;
+	int		count, cnt =0;
+	u_char		*p;
+	u_int		*ptr;
+
+	if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
+		mISDN_debugprint(&bch->inst, "%s", __FUNCTION__);
+	if (!bch->tx_skb)
+		return;
+	count = bch->tx_skb->len - bch->tx_idx;
+	if (count <= 0)
+		return;
+	p = bch->tx_skb->data + bch->tx_idx;
+	hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
+	if (count > HDLC_FIFO_SIZE) {
+		count = HDLC_FIFO_SIZE;
+	} else {
+		if (test_bit(FLG_HDLC, &bch->Flags))
+			hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
+	}
+	if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
+		mISDN_debugprint(&bch->inst, "%s: %d/%d", __FUNCTION__,
+			count, bch->tx_idx);
+	ptr = (u_int *) p;
+	bch->tx_idx += count;
+	hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count);
+	if (fc->type == AVM_FRITZ_PCIV2) {
+		__write_ctrl_pciv2(fc, hdlc, bch->channel);
+		while (cnt<count) {
+#ifdef __powerpc__
+#ifdef CONFIG_APUS
+			out_le32((unsigned *)(fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1) +_IO_BASE), *ptr++);
+#else
+			out_be32((unsigned *)(fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1) +_IO_BASE), *ptr++);
+#endif /* CONFIG_APUS */
+#else
+			outl(*ptr++, fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1));
+#endif /* __powerpc__ */
+			cnt += 4;
+		}
+	} else if (fc->type == AVM_FRITZ_PCI) {
+		__write_ctrl_pci(fc, hdlc, bch->channel);
+		while (cnt<count) {
+#ifdef __powerpc__
+#ifdef CONFIG_APUS
+			out_le32((unsigned *)(fc->addr + CHIP_WINDOW +_IO_BASE), *ptr++);
+#else
+			out_be32((unsigned *)(fc->addr + CHIP_WINDOW +_IO_BASE), *ptr++);
+#endif /* CONFIG_APUS */
+#else
+			outl(*ptr++, fc->addr + CHIP_WINDOW);
+#endif /* __powerpc__ */
+			cnt += 4;
+		}
+	} else {
+		__write_ctrl_pnp(fc, hdlc, bch->channel, 3);
+		while (cnt<count) {
+			outb(*p++, fc->addr + CHIP_WINDOW);
+			cnt++;
+		}
+	}
+	if (bch->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bch->log;
+
+		if (fc->type == AVM_FRITZ_PNP)
+			p = (u_char *) ptr;
+		t += sprintf(t, "hdlc_fill_fifo %c cnt %d",
+			     bch->channel ? 'B' : 'A', count);
+		mISDN_QuickHex(t, p, count);
+		mISDN_debugprint(&bch->inst, bch->log);
+	}
+}
+
+static void
+HDLC_irq_xpr(channel_t *bch)
+{
+	if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
+		hdlc_fill_fifo(bch);
+	else {
+		if (bch->tx_skb)
+			dev_kfree_skb(bch->tx_skb);
+		bch->tx_idx = 0;
+		if (test_bit(FLG_TX_NEXT, &bch->Flags)) {
+			bch->tx_skb = bch->next_skb;
+			if (bch->tx_skb) {
+				mISDN_head_t	*hh = mISDN_HEAD_P(bch->tx_skb);
+
+				bch->next_skb = NULL;
+				test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+				queue_ch_frame(bch, CONFIRM, hh->dinfo, NULL);
+				hdlc_fill_fifo(bch);
+			} else {
+				printk(KERN_WARNING "hdlc tx irq TX_NEXT without skb\n");
+				test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+				test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+			}
+		} else {
+			bch->tx_skb = NULL;
+			test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		}
+	}
+}
+
+static void
+HDLC_irq(channel_t *bch, u_int stat)
+{
+	int		len;
+	struct sk_buff	*skb;
+	hdlc_hw_t	*hdlc = bch->hw;
+
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "ch%d stat %#x", bch->channel, stat);
+	if (stat & HDLC_INT_RPR) {
+		if (stat & HDLC_STAT_RDO) {
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "RDO");
+			else
+				mISDN_debugprint(&bch->inst, "ch%d stat %#x", bch->channel, stat);
+			hdlc->ctrl.sr.xml = 0;
+			hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS;
+			write_ctrl(bch, 1);
+			hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
+			write_ctrl(bch, 1);
+			if (bch->rx_skb)
+				skb_trim(bch->rx_skb, 0);
+		} else {
+			if (!(len = (stat & HDLC_STAT_RML_MASK)>>8))
+				len = 32;
+			hdlc_empty_fifo(bch, len);
+			if (!bch->rx_skb)
+				goto handle_tx;
+			if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+				if (((stat & HDLC_STAT_CRCVFRRAB)==HDLC_STAT_CRCVFR) ||
+					test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+					if (bch->rx_skb->len < MISDN_COPY_SIZE) {
+						skb = alloc_stack_skb(bch->rx_skb->len, bch->up_headerlen);
+						if (skb) {
+							memcpy(skb_put(skb, bch->rx_skb->len),
+								bch->rx_skb->data, bch->rx_skb->len);
+							skb_trim(bch->rx_skb, 0);
+						} else {
+							skb = bch->rx_skb;
+							bch->rx_skb = NULL;
+						}
+					} else {
+						skb = bch->rx_skb;
+						bch->rx_skb = NULL;
+					}
+					queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, skb);
+				} else {
+					if (bch->debug & L1_DEB_HSCX)
+						mISDN_debugprint(&bch->inst, "invalid frame");
+					else
+						mISDN_debugprint(&bch->inst, "ch%d invalid frame %#x", bch->channel, stat);
+					skb_trim(bch->rx_skb, 0);
+				}
+			}
+		}
+	}
+handle_tx:
+	if (stat & HDLC_INT_XDU) {
+		/* Here we lost an TX interrupt, so
+		 * restart transmitting the whole frame on HDLC
+		 * in transparent mode we send the next data
+		 */
+		if (bch->debug & L1_DEB_WARN) {
+			if (bch->tx_skb)
+				mISDN_debugprint(&bch->inst, "ch%d XDU tx_len(%d) tx_idx(%d) Flags(%lx)",
+					bch->channel, bch->tx_skb->len, bch->tx_idx, bch->Flags);
+			else
+				mISDN_debugprint(&bch->inst, "ch%d XDU no tx_skb Flags(%lx)",
+					bch->channel, bch->Flags);
+		}
+		if (bch->tx_skb && bch->tx_skb->len) {
+			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+				bch->tx_idx = 0;
+		}
+		hdlc->ctrl.sr.xml = 0;
+		hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS;
+		write_ctrl(bch, 1);
+		hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
+		HDLC_irq_xpr(bch);
+		return;
+	} else if (stat & HDLC_INT_XPR)
+		HDLC_irq_xpr(bch);
+}
+
+static inline void
+HDLC_irq_main(fritzpnppci *fc)
+{
+	u_int stat;
+	channel_t *bch;
+
+	stat = read_status(fc, 0);
+	if (stat & HDLC_INT_MASK) {
+		if (!(bch = Sel_BCS(fc, 0))) {
+			if (fc->bch[0].debug)
+				mISDN_debugprint(&fc->bch[0].inst, "hdlc spurious channel 0 IRQ");
+		} else
+			HDLC_irq(bch, stat);
+	}
+	stat = read_status(fc, 1);
+	if (stat & HDLC_INT_MASK) {
+		if (!(bch = Sel_BCS(fc, 1))) {
+			if (fc->bch[1].debug)
+				mISDN_debugprint(&fc->bch[1].inst, "hdlc spurious channel 1 IRQ");
+		} else
+			HDLC_irq(bch, stat);
+	}
+}
+
+static irqreturn_t
+avm_fritz_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	fritzpnppci	*fc = dev_id;
+	u_char val;
+	u_char sval;
+
+	spin_lock(&fc->lock);
+	sval = inb(fc->addr + 2);
+	if (fc->dch.debug & L1_DEB_INTSTAT)
+		mISDN_debugprint(&fc->dch.inst, "irq stat0 %x", sval);
+	if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
+		/* possible a shared  IRQ reqest */
+		spin_unlock(&fc->lock);
+		return IRQ_NONE;
+	}
+	fc->irqcnt++;
+
+	if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
+		val = ReadISAC(fc, ISAC_ISTA);
+		mISDN_isac_interrupt(&fc->dch, val);
+	}
+	if (!(sval & AVM_STATUS0_IRQ_HDLC)) {
+		HDLC_irq_main(fc);
+	}
+	if (fc->type == AVM_FRITZ_PNP) {
+		WriteISAC(fc, ISAC_MASK, 0xFF);
+		WriteISAC(fc, ISAC_MASK, 0x0);
+	}
+	spin_unlock(&fc->lock);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+avm_fritzv2_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	fritzpnppci	*fc = dev_id;
+	u_char val;
+	u_char sval;
+
+	spin_lock(&fc->lock);
+	sval = inb(fc->addr + 2);
+	if (fc->dch.debug & L1_DEB_INTSTAT)
+		mISDN_debugprint(&fc->dch.inst, "irq stat0 %x", sval);
+	if (!(sval & AVM_STATUS0_IRQ_MASK)) {
+		/* possible a shared  IRQ reqest */
+		spin_unlock(&fc->lock);
+		return IRQ_NONE;
+	}
+	fc->irqcnt++;
+
+	if (sval & AVM_STATUS0_IRQ_HDLC) {
+		HDLC_irq_main(fc);
+	}
+	if (sval & AVM_STATUS0_IRQ_ISAC) {
+		val = fcpci2_read_isac(fc, ISACSX_ISTA);
+		mISDN_isac_interrupt(&fc->dch, val);
+	}
+	if (sval & AVM_STATUS0_IRQ_TIMER) {
+		if (fc->dch.debug & L1_DEB_INTSTAT)
+			mISDN_debugprint(&fc->dch.inst, "Fc2 timer irq");
+		outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2);
+		udelay(1);
+		outb(fc->ctrlreg, fc->addr + 2);
+	}
+	spin_unlock(&fc->lock);
+	return IRQ_HANDLED;
+}
+
+static int
+hdlc_down(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*bch;
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	bch = container_of(inst, channel_t, inst);
+	if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		ret = channel_senddata(bch, hh->dinfo, skb);
+		if (ret > 0) { /* direct TX */
+			hdlc_fill_fifo(bch);
+			ret = 0;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		return(ret);
+	} 
+	if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_ESTABLISH  | REQUEST))) {
+		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
+			spin_lock_irqsave(inst->hwlock, flags);
+			ret = modehdlc(bch, bch->channel,
+				bch->inst.pid.protocol[1]);
+			spin_unlock_irqrestore(inst->hwlock, flags);
+		}
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
+	} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_RELEASE | REQUEST)) ||
+		((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+			dev_kfree_skb(bch->next_skb);
+			bch->next_skb = NULL;
+		}
+		if (bch->tx_skb) {
+			dev_kfree_skb(bch->tx_skb);
+			bch->tx_skb = NULL;
+			bch->tx_idx = 0;
+		}
+		test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		modehdlc(bch, bch->channel, 0);
+		if (bch->rx_skb) {
+			dev_kfree_skb(bch->rx_skb);
+			bch->rx_skb = NULL;
+		}
+		test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		skb_trim(skb, 0);
+		if (hh->prim != (PH_CONTROL | REQUEST))
+			if (!mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, 0, skb))
+				return(0);
+	} else {
+		printk(KERN_WARNING "hdlc_down unknown prim(%x)\n", hh->prim);
+		ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+static void
+inithdlc(fritzpnppci *fc)
+{
+	modehdlc(&fc->bch[0], 0, -1);
+	modehdlc(&fc->bch[1], 1, -1);
+}
+
+void
+clear_pending_hdlc_ints(fritzpnppci *fc)
+{
+	u_int val;
+
+	val = read_status(fc, 0);
+	mISDN_debugprint(&fc->dch.inst, "HDLC 1 STA %x", val);
+	val = read_status(fc, 1);
+	mISDN_debugprint(&fc->dch.inst, "HDLC 2 STA %x", val);
+}
+
+static void
+reset_avmpcipnp(fritzpnppci *fc)
+{
+	switch (fc->type) {
+		case AVM_FRITZ_PNP:
+		case AVM_FRITZ_PCI:
+			fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER;
+			break;
+		case AVM_FRITZ_PCIV2:
+			fc->ctrlreg = AVM_STATUS0_RESET;
+			break;
+	}
+	printk(KERN_INFO "AVM PCI/PnP: reset\n");
+	disable_hwirq(fc);
+	mdelay(5);
+	switch (fc->type) {
+		case AVM_FRITZ_PNP:
+			fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER;
+			disable_hwirq(fc);
+			outb(AVM_STATUS1_ENA_IOM | fc->irq, fc->addr + 3);
+			break;
+		case AVM_FRITZ_PCI:
+			fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER;
+			disable_hwirq(fc);
+			outb(AVM_STATUS1_ENA_IOM, fc->addr + 3);
+			break;
+		case AVM_FRITZ_PCIV2:
+			fc->ctrlreg = 0;
+			disable_hwirq(fc);
+			break;
+	}
+	mdelay(1);
+	printk(KERN_INFO "AVM PCI/PnP: S0/S1 %x/%x\n", inb(fc->addr + 2), inb(fc->addr + 3));
+}
+
+static int init_card(fritzpnppci *fc)
+{
+	int		cnt = 3;
+	u_int		shared = SA_SHIRQ;
+	u_long		flags;
+	u_char		*id = "AVM Fritz!PCI";
+
+	if (fc->type == AVM_FRITZ_PNP) {
+		shared = 0;
+		id = "AVM Fritz!PnP";
+	}
+	reset_avmpcipnp(fc); /* disable IRQ */
+	if (fc->type == AVM_FRITZ_PCIV2) {
+		if (request_irq(fc->irq, avm_fritzv2_interrupt, shared, id, fc)) {
+			printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
+				fc->irq);
+			return(-EIO);
+		}
+	} else {
+		if (request_irq(fc->irq, avm_fritz_interrupt, shared, id, fc)) {
+			printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
+				fc->irq);
+			return(-EIO);
+		}
+	}
+	while (cnt) {
+		int	ret;
+
+		spin_lock_irqsave(&fc->lock, flags);
+		mISDN_clear_isac(&fc->dch);
+		if ((ret=mISDN_isac_init(&fc->dch))) {
+			printk(KERN_WARNING "mISDN: mISDN_isac_init failed with %d\n", ret);
+			spin_unlock_irqrestore(&fc->lock, flags);
+			break;
+		}
+		clear_pending_hdlc_ints(fc);
+		inithdlc(fc);
+		WriteISAC(fc, ISAC_MASK, 0);
+		enable_hwirq(fc);
+		/* RESET Receiver and Transmitter */
+		WriteISAC(fc, ISAC_CMDR, 0x41);
+		spin_unlock_irqrestore(&fc->lock, flags);
+		/* Timeout 10ms */
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout((10*HZ)/1000);
+		printk(KERN_INFO "AVM Fritz!PCI: IRQ %d count %d\n",
+			fc->irq, fc->irqcnt);
+		if (!fc->irqcnt) {
+			printk(KERN_WARNING
+			       "AVM Fritz!PCI: IRQ(%d) getting no interrupts during init %d\n",
+			       fc->irq, 4 - cnt);
+			if (cnt == 1) {
+				return (-EIO);
+			} else {
+				reset_avmpcipnp(fc);
+				cnt--;
+			}
+		} else {
+			return(0);
+		}
+	}
+	return(-EIO);
+}
+
+#define MAX_CARDS	4
+static int fritz_cnt;
+static u_int protocol[MAX_CARDS];
+static int layermask[MAX_CARDS];
+
+static mISDNobject_t	fritz;
+static int debug;
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#define MODULE_PARM_T   "1-4i"
+MODULE_PARM(protocol, MODULE_PARM_T);
+MODULE_PARM(layermask, MODULE_PARM_T);
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+
+#ifdef OLD_MODULE_PARAM_ARRAY
+static int num_protocol=0,num_layermask=0;
+module_param_array(protocol, uint, num_protocol, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, num_layermask, S_IRUGO | S_IWUSR);
+#else
+module_param_array(protocol, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, NULL, S_IRUGO | S_IWUSR);
+#endif
+#endif
+
+#endif
+
+int
+setup_fritz(fritzpnppci *fc)
+{
+	u_int	val, ver;
+
+	if (!request_region(fc->addr, 32, (fc->type == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
+		printk(KERN_WARNING
+		       "mISDN: %s config port %x-%x already in use\n",
+		       "AVM Fritz!PCI",
+		       fc->addr,
+		       fc->addr + 31);
+		return(-EIO);
+	}
+	switch (fc->type) {
+	    case AVM_FRITZ_PCI:
+		val = inl(fc->addr);
+		printk(KERN_INFO "AVM PCI: stat %#x\n", val);
+		printk(KERN_INFO "AVM PCI: Class %X Rev %d\n",
+			val & 0xff, (val>>8) & 0xff);
+		outl(AVM_HDLC_1, fc->addr + CHIP_INDEX);
+		ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24;
+		printk(KERN_INFO "AVM PnP: HDLC version %x\n", ver & 0xf);
+		fc->dch.read_reg = &ReadISAC;
+		fc->dch.write_reg = &WriteISAC;
+		fc->dch.read_fifo = &ReadISACfifo;
+		fc->dch.write_fifo = &WriteISACfifo;
+		fc->dch.type = ISAC_TYPE_ISAC;
+		break;
+	    case AVM_FRITZ_PCIV2:
+		val = inl(fc->addr);
+		printk(KERN_INFO "AVM PCI V2: stat %#x\n", val);
+		printk(KERN_INFO "AVM PCI V2: Class %X Rev %d\n",
+			val & 0xff, (val>>8) & 0xff);
+		ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24;
+		printk(KERN_INFO "AVM PnP: HDLC version %x\n", ver & 0xf);
+		fc->dch.read_reg = &fcpci2_read_isac;
+		fc->dch.write_reg = &fcpci2_write_isac;
+		fc->dch.read_fifo = &fcpci2_read_isac_fifo;
+		fc->dch.write_fifo = &fcpci2_write_isac_fifo;
+		fc->dch.type = ISAC_TYPE_ISACSX;
+		break;
+	    case AVM_FRITZ_PNP:
+		val = inb(fc->addr);
+		ver = inb(fc->addr + 1);
+		printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver);
+		outb(AVM_HDLC_1, fc->addr + CHIP_INDEX);
+		ver = inb(fc->addr + CHIP_WINDOW + 7);
+		printk(KERN_INFO "AVM PnP: HDLC version %x\n", ver & 0xf);
+		fc->dch.read_reg = &ReadISAC;
+		fc->dch.write_reg = &WriteISAC;
+		fc->dch.read_fifo = &ReadISACfifo;
+		fc->dch.write_fifo = &WriteISACfifo;
+		fc->dch.type = ISAC_TYPE_ISAC;
+		break;
+	    default:
+	    	release_region(fc->addr, 32);
+	  	printk(KERN_WARNING "AVM unknown type %d\n", fc->type);
+	  	return(-ENODEV);
+	}
+	printk(KERN_INFO "mISDN: %s config irq:%d base:0x%X\n",
+		(fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" :
+		(fc->type == AVM_FRITZ_PCIV2) ? "AVM Fritz!PCIv2" : "AVM Fritz!PnP",
+		fc->irq, fc->addr);
+
+	fc->dch.hw = &fc->isac;
+	return(0);
+}
+
+static void
+release_card(fritzpnppci *card)
+{
+	u_long		flags;
+
+	disable_hwirq(card);
+	spin_lock_irqsave(&card->lock, flags);
+	modehdlc(&card->bch[0], 0, ISDN_PID_NONE);
+	modehdlc(&card->bch[1], 1, ISDN_PID_NONE);
+	mISDN_isac_free(&card->dch);
+	spin_unlock_irqrestore(&card->lock, flags);
+	free_irq(card->irq, card);
+	spin_lock_irqsave(&card->lock, flags);
+	release_region(card->addr, 32);
+	mISDN_freechannel(&card->bch[1]);
+	mISDN_freechannel(&card->bch[0]);
+	mISDN_freechannel(&card->dch);
+	spin_unlock_irqrestore(&card->lock, flags);
+	mISDN_ctrl(&card->dch.inst, MGR_UNREGLAYER | REQUEST, NULL);
+	spin_lock_irqsave(&fritz.lock, flags);
+	list_del(&card->list);
+	spin_unlock_irqrestore(&fritz.lock, flags);
+	if (card->type == AVM_FRITZ_PNP) {
+#if defined(CONFIG_PNP)
+		pnp_disable_dev(card->dev.pnp);
+		pnp_set_drvdata(card->dev.pnp, NULL);
+#endif
+	} else {
+		pci_disable_device(card->dev.pci);
+		pci_set_drvdata(card->dev.pci, NULL);
+	}
+	kfree(card);
+}
+
+static int
+fritz_manager(void *data, u_int prim, void *arg) {
+	fritzpnppci	*card;
+	mISDNinstance_t	*inst = data;
+	struct sk_buff	*skb;
+	u_long		flags;
+	int		channel = -1;
+
+	if (debug & 0x10000)
+		printk(KERN_DEBUG "%s: data(%p) prim(%x) arg(%p)\n",
+			__FUNCTION__, data, prim, arg);
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim,arg,&fritz)
+		printk(KERN_ERR "%s: no data prim %x arg %p\n",
+			__FUNCTION__, prim, arg);
+		return(-EINVAL);
+	}
+	spin_lock_irqsave(&fritz.lock, flags);
+	list_for_each_entry(card, &fritz.ilist, list) {
+		if (&card->dch.inst == inst) {
+			channel = 2;
+			break;
+		}
+		if (&card->bch[0].inst == inst) {
+			channel = 0;
+			break;
+		}
+		if (&card->bch[1].inst == inst) {
+			channel = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&fritz.lock, flags);
+	if (channel<0) {
+		printk(KERN_WARNING "%s: no channel data %p prim %x arg %p\n",
+			__FUNCTION__, data, prim, arg);
+		return(-EINVAL);
+	}
+
+	switch(prim) {
+	    case MGR_REGLAYER | CONFIRM:
+		if (channel == 2)
+			mISDN_setpara(&card->dch, &inst->st->para);
+		else
+			mISDN_setpara(&card->bch[channel], &inst->st->para);
+		break;
+	    case MGR_UNREGLAYER | REQUEST:
+	    	if ((skb = create_link_skb(PH_CONTROL | REQUEST,
+	    		HW_DEACTIVATE, 0, NULL, 0))) {
+			if (channel == 2) {
+				if (mISDN_ISAC_l1hw(inst, skb))
+					dev_kfree_skb(skb);
+			} else {
+				if (hdlc_down(inst, skb))
+					dev_kfree_skb(skb);
+			}
+		} else
+			printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+		break;
+	    case MGR_CLRSTPARA | INDICATION:
+		arg = NULL;
+	    case MGR_ADDSTPARA | INDICATION:
+		if (channel == 2)
+			mISDN_setpara(&card->dch, arg);
+		else
+			mISDN_setpara(&card->bch[channel], arg);
+		break;
+	    case MGR_RELEASE | INDICATION:
+		if (channel == 2) {
+			release_card(card);
+		} else {
+			fritz.refcnt--;
+		}
+		break;
+	    case MGR_SETSTACK | INDICATION:
+		if ((channel!=2) && (inst->pid.global == 2)) {
+			if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
+				0, 0, NULL, 0))) {
+				if (hdlc_down(inst, skb))
+					dev_kfree_skb(skb);
+			}
+			if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
+					0, 0, NULL, 0);
+			else
+				mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
+					0, 0, NULL, 0);
+		}
+		break;
+	    PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+	    PRIM_NOT_HANDLED(MGR_GLOBALOPT | REQUEST);
+	    default:
+		printk(KERN_WARNING "%s: prim %x not handled\n",
+			__FUNCTION__, prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+static int __devinit setup_instance(fritzpnppci *card)
+{
+	int		i, err;
+	mISDN_pid_t	pid;
+	u_long		flags;
+	struct device	*dev;
+
+	if (card->type == AVM_FRITZ_PNP) {
+#if defined(CONFIG_PNP)
+		dev = &card->dev.pnp->dev;
+#else
+		dev = NULL;
+#endif
+	} else {
+		dev = &card->dev.pci->dev;
+	}
+	spin_lock_irqsave(&fritz.lock, flags);
+	list_add_tail(&card->list, &fritz.ilist);
+	spin_unlock_irqrestore(&fritz.lock, flags);
+	card->dch.debug = debug;
+	spin_lock_init(&card->lock);
+	card->dch.inst.hwlock = &card->lock;
+	card->dch.inst.class_dev.dev = dev;
+	card->dch.inst.pid.layermask = ISDN_LAYER(0);
+	card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
+	mISDN_init_instance(&card->dch.inst, &fritz, card, mISDN_ISAC_l1hw);
+	sprintf(card->dch.inst.name, "Fritz%d", fritz_cnt+1);
+	mISDN_set_dchannel_pid(&pid, protocol[fritz_cnt], layermask[fritz_cnt]);
+	mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
+	for (i=0; i<2; i++) {
+		card->bch[i].channel = i;
+		mISDN_init_instance(&card->bch[i].inst, &fritz, card, hdlc_down);
+		card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
+		card->bch[i].inst.hwlock = &card->lock;
+		card->bch[i].inst.class_dev.dev = dev;
+		card->bch[i].debug = debug;
+		sprintf(card->bch[i].inst.name, "%s B%d", card->dch.inst.name, i+1);
+		mISDN_initchannel(&card->bch[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM);
+		card->bch[i].hw = &card->hdlc[i];
+	}
+	printk(KERN_DEBUG "fritz card %p dch %p bch1 %p bch2 %p\n",
+		card, &card->dch, &card->bch[0], &card->bch[1]);
+	err = setup_fritz(card);
+	if (err) {
+		mISDN_freechannel(&card->dch);
+		mISDN_freechannel(&card->bch[1]);
+		mISDN_freechannel(&card->bch[0]);
+		spin_lock_irqsave(&fritz.lock, flags);
+		list_del(&card->list);
+		spin_unlock_irqrestore(&fritz.lock, flags);
+		kfree(card);
+		return(err);
+	}
+	fritz_cnt++;
+	err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &card->dch.inst);
+	if (err) {
+		release_card(card);
+		return(err);
+	}
+	for (i=0; i<2; i++) {
+		err = mISDN_ctrl(card->dch.inst.st, MGR_NEWSTACK | REQUEST, &card->bch[i].inst);
+		if (err) {
+			printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
+			mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+			return(err);
+		}
+	}
+	err = mISDN_ctrl(card->dch.inst.st, MGR_SETSTACK | REQUEST, &pid);
+	if (err) {
+		printk(KERN_ERR  "MGR_SETSTACK REQUEST dch err(%d)\n", err);
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return(err);
+	}
+	err = init_card(card);
+	if (err) {
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return(err);
+	}
+	mISDN_ctrl(card->dch.inst.st, MGR_CTRLREADY | INDICATION, NULL);
+	printk(KERN_INFO "fritz %d cards installed\n", fritz_cnt);
+	return(0);
+}
+
+static int __devinit fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int		err = -ENOMEM;
+	fritzpnppci	*card;
+
+	if (!(card = kmalloc(sizeof(fritzpnppci), GFP_ATOMIC))) {
+		printk(KERN_ERR "No kmem for fritzcard\n");
+		return(err);
+	}
+	memset(card, 0, sizeof(fritzpnppci));
+	if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)
+		card->type = AVM_FRITZ_PCIV2;
+	else
+		card->type = AVM_FRITZ_PCI;
+	card->dev.pci = pdev;
+	err = pci_enable_device(pdev);
+	if (err) {
+		kfree(card);
+		return(err);
+	}
+
+	printk(KERN_INFO "mISDN_fcpcipnp: found adapter %s at %s\n",
+	       (char *) ent->driver_data, pci_name(pdev));
+
+	card->addr = pci_resource_start(pdev, 1);
+	card->irq = pdev->irq;
+	pci_set_drvdata(pdev, card);
+	err = setup_instance(card);
+	if (err)
+		pci_set_drvdata(pdev, NULL);
+	return(err);
+}
+
+#if defined(CONFIG_PNP)
+#ifdef NEW_ISAPNP
+static int __devinit fritzpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
+#else
+static int __devinit fritzpnp_probe(struct pci_dev *pdev, const struct isapnp_device_id *dev_id)
+#endif
+{
+	int		err;
+	fritzpnppci	*card;
+
+	if (!pdev)
+		return(-ENODEV);
+
+	if (!(card = kmalloc(sizeof(fritzpnppci), GFP_ATOMIC))) {
+		printk(KERN_ERR "No kmem for fritzcard\n");
+		return(-ENOMEM);
+	}
+	memset(card, 0, sizeof(fritzpnppci));
+	card->type = AVM_FRITZ_PNP;
+	card->dev.pnp = pdev;
+	pnp_disable_dev(pdev);
+	err = pnp_activate_dev(pdev);
+	if (err<0) {
+		printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__,
+			(char *)dev_id->driver_data, err);
+		kfree(card);
+		return(err);
+	}
+	card->addr = pnp_port_start(pdev, 0);
+	card->irq = pnp_irq(pdev, 0);
+
+	printk(KERN_INFO "mISDN_fcpcipnp: found adapter %s at IO %#x irq %d\n",
+	       (char *)dev_id->driver_data, card->addr, card->irq);
+
+	pnp_set_drvdata(pdev, card);
+	err = setup_instance(card);
+	if (err)
+		pnp_set_drvdata(pdev, NULL);
+	return(err);
+}
+#endif /* CONFIG_PNP */
+
+static void __devexit fritz_remove_pci(struct pci_dev *pdev)
+{
+	fritzpnppci	*card = pci_get_drvdata(pdev);
+
+	if (card)
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+	else
+		printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__);
+}
+
+#if defined(CONFIG_PNP)
+#ifdef NEW_ISAPNP
+static void __devexit fritz_remove_pnp(struct pnp_dev *pdev)
+#else
+static void __devexit fritz_remove_pnp(struct pci_dev *pdev)
+#endif
+{
+	fritzpnppci	*card = pnp_get_drvdata(pdev);
+
+	if (card)
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+	else
+		printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__);
+}
+#endif /* CONFIG_PNP */
+
+static struct pci_device_id fcpci_ids[] __devinitdata = {
+	{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1   , PCI_ANY_ID, PCI_ANY_ID,
+	  0, 0, (unsigned long) "Fritz!Card PCI" },
+	{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,
+	  0, 0, (unsigned long) "Fritz!Card PCI v2" },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, fcpci_ids);
+
+static struct pci_driver fcpci_driver = {
+	name:     "fcpci",
+	probe:    fritzpci_probe,
+	remove:   __devexit_p(fritz_remove_pci),
+	id_table: fcpci_ids,
+};
+
+#if defined(CONFIG_PNP)
+#ifdef NEW_ISAPNP
+static struct pnp_device_id fcpnp_ids[] __devinitdata = {
+	{ 
+		.id		= "AVM0900",
+		.driver_data	= (unsigned long) "Fritz!Card PnP",
+	},
+};
+
+static struct pnp_driver fcpnp_driver = {
+#else
+static struct isapnp_device_id fcpnp_ids[] __devinitdata = {
+	{ ISAPNP_VENDOR('A', 'V', 'M'), ISAPNP_FUNCTION(0x0900),
+	  ISAPNP_VENDOR('A', 'V', 'M'), ISAPNP_FUNCTION(0x0900), 
+	  (unsigned long) "Fritz!Card PnP" },
+	{ }
+};
+MODULE_DEVICE_TABLE(isapnp, fcpnp_ids);
+
+static struct isapnp_driver fcpnp_driver = {
+#endif
+	name:     "fcpnp",
+	probe:    fritzpnp_probe,
+	remove:   __devexit_p(fritz_remove_pnp),
+	id_table: fcpnp_ids,
+};
+#endif /* CONFIG_PNP */
+
+static char FritzName[] = "AVM Fritz";
+
+static int __init Fritz_init(void)
+{
+	int	err;
+#ifdef OLD_PCI_REGISTER_DRIVER
+	int	pci_nr_found;
+#endif
+
+	printk(KERN_INFO "AVM Fritz PCI/PnP driver Rev. %s\n", mISDN_getrev(avm_fritz_rev));
+#ifdef MODULE
+	fritz.owner = THIS_MODULE;
+#endif
+	spin_lock_init(&fritz.lock);
+	INIT_LIST_HEAD(&fritz.ilist);
+	fritz.name = FritzName;
+	fritz.own_ctrl = fritz_manager;
+	fritz.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0;
+	fritz.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS |
+				    ISDN_PID_L1_B_64HDLC;
+	fritz.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS;
+	if ((err = mISDN_register(&fritz))) {
+		printk(KERN_ERR "Can't register Fritz PCI error(%d)\n", err);
+		return(err);
+	}
+	err = pci_register_driver(&fcpci_driver);
+	if (err < 0)
+		goto out;
+#ifdef OLD_PCI_REGISTER_DRIVER
+	pci_nr_found = err;
+#endif
+#if defined(CONFIG_PNP)
+	err = pnp_register_driver(&fcpnp_driver);
+	if (err < 0)
+		goto out_unregister_pci;
+#endif
+#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
+#ifdef OLD_PCI_REGISTER_DRIVER
+	if (pci_nr_found + err == 0) {
+		err = -ENODEV;
+		goto out_unregister_isapnp;
+	}
+#endif
+#endif
+	
+	mISDN_module_register(THIS_MODULE);
+
+	return 0;
+
+#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
+#ifdef OLD_PCI_REGISTER_DRIVER
+ out_unregister_isapnp:
+#if defined(CONFIG_PNP)
+	pnp_unregister_driver(&fcpnp_driver);
+#endif
+#endif
+#endif
+#if defined(CONFIG_PNP)
+ out_unregister_pci:
+#endif
+	pci_unregister_driver(&fcpci_driver);
+ out:
+ 	return err;
+}
+
+static void __exit Fritz_cleanup(void)
+{
+	fritzpnppci *card, *next;
+	int err;
+
+	mISDN_module_unregister(THIS_MODULE);
+	
+	if ((err = mISDN_unregister(&fritz))) {
+		printk(KERN_ERR "Can't unregister Fritz PCI error(%d)\n", err);
+	}
+	list_for_each_entry_safe(card, next, &fritz.ilist, list) {
+		printk(KERN_ERR "Fritz PCI card struct not empty refs %d\n",
+			fritz.refcnt);
+		release_card(card);
+	}
+#if defined(CONFIG_PNP)
+	pnp_unregister_driver(&fcpnp_driver);
+#endif
+	pci_unregister_driver(&fcpci_driver);
+}
+
+module_init(Fritz_init);
+module_exit(Fritz_cleanup);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/capi.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/capi.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/capi.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,460 @@
+/* $Id: capi.c,v 1.21 2006/12/21 15:25:06 nadi Exp $
+ *
+ */
+
+#include <linux/module.h>
+#include "core.h"
+#include "m_capi.h"
+#include "helper.h"
+#include "debug.h"
+
+static char *capi_revision = "$Revision: 1.21 $";
+
+static int debug = 0;
+static mISDNobject_t capi_obj;
+
+static char MName[] = "mISDN Capi 2.0";
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+#endif
+#endif
+
+static char deb_buf[256];
+
+void capidebug(int level, char *fmt, ...)
+{
+	va_list args;
+
+	if (debug & level) {
+		va_start(args, fmt);
+		vsprintf(deb_buf, fmt, args);
+		printk(KERN_DEBUG "%s\n", deb_buf);
+		va_end(args);
+	}
+}
+
+#ifdef OLDCAPI_DRIVER_INTERFACE
+struct capi_driver_interface *cdrv_if;
+#endif
+
+struct kmem_cache	*mISDN_cmsg_cp;
+struct kmem_cache	*mISDN_AppPlci_cp;
+struct kmem_cache	*mISDN_ncci_cp;
+struct kmem_cache	*mISDN_sspc_cp;
+
+#ifdef MISDN_KMEM_DEBUG
+static struct list_head mISDN_kmem_garbage = LIST_HEAD_INIT(mISDN_kmem_garbage);
+
+_cmsg *
+_kd_cmsg_alloc(char *fn, int line)
+{
+	_kd_cmsg_t	*ki = kmem_cache_alloc(mISDN_cmsg_cp, GFP_ATOMIC);
+
+	if (!ki)
+		return(NULL);
+	ki->kdi.typ = KM_DBG_TYP_CM;
+	INIT_LIST_HEAD(&ki->kdi.head);
+	ki->kdi.line = line;
+	ki->kdi.file = fn;
+	list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
+	return(&ki->cm);
+}
+
+void
+cmsg_free(_cmsg *cm)
+{
+	km_dbg_item_t	*kdi;
+
+	if (!cm) {
+		int_errtxt("zero pointer free at %p", __builtin_return_address(0));
+		return;
+	}
+	kdi = KDB_GET_KDI(cm);
+	list_del(&kdi->head);
+	kmem_cache_free(mISDN_cmsg_cp, kdi);
+}
+
+AppPlci_t *
+_kd_AppPlci_alloc(char *fn, int line)
+{
+	_kd_AppPlci_t	*ki = kmem_cache_alloc(mISDN_AppPlci_cp, GFP_ATOMIC);
+
+	if (!ki)
+		return(NULL);
+	ki->kdi.typ = KM_DBG_TYP_AP;
+	INIT_LIST_HEAD(&ki->kdi.head);
+	ki->kdi.line = line;
+	ki->kdi.file = fn;
+	list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
+	return(&ki->ap);
+}
+
+void
+AppPlci_free(AppPlci_t *ap)
+{
+	km_dbg_item_t	*kdi;
+
+	if (!ap) {
+		int_errtxt("zero pointer free at %p", __builtin_return_address(0));
+		return;
+	}
+	kdi = KDB_GET_KDI(ap);
+	list_del(&kdi->head);
+	kmem_cache_free(mISDN_AppPlci_cp, kdi);
+}
+
+Ncci_t *
+_kd_ncci_alloc(char *fn, int line)
+{
+	_kd_Ncci_t	*ki = kmem_cache_alloc(mISDN_ncci_cp, GFP_ATOMIC);
+
+	if (!ki)
+		return(NULL);
+	ki->kdi.typ = KM_DBG_TYP_NI;
+	INIT_LIST_HEAD(&ki->kdi.head);
+	ki->kdi.line = line;
+	ki->kdi.file = fn;
+	list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
+	return(&ki->ni);
+}
+
+void
+ncci_free(Ncci_t *ni)
+{
+	km_dbg_item_t	*kdi;
+
+	if (!ni) {
+		int_errtxt("zero pointer free at %p", __builtin_return_address(0));
+		return;
+	}
+	kdi = KDB_GET_KDI(ni);
+	list_del(&kdi->head);
+	kmem_cache_free(mISDN_ncci_cp, kdi);
+}
+
+SSProcess_t *
+_kd_SSProcess_alloc(char *fn, int line)
+{
+	_kd_SSProcess_t	*ki = kmem_cache_alloc(mISDN_sspc_cp, GFP_ATOMIC);
+
+	if (!ki)
+		return(NULL);
+	ki->kdi.typ = KM_DBG_TYP_SP;
+	INIT_LIST_HEAD(&ki->kdi.head);
+	ki->kdi.line = line;
+	ki->kdi.file = fn;
+	list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
+	return(&ki->sp);
+}
+
+void
+SSProcess_free(SSProcess_t *sp)
+{
+	km_dbg_item_t	*kdi;
+
+	if (!sp) {
+		int_errtxt("zero pointer free at %p", __builtin_return_address(0));
+		return;
+	}
+	kdi = KDB_GET_KDI(sp);
+	list_del(&kdi->head);
+	kmem_cache_free(mISDN_sspc_cp, kdi);
+}
+
+static void
+free_garbage(void)
+{
+	struct list_head	*item, *next;
+	_kd_all_t		*kda;
+
+	list_for_each_safe(item, next, &mISDN_kmem_garbage) {
+		kda = (_kd_all_t *)item;
+		printk(KERN_DEBUG "garbage item found (%p <- %p -> %p) type%ld allocated at %s:%d\n",
+			kda->kdi.head.prev, item, kda->kdi.head.next, kda->kdi.typ, kda->kdi.file, kda->kdi.line);
+		list_del(item);
+		switch(kda->kdi.typ) {
+			case KM_DBG_TYP_CM:
+				printk(KERN_DEBUG "cmsg cmd(%x,%x) appl(%x) addr(%x) nr(%d)\n",
+					kda->a.cm.Command,
+					kda->a.cm.Subcommand,
+					kda->a.cm.ApplId,
+					kda->a.cm.adr.adrController,
+					kda->a.cm.Messagenumber);
+				kmem_cache_free(mISDN_cmsg_cp, item);
+				break;
+			case KM_DBG_TYP_AP:
+				printk(KERN_DEBUG "AppPlci: PLCI(%x) m.state(%x) appl(%p)\n",
+					kda->a.ap.addr,
+					kda->a.ap.plci_m.state,
+					kda->a.ap.appl);
+				kmem_cache_free(mISDN_AppPlci_cp, item);
+				break;
+			case KM_DBG_TYP_NI:
+				printk(KERN_DEBUG "Ncci: NCCI(%x) state(%lx) m.state(%x) aplci(%p)\n",
+					kda->a.ni.addr,
+					kda->a.ni.state,
+					kda->a.ni.ncci_m.state,
+					kda->a.ni.AppPlci);
+				kmem_cache_free(mISDN_ncci_cp, item);
+				break;
+			case KM_DBG_TYP_SP:
+				printk(KERN_DEBUG "SSPc: addr(%x) id(%x) apid(%x) func(%x)\n",
+					kda->a.sp.addr,
+					kda->a.sp.invokeId,
+					kda->a.sp.ApplId,
+					kda->a.sp.Function);
+				kmem_cache_free(mISDN_sspc_cp, item);
+				break;
+			default:
+				printk(KERN_DEBUG "unknown garbage item(%p) type %ld\n",
+					item, kda->kdi.typ);
+				break; 
+		}
+	}
+}
+
+#endif
+
+static void CapiCachesFree(void)
+{
+#ifdef MISDN_KMEM_DEBUG
+	free_garbage();
+#endif
+	if (mISDN_cmsg_cp) {
+		kmem_cache_destroy(mISDN_cmsg_cp);
+		mISDN_cmsg_cp = NULL;
+	}
+	if (mISDN_AppPlci_cp) {
+		kmem_cache_destroy(mISDN_AppPlci_cp);
+		mISDN_AppPlci_cp = NULL;
+	}
+	if (mISDN_ncci_cp) {
+		kmem_cache_destroy(mISDN_ncci_cp);
+		mISDN_ncci_cp = NULL;
+	}
+	if (mISDN_sspc_cp) {
+		kmem_cache_destroy(mISDN_sspc_cp);
+		mISDN_sspc_cp = NULL;
+	}
+}
+
+static int CapiNew(void)
+{
+	mISDN_cmsg_cp = NULL;
+	mISDN_AppPlci_cp = NULL;
+	mISDN_ncci_cp = NULL;
+	mISDN_sspc_cp = NULL;
+	mISDN_cmsg_cp = kmem_cache_create("mISDN_cmesg",
+#ifdef MISDN_KMEM_DEBUG
+				sizeof(_kd_cmsg_t),
+#else
+				sizeof(_cmsg),
+#endif
+				0, 0, NULL, NULL);
+	if (!mISDN_cmsg_cp) {
+		CapiCachesFree();
+		return(-ENOMEM);
+	}
+	mISDN_AppPlci_cp = kmem_cache_create("mISDN_AppPlci",
+#ifdef MISDN_KMEM_DEBUG
+				sizeof(_kd_AppPlci_t),
+#else
+				sizeof(AppPlci_t),
+#endif
+				0, 0, NULL, NULL);
+	if (!mISDN_AppPlci_cp) {
+		CapiCachesFree();
+		return(-ENOMEM);
+	}
+	mISDN_ncci_cp = kmem_cache_create("mISDN_Ncci",
+#ifdef MISDN_KMEM_DEBUG
+				sizeof(_kd_Ncci_t),
+#else
+				sizeof(Ncci_t),
+#endif
+				0, 0, NULL, NULL);
+	if (!mISDN_ncci_cp) {
+		CapiCachesFree();
+		return(-ENOMEM);
+	}
+	mISDN_sspc_cp = kmem_cache_create("mISDN_SSProc",
+#ifdef MISDN_KMEM_DEBUG
+				sizeof(_kd_SSProcess_t),
+#else
+				sizeof(SSProcess_t),
+#endif
+				0, 0, NULL, NULL);
+	if (!mISDN_sspc_cp) {
+		CapiCachesFree();
+		return(-ENOMEM);
+	}
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	cdrv_if = attach_capi_driver(&mISDN_driver);
+	if (!cdrv_if) {
+		CapiCachesFree();
+		printk(KERN_ERR "mISDN: failed to attach capi_driver\n");
+		return -EIO;
+	}
+#endif
+	init_listen();
+	init_AppPlci();
+	init_ncci();
+	return 0;
+}
+
+static int
+capi20_manager(void *data, u_int prim, void *arg) {
+	mISDNinstance_t	*inst = data;
+	int		found=0;
+	PLInst_t	*plink = NULL;
+	Controller_t	*ctrl;
+	u_long		flags;
+
+	if (CAPI_DBG_INFO & debug)
+		printk(KERN_DEBUG "capi20_manager data:%p prim:%x arg:%p\n", data, prim, arg);
+	if (!data)
+		return(-EINVAL);
+	spin_lock_irqsave(&capi_obj.lock, flags);
+	list_for_each_entry(ctrl, &capi_obj.ilist, list) {
+		if (&ctrl->inst == inst) {
+			found++;
+			break;
+		}
+		list_for_each_entry(plink, &ctrl->linklist, list) {
+			if (&plink->inst == inst) {
+				found++;
+				break;
+			}
+		}
+		if (found)
+			break;
+		plink = NULL;
+	}
+	if (&ctrl->list == &capi_obj.ilist)
+		ctrl = NULL;
+	spin_unlock_irqrestore(&capi_obj.lock, flags);
+	if (prim == (MGR_NEWLAYER | REQUEST)) {
+		int ret = ControllerConstr(&ctrl, data, arg, &capi_obj);
+		if (!ret)
+			ctrl->debug = debug;
+		return(ret);
+	}
+	if (!ctrl) {
+		if (CAPI_DBG_WARN & debug)
+			printk(KERN_WARNING "capi20_manager setif no instance\n");
+		return(-EINVAL);
+	}
+	switch(prim) {
+	    case MGR_NEWENTITY | CONFIRM:
+		ctrl->entity = (u_long)arg & 0xffffffff;
+		break;
+#ifdef FIXME
+	    case MGR_CONNECT | REQUEST:
+		return(mISDN_ConnectIF(inst, arg));
+	    case MGR_SETIF | INDICATION:
+	    case MGR_SETIF | REQUEST:
+		if (&ctrl->inst == inst)
+			return(mISDN_SetIF(inst, arg, prim, NULL, ControllerL3L4, ctrl));
+		else
+			return(AppPlcimISDN_SetIF(inst->data, prim, arg));
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		return(mISDN_DisConnectIF(inst, arg));
+#endif
+	    case MGR_SETSTACK | INDICATION:
+		if (!(&ctrl->inst == inst))
+			return(AppPlcimISDN_Active(inst->privat));
+		return(0);
+	    case MGR_RELEASE | INDICATION:
+		if (CAPI_DBG_INFO & debug)
+			printk(KERN_DEBUG "release_capi20 id %x\n", ctrl->inst.st->id);
+		ControllerDestr(ctrl);
+	    	break;
+	    case MGR_UNREGLAYER | REQUEST:
+		if (plink) {
+			plink->inst.function = NULL;
+			mISDN_ctrl(&plink->inst, MGR_UNREGLAYER | REQUEST, NULL);
+		}
+		break;
+	    case MGR_CTRLREADY | INDICATION:
+		if (CAPI_DBG_INFO & debug)
+			printk(KERN_DEBUG "ctrl %x ready\n", ctrl->inst.st->id);
+		ControllerRun(ctrl);
+		break;
+	    default:
+		if (CAPI_DBG_WARN & debug)
+			printk(KERN_WARNING "capi20_manager prim %x not handled\n", prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+int Capi20Init(void)
+{
+	int err;
+
+	printk(KERN_INFO "%s driver file version %s\n", MName, mISDN_getrev(capi_revision));
+#ifdef MODULE
+	capi_obj.owner = THIS_MODULE;
+#endif
+	capi_obj.name = MName;
+	capi_obj.DPROTO.protocol[4] = ISDN_PID_L4_CAPI20;
+	capi_obj.BPROTO.protocol[4] = ISDN_PID_L4_B_CAPI20;
+	capi_obj.BPROTO.protocol[3] = ISDN_PID_L3_B_TRANS;
+	capi_obj.own_ctrl = capi20_manager;
+	spin_lock_init(&capi_obj.lock);
+	INIT_LIST_HEAD(&capi_obj.ilist);
+	if ((err = CapiNew()))
+		return(err);
+	if ((err = mISDN_register(&capi_obj))) {
+		printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
+#ifdef OLDCAPI_DRIVER_INTERFACE
+		detach_capi_driver(&mISDN_driver);
+#endif
+		CapiCachesFree();
+		free_listen();
+		free_AppPlci();
+		free_ncci();
+		free_Application();
+	} else
+		mISDN_module_register(THIS_MODULE);
+	return(err);
+}
+
+#ifdef MODULE
+static void Capi20cleanup(void)
+{
+	int		err;
+	Controller_t	*contr, *next;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if ((err = mISDN_unregister(&capi_obj))) {
+		printk(KERN_ERR "Can't unregister CAPI20 error(%d)\n", err);
+	}
+	if (!list_empty(&capi_obj.ilist)) {
+		printk(KERN_WARNING "mISDN controller list not empty\n");
+		list_for_each_entry_safe(contr, next, &capi_obj.ilist, list)
+			ControllerDestr(contr);
+	}
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	detach_capi_driver(&mISDN_driver);
+#endif
+	free_Application();
+	CapiCachesFree();
+	free_listen();
+	free_AppPlci();
+	free_ncci();
+}
+
+module_init(Capi20Init);
+module_exit(Capi20cleanup);
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/capi_enc.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/capi_enc.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/capi_enc.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,213 @@
+/* $Id: capi_enc.c,v 1.3 2003/11/21 22:29:41 keil Exp $
+ *
+ */
+
+#include "m_capi.h"
+#include "asn1.h"
+
+int capiEncodeWord(__u8 *p, __u16 i)
+{
+	*p++ = i;
+	*p++ = i >> 8;
+	return 2;
+}
+
+int capiEncodeDWord(__u8 *p, __u32 i)
+{
+	*p++ = i;
+	*p++ = i >> 8;
+	*p++ = i >> 16;
+	*p++ = i >> 24;
+	return 4;
+}
+
+int capiEncodeFacilityPartyNumber(__u8 *dest, struct PartyNumber *partyNumber)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	switch (partyNumber->type) {
+	case 0: // unknown
+		*p++ = 0;
+		*p++ = 0;
+		*p++ = 0;
+	        strcpy(p, partyNumber->p.unknown); p += strlen(partyNumber->p.unknown);
+		break;
+	case 1: // publicPartyNumber
+		*p++ = 1;
+		*p++ = partyNumber->p.publicPartyNumber.publicTypeOfNumber << 4;
+		*p++ = 0;
+	        strcpy(p, partyNumber->p.publicPartyNumber.numberDigits);
+		p += strlen(partyNumber->p.publicPartyNumber.numberDigits);
+		break;
+	default: 
+		int_error();
+	}
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeFacilityPartyNumber2(__u8 *dest, struct ServedUserNr *servedUserNr)
+{
+	if (servedUserNr->all) {
+		*dest++ = 0; // empty struct;
+		return 1;
+	}
+	return capiEncodeFacilityPartyNumber(dest, &servedUserNr->partyNumber);
+}
+
+int capiEncodeServedUserNumbers(__u8 *dest, struct ServedUserNumberList *list)
+{
+	__u8 *p;
+	int i;
+
+	p = &dest[1];
+	for (i = 0; i < 10; i++) {
+		if (list->partyNumber[i].type >= 0)
+			p += capiEncodeFacilityPartyNumber(p, &list->partyNumber[i]);
+	}
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeInterrogateResponse(__u8 *dest, struct IntResult *intResult)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	p += capiEncodeWord(p, intResult->procedure);
+	p += capiEncodeWord(p, intResult->basicService);
+	p += capiEncodeFacilityPartyNumber2(p, &intResult->servedUserNr);
+	p += capiEncodeFacilityPartyNumber(p, &intResult->address.partyNumber);
+	*p++ = 0; // subaddress
+
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeInterrogateResponseList(__u8 *dest, struct IntResultList *list)
+{
+	__u8 *p;
+	int i;
+
+	p = &dest[1];
+	for (i = 0; i < 10; i++) {
+		if (list->intResult[i].basicService >= 0)
+			p += capiEncodeInterrogateResponse(p, &list->intResult[i]);
+	}
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeFacIndCFact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	p += capiEncodeWord(p, SupplementaryServiceReason);
+	p += capiEncodeDWord(p, Handle);
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeFacIndCFdeact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	p += capiEncodeWord(p, SupplementaryServiceReason);
+	p += capiEncodeDWord(p, Handle);
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeFacIndCFinterParameters(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle, 
+				      struct IntResultList *list)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	p += capiEncodeWord(p, SupplementaryServiceReason);
+	p += capiEncodeDWord(p, Handle);
+	p += capiEncodeInterrogateResponseList(p, list);
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeFacIndCFinterNumbers(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle, 
+				   struct ServedUserNumberList *list)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	p += capiEncodeWord(p, SupplementaryServiceReason);
+	p += capiEncodeDWord(p, Handle);
+	p += capiEncodeServedUserNumbers(p, list);
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeFacIndCFNotAct(__u8 *dest, struct ActDivNotification *actNot)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	p += capiEncodeWord(p, actNot->procedure);
+	p += capiEncodeWord(p, actNot->basicService);
+	p += capiEncodeFacilityPartyNumber2(p, &actNot->servedUserNr);
+	p += capiEncodeFacilityPartyNumber(p, &actNot->address.partyNumber);
+	*p++ = 0; // sub
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeFacIndCFNotDeact(__u8 *dest, struct DeactDivNotification *deactNot)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	p += capiEncodeWord(p, deactNot->procedure);
+	p += capiEncodeWord(p, deactNot->basicService);
+	p += capiEncodeFacilityPartyNumber2(p, &deactNot->servedUserNr);
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeFacConfStruct(__u8 *dest, struct FacConfParm *facConfParm)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	switch (facConfParm->Function) {
+	case 0x0000:
+		p += capiEncodeWord(p, facConfParm->u.GetSupportedServices.SupplementaryServiceInfo);
+		p += capiEncodeDWord(p, facConfParm->u.GetSupportedServices.SupportedServices);
+		break;
+	default:
+		p += capiEncodeWord(p, facConfParm->u.Info.SupplementaryServiceInfo);
+	}
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeFacConfParm(__u8 *dest, struct FacConfParm *facConfParm)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	p += capiEncodeWord(p, facConfParm->Function);
+	p += capiEncodeFacConfStruct(p, facConfParm);
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+
+int capiEncodeFacIndSuspend(__u8 *dest, __u16  SupplementaryServiceReason)
+{
+	__u8 *p;
+
+	p = &dest[1];
+	p += capiEncodeWord(p, SupplementaryServiceReason);
+	dest[0] = p - &dest[1];
+	return p - dest;
+}
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/channel.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/channel.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/channel.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,88 @@
+/* $Id: channel.c,v 1.2 2006/03/06 12:58:31 keil Exp $
+ *
+ *  Author       (c) Karsten Keil <kkeil at suse.de>
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/module.h>
+#include "channel.h"
+#include "layer1.h"
+
+int
+mISDN_initchannel(channel_t *ch, ulong prop, int maxlen)
+{
+	ch->log = kmalloc(MAX_LOG_SPACE, GFP_ATOMIC);
+	if (!ch->log) {
+		printk(KERN_WARNING
+			"mISDN: No memory for channel log\n");
+		return(-ENOMEM);
+	}
+	ch->Flags = prop;
+	ch->maxlen = maxlen;
+	ch->hw = NULL;
+	ch->rx_skb = NULL;
+	ch->tx_skb = NULL;
+	ch->tx_idx = 0;
+	ch->next_skb = NULL;
+	return(0);
+}
+
+int
+mISDN_freechannel(channel_t *ch)
+{
+	if (ch->tx_skb) {
+		dev_kfree_skb(ch->tx_skb);
+		ch->tx_skb = NULL;
+	}
+	if (ch->rx_skb) {
+		dev_kfree_skb(ch->rx_skb);
+		ch->rx_skb = NULL;
+	}
+	if (ch->next_skb) {
+		dev_kfree_skb(ch->next_skb);
+		ch->next_skb = NULL;
+	}
+	kfree(ch->log);
+	ch->log = NULL;
+	return(0);
+}
+
+/* need called with HW lock */
+int
+mISDN_setpara(channel_t *ch, mISDN_stPara_t *stp)
+{
+	if (!stp) { // clear parameters
+		ch->maxlen = 0;
+		ch->up_headerlen = 0;
+		return(0);
+	}
+	if (stp->up_headerlen)
+		ch->up_headerlen = stp->up_headerlen;
+	if (stp->maxdatalen) {
+		if (ch->maxlen < stp->maxdatalen) {
+			if (ch->rx_skb) {
+				struct sk_buff	*skb;
+
+				skb = alloc_skb(stp->maxdatalen +
+					ch->up_headerlen, GFP_ATOMIC);
+				if (!skb) {
+					int_errtxt("no skb for %d+%d", stp->maxdatalen, ch->up_headerlen);
+					return(-ENOMEM);
+				}
+				skb_reserve(skb, ch->up_headerlen);
+				memcpy(skb_put(skb, ch->rx_skb->len),
+					ch->rx_skb->data, ch->rx_skb->len);
+				dev_kfree_skb(ch->rx_skb);
+				ch->rx_skb = skb;
+			}
+		}
+		ch->maxlen = stp->maxdatalen;
+	}
+	return(0);
+}
+
+EXPORT_SYMBOL(mISDN_initchannel);
+EXPORT_SYMBOL(mISDN_freechannel);
+EXPORT_SYMBOL(mISDN_setpara);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/channel.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/channel.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/channel.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,168 @@
+/* $Id: channel.h,v 1.4 2006/09/07 13:02:34 crich Exp $
+ *
+ *   Basic declarations for a mISDN HW channel
+ *
+ *  Author       (c) Karsten Keil <kkeil at suse.de>
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#ifndef MISDN_CHANNEL_H
+#define MISDN_CHANNEL_H
+#include <linux/mISDNif.h>
+#include <linux/mISDNdebugtool.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include "helper.h"
+#ifdef MISDN_MEMDEBUG
+#include "memdbg.h"
+#endif
+#include "core.h"
+
+#define MAX_DFRAME_LEN_L1	300
+#define MAX_MON_FRAME		32
+#define MAX_LOG_SPACE		2048
+#define MISDN_COPY_SIZE		32
+
+/* channel->Flags bit field */
+#define FLG_TX_BUSY		0	// tx_buf in use
+#define FLG_TX_NEXT		1	// next_skb in use
+#define FLG_L1_BUSY		2	// L1 is permanent busy
+#define FLG_USED		5	// channel is in use		
+#define FLG_ACTIVE		6	// channel is activated
+#define FLG_BUSY_TIMER		7
+/* channel type */
+#define FLG_DCHANNEL		8	// channel is D-channel
+#define	FLG_BCHANNEL		9	// channel is B-channel
+#define FLG_ECHANNEL		10	// channel is E-channel
+#define FLG_TRANSPARENT		12	// channel use transparent data
+#define FLG_HDLC		13	// channel use hdlc data
+#define FLG_L2DATA		14	// channel use L2 DATA primitivs
+#define FLG_ORIGIN		15	// channel is on origin site 
+/* channel specific stuff */
+/* arcofi specific */
+#define FLG_ARCOFI_TIMER	16
+#define FLG_ARCOFI_ERROR	17
+/* isar specific */
+#define FLG_INITIALIZED		16
+#define FLG_DLEETX		17
+#define FLG_LASTDLE		18
+#define FLG_FIRST		19
+#define FLG_LASTDATA		20
+#define FLG_NMD_DATA		21
+#define FLG_FTI_RUN		22
+#define FLG_LL_OK		23
+#define FLG_LL_CONN		24
+#define FLG_DTMFSEND		25
+
+
+#define MSK_INIT_DCHANNEL	((1<<FLG_DCHANNEL)|(1<<FLG_HDLC))
+#define MSK_INIT_BCHANNEL	(1<<FLG_BCHANNEL)
+#define MSK_INIT_ECHANNEL	(1<<FLG_ECHANNEL)
+
+
+typedef struct _channel_t {
+	mISDNinstance_t		inst;
+	int			channel;
+	/* basic properties */
+	u_long			Flags;
+	u_int			type;
+	u_int			state;
+	/* HW access */
+	u_char			(*read_reg) (void *, u_char);
+	void			(*write_reg) (void *, u_char, u_char);
+	void			(*read_fifo) (void *, u_char *, int);
+	void			(*write_fifo) (void *, u_char *, int);
+	void			*hw;
+	struct timer_list	timer;
+	/* receive data */
+	struct sk_buff		*rx_skb;
+	int			maxlen;
+	int			up_headerlen;
+	/* send data */
+	struct sk_buff		*next_skb;
+	struct sk_buff		*tx_skb;
+	int			tx_idx;
+	/* debug */
+	int			debug;
+	char			*log;
+	/* statistics */
+	int			err_crc;
+	int			err_tx;
+	int			err_rx;
+} channel_t;
+
+extern int	mISDN_initchannel(channel_t *, ulong, int);
+extern int	mISDN_freechannel(channel_t *);
+extern int	mISDN_setpara(channel_t *, mISDN_stPara_t *);
+
+static inline void
+queue_ch_frame(channel_t *ch, u_int pr, int dinfo, struct sk_buff *skb)
+{
+	int	err;
+
+	pr |= test_bit(FLG_L2DATA, &ch->Flags) ? DL_DATA : PH_DATA;
+	if (!skb) {
+		err = mISDN_queue_data(&ch->inst, FLG_MSG_UP, pr, dinfo, 0, NULL, ch->up_headerlen);
+	} else {
+#ifdef CONFIG_MISDN_NETDEV
+		misdn_log_frame(ch->inst.st, skb->data, skb->len, FLG_MSG_UP);
+#endif
+		if (ch->Flags & MSK_INIT_DCHANNEL)
+			mISDN_dt_new_frame(ch->inst.st, D_RX, skb, 1);
+		err = mISDN_queueup_newhead(&ch->inst, 0, pr, dinfo, skb);
+	}
+	if (unlikely(err)) {
+		int_errtxt("err=%d", err);
+		if (skb)
+			dev_kfree_skb(skb);
+	}
+}
+
+static inline int
+channel_senddata(channel_t *ch, int di, struct sk_buff *skb)
+{
+	/* HW lock must be obtained */
+	/* check oversize */
+	if (skb->len <= 0) {
+		printk(KERN_WARNING "%s: skb too small\n", __FUNCTION__);
+		return(-EINVAL);
+	}
+	if (skb->len > ch->maxlen) {
+		printk(KERN_WARNING "%s: skb too large(%d/%d)\n",
+			__FUNCTION__, skb->len, ch->maxlen);
+		return(-EINVAL);
+	}
+	/* check for pending next_skb */
+	if (ch->next_skb) {
+#ifdef DEBUG_NEXT_SKB_EXISTS
+		printk(KERN_WARNING "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n",
+			__FUNCTION__, skb->len, ch->next_skb->len);
+#endif
+		return(-EBUSY);
+	}
+	if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) {
+		test_and_set_bit(FLG_TX_NEXT, &ch->Flags);
+#ifdef CONFIG_MISDN_NETDEV
+		misdn_log_frame(ch->inst.st, skb->data, skb->len, FLG_MSG_DOWN);
+#endif
+		if (ch->Flags & MSK_INIT_DCHANNEL)
+			mISDN_dt_new_frame(ch->inst.st, D_TX, skb, 1);
+		ch->next_skb = skb;
+		return(0);
+	} else {
+		/* write to fifo */
+		ch->tx_skb = skb;
+		ch->tx_idx = 0;
+#ifdef CONFIG_MISDN_NETDEV
+		misdn_log_frame(ch->inst.st, skb->data, skb->len, FLG_MSG_DOWN);
+#endif
+		if (ch->Flags & MSK_INIT_DCHANNEL)
+			mISDN_dt_new_frame(ch->inst.st, D_TX, skb, 1);
+		queue_ch_frame(ch, CONFIRM, di, NULL);
+		return(skb->len);
+	}
+}
+
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/contr.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/contr.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/contr.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,791 @@
+/* $Id: contr.c,v 1.30 2006/09/14 15:51:46 gkelleter Exp $
+ *
+ */
+
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include "m_capi.h"
+#include "helper.h"
+#include "debug.h"
+
+#define contrDebug(contr, lev, fmt, args...) \
+	if (contr->debug & lev) capidebug(lev, fmt, ## args)
+
+void
+ControllerDestr(Controller_t *contr)
+{
+	mISDNinstance_t		*inst = &contr->inst;
+	struct list_head	*item, *next;
+	u_long			flags;
+
+	spin_lock_irqsave(&contr->list_lock, flags);
+	list_for_each_safe(item, next, &contr->Applications) {
+		ApplicationDestr(list_entry(item, Application_t, head), 3);
+	}
+	if (contr->plcis) {
+		Plci_t	*plci = contr->plcis;
+		int	i;
+
+		for (i = 0; i < contr->maxplci; i++) {
+			AppPlci_t	*aplci;
+			if (test_bit(PLCI_STATE_ACTIV, &plci->state)) {
+				if (plci->nAppl) {
+					printk(KERN_ERR "%s: PLCI(%x) still busy (%d)\n",
+						__FUNCTION__, plci->addr, plci->nAppl);
+					list_for_each_safe(item, next, &plci->AppPlcis) {
+						aplci = (AppPlci_t *)item;
+						aplci->contr = NULL;
+						plciDetachAppPlci(plci, aplci);
+						AppPlciDestr(aplci);
+					}
+				}
+			}
+			plci++;
+		}
+		kfree(contr->plcis);
+		contr->plcis = NULL;
+	}
+	list_for_each_safe(item, next, &contr->SSProcesse) {
+		SSProcessDestr(list_entry(item, SSProcess_t, head));
+	}
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	if (contr->ctrl)
+		cdrv_if->detach_ctr(contr->ctrl);
+#else
+	if (contr->ctrl) {
+		detach_capi_ctr(contr->ctrl);
+		kfree(contr->ctrl);
+	}
+#endif
+	contr->ctrl = NULL;
+#ifdef FIXME
+	if (inst->up.peer) {
+		mISDN_ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up);
+	}
+	if (inst->down.peer) {
+		mISDN_ctrl(inst->down.peer, MGR_DISCONNECT | REQUEST, &inst->down);
+	}
+#endif
+	list_for_each_safe(item, next, &contr->linklist) {
+		PLInst_t	*plink = list_entry(item, PLInst_t, list);
+		list_del(&plink->list);
+		kfree(plink);
+	}
+	if (contr->entity != MISDN_ENTITY_NONE)
+		mISDN_ctrl(inst, MGR_DELENTITY | REQUEST, (void *)((u_long)contr->entity));
+	mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+	list_del(&contr->list);
+	spin_unlock_irqrestore(&contr->list_lock, flags);
+	kfree(contr);
+}
+
+void
+ControllerRun(Controller_t *contr)
+{
+	PLInst_t	*plink;
+	int		ret;
+
+	if (contr->inst.st && contr->inst.st->mgr)
+		sprintf(contr->ctrl->manu, "mISDN CAPI controller %s", contr->inst.st->mgr->name);
+	else
+		sprintf(contr->ctrl->manu, "mISDN CAPI");
+	strncpy(contr->ctrl->serial, "0002", CAPI_SERIAL_LEN);
+	contr->ctrl->version.majorversion = 2; 
+	contr->ctrl->version.minorversion = 0;
+	contr->ctrl->version.majormanuversion = 1;
+	contr->ctrl->version.minormanuversion = 0;
+	memset(&contr->ctrl->profile, 0, sizeof(struct capi_profile));
+	contr->ctrl->profile.ncontroller = cpu_to_le16(1);
+	contr->ctrl->profile.nbchannel = cpu_to_le16(contr->nr_bc);
+	contrDebug(contr, CAPI_DBG_INFO, "%s: %s version(%s)",
+		__FUNCTION__, contr->ctrl->manu, contr->ctrl->serial);
+	// FIXME
+	ret = mISDN_ctrl(contr->inst.st, MGR_GLOBALOPT | REQUEST, &contr->ctrl->profile.goptions);
+	if (ret) {
+		/* Fallback on error, minimum set */
+		contr->ctrl->profile.goptions = GLOBALOPT_INTERNAL_CTRL;
+	}
+	/* add options we allways know about FIXME: DTMF */
+	contr->ctrl->profile.goptions |= GLOBALOPT_DTMF |
+					 GLOBALOPT_SUPPLEMENTARY_SERVICE;
+
+	if (contr->nr_bc) {
+		mISDN_pid_t	pidmask;
+
+		memset(&pidmask, 0, sizeof(mISDN_pid_t));
+		pidmask.protocol[1] = 0x03ff;
+		pidmask.protocol[2] = 0x1fff;
+		pidmask.protocol[3] = 0x00ff;
+		if (list_empty(&contr->linklist)) {
+			int_error();
+			ret = -EINVAL;
+		} else {
+			plink = list_entry(contr->linklist.next, PLInst_t, list);
+			ret = mISDN_ctrl(plink->st, MGR_EVALSTACK | REQUEST, &pidmask);
+		}
+		if (ret) {
+			/* Fallback on error, minimum set */
+			int_error();
+			contr->ctrl->profile.support1 = 3; // HDLC, TRANS
+			contr->ctrl->profile.support2 = 3; // X75SLP, TRANS
+			contr->ctrl->profile.support3 = 1; // TRANS
+		} else {
+			contr->ctrl->profile.support1 = pidmask.protocol[1];
+			contr->ctrl->profile.support2 = pidmask.protocol[2];
+			contr->ctrl->profile.support3 = pidmask.protocol[3];
+		}
+	}
+	contrDebug(contr, CAPI_DBG_INFO, "%s: GLOBAL(%08X) B1(%08X) B2(%08X) B3(%08X)",
+		__FUNCTION__, contr->ctrl->profile.goptions, contr->ctrl->profile.support1,
+		contr->ctrl->profile.support2, contr->ctrl->profile.support3);
+	cpu_to_le32s(&contr->ctrl->profile.goptions);
+	cpu_to_le32s(&contr->ctrl->profile.support1);
+	cpu_to_le32s(&contr->ctrl->profile.support2);
+	cpu_to_le32s(&contr->ctrl->profile.support3);
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	contr->ctrl->ready(contr->ctrl);
+#else
+	capi_ctr_ready(contr->ctrl);
+#endif
+}
+
+Application_t
+*getApplication4Id(Controller_t *contr, __u16 ApplId)
+{
+	struct list_head	*item;
+	Application_t		*ap = NULL;
+
+	list_for_each(item, &contr->Applications) {
+		ap = (Application_t *)item;
+		if (ap->ApplId == ApplId)
+			break;
+		ap = NULL;
+	}
+	return(ap);
+}
+
+Plci_t
+*getPlci4Addr(Controller_t *contr, __u32 addr)
+{
+	int i = (addr >> 8) & 0xff;
+
+	if ((i < 1) || (i > contr->maxplci)) {
+		int_error();
+		return(NULL);
+	}
+	return(&contr->plcis[i - 1]);
+}
+
+static void
+RegisterApplication(struct capi_ctr *ctrl, __u16 ApplId, capi_register_params *rp)
+{
+	Controller_t	*contr = ctrl->driverdata;
+	Application_t	*appl;
+	u_long		flags;
+	int		ret;
+
+	contrDebug(contr, CAPI_DBG_APPL, "%s: ApplId(%x)", __FUNCTION__, ApplId);
+	appl = getApplication4Id(contr, ApplId);
+	if (appl) {
+		int_error();
+		return;
+	}
+	spin_lock_irqsave(&contr->list_lock, flags);
+	ret = ApplicationConstr(contr, ApplId, rp);
+	spin_unlock_irqrestore(&contr->list_lock, flags);
+	if (ret) {
+		int_error();
+		return;
+	}
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	contr->ctrl->appl_registered(contr->ctrl, ApplId);
+#endif
+}
+
+static void
+ReleaseApplication(struct capi_ctr *ctrl, __u16 ApplId)
+{
+	Controller_t	*contr = ctrl->driverdata;
+	Application_t	*appl;
+	u_long		flags;
+
+	contrDebug(contr, CAPI_DBG_APPL, "%s: ApplId(%x) caller:%lx", __FUNCTION__, ApplId, __builtin_return_address(0));
+	spin_lock_irqsave(&contr->list_lock, flags);
+	appl = getApplication4Id(contr, ApplId);
+	if (!appl) {
+		spin_unlock_irqrestore(&contr->list_lock, flags);
+		int_error();
+		return;
+	}
+	ApplicationDestr(appl, 1);
+	spin_unlock_irqrestore(&contr->list_lock, flags);
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	contr->ctrl->appl_released(contr->ctrl, ApplId);
+#endif
+}
+
+#ifdef OLDCAPI_DRIVER_INTERFACE
+static void
+#else
+static u16
+#endif
+SendMessage(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+	Controller_t	*contr = ctrl->driverdata;
+	Application_t	*appl;
+	int		ApplId;
+	int		err = CAPI_NOERROR;
+	u16		cmd;
+	AppPlci_t	*aplci;
+	Ncci_t		*ncci;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+
+	ApplId = CAPIMSG_APPID(skb->data);
+	appl = getApplication4Id(contr, ApplId);
+	if (!appl) {
+		int_error();
+		err = CAPI_ILLAPPNR;
+		goto end;
+	}
+
+	hh->prim = CAPI_MESSAGE_REQUEST;
+	hh->dinfo = ApplId;
+	cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
+	contrDebug(contr, CAPI_DBG_CONTR_MSG, "SendMessage: %s caddr(%x)", 
+		capi_cmd2str(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data)),
+		CAPIMSG_CONTROL(skb->data));
+	switch (cmd) {
+		// for NCCI state machine
+		case CAPI_DATA_B3_REQ:
+		case CAPI_DATA_B3_RESP:
+		case CAPI_CONNECT_B3_RESP:
+		case CAPI_CONNECT_B3_ACTIVE_RESP:
+		case CAPI_DISCONNECT_B3_REQ:
+		case CAPI_RESET_B3_REQ:
+		case CAPI_RESET_B3_RESP:
+			aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
+			if (!aplci) {
+				AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
+				dev_kfree_skb(skb);
+				break;
+			}
+			ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_EXACT);
+			if ((!ncci) || (!ncci->link)) {
+				int_error();
+				AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
+				dev_kfree_skb(skb);
+				break;
+			}
+			err = mISDN_queue_message(&ncci->link->inst, 0, skb);
+			if (err) {
+				int_errtxt("mISDN_queue_message return(%d)", err);
+				err = CAPI_MSGBUSY;
+			}
+			break;
+		// new NCCI
+		case CAPI_CONNECT_B3_REQ:
+		// maybe already down NCCI
+		case CAPI_DISCONNECT_B3_RESP:
+		// for PLCI state machine
+		case CAPI_INFO_REQ:
+		case CAPI_ALERT_REQ:
+		case CAPI_CONNECT_REQ:
+		case CAPI_CONNECT_RESP:
+		case CAPI_CONNECT_ACTIVE_RESP:
+		case CAPI_DISCONNECT_REQ:
+		case CAPI_DISCONNECT_RESP:
+		case CAPI_SELECT_B_PROTOCOL_REQ:
+		// for LISTEN state machine
+		case CAPI_LISTEN_REQ:
+		// other
+		case CAPI_FACILITY_REQ:
+		case CAPI_MANUFACTURER_REQ:
+		case CAPI_INFO_RESP:
+			err = mISDN_queue_message(&contr->inst, 0, skb);
+			if (err) {
+				int_errtxt("mISDN_queue_message return(%d)", err);
+				err = CAPI_MSGBUSY;
+			}
+			break;
+		/* need not further action currently, so it can be released here too avoid
+		 * overlap with a release application
+		 */
+		case CAPI_FACILITY_RESP:
+			dev_kfree_skb(skb);
+			break;
+		default:
+			contrDebug(contr, CAPI_DBG_WARN, "SendMessage: %#x %#x not handled!", 
+				CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
+			err = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
+			break;
+	}
+end:
+#ifndef OLDCAPI_DRIVER_INTERFACE
+	return(err);
+#endif
+}
+
+static int
+LoadFirmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+	Controller_t	*contr = ctrl->driverdata;
+	struct firm {
+		int	len;
+		void	*data;
+	} firm;
+	int	retval;
+	
+	firm.len  = data->firmware.len;
+	if (data->firmware.user) {
+		firm.data = vmalloc(data->firmware.len);
+		if (!firm.data)
+			return(-ENOMEM);
+		retval = copy_from_user(firm.data, data->firmware.data, data->firmware.len);
+		if (retval) {
+			vfree(firm.data);
+			return(retval);
+		}
+	} else
+		firm.data = data;
+	mISDN_ctrl(contr->inst.st, MGR_LOADFIRM | REQUEST, &firm);
+	if (data->firmware.user)
+		vfree(firm.data);
+	return(0);
+}
+
+static char *
+procinfo(struct capi_ctr *ctrl)
+{
+	Controller_t *contr = ctrl->driverdata;
+
+	if (CAPI_DBG_INFO & contr->debug)
+		printk(KERN_DEBUG "%s\n", __FUNCTION__);
+	if (!contr)
+		return "";
+	sprintf(contr->infobuf, "-");
+	return contr->infobuf;
+}
+
+static int
+read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
+{
+       int len = 0;
+
+       len += sprintf(page+len, "mISDN_read_proc\n");
+       if (off+count >= len)
+          *eof = 1;
+       if (len < off)
+           return 0;
+       *start = page + off;
+       return ((count < len-off) ? count : len-off);
+};
+
+
+static void
+ResetController(struct capi_ctr *ctrl)
+{
+	Controller_t		*contr = ctrl->driverdata;
+	struct list_head	*item, *next;
+	u_long			flags;
+
+	spin_lock_irqsave(&contr->list_lock, flags);
+	list_for_each_safe(item, next, &contr->Applications) {
+		ApplicationDestr((Application_t *)item, 2);
+	}
+	list_for_each_safe(item, next, &contr->SSProcesse) {
+		SSProcessDestr((SSProcess_t *)item);
+	}
+	spin_unlock_irqrestore(&contr->list_lock, flags);
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	contr->ctrl->reseted(contr->ctrl);
+#else
+	capi_ctr_reseted(contr->ctrl);
+#endif
+}
+
+#ifdef OLDCAPI_DRIVER_INTERFACE
+static void
+Remove_Controller(struct capi_ctr *ctrl)
+{
+	Controller_t *contr = ctrl->driverdata;
+
+	if (CAPI_DBG_INFO & contr->debug)
+		printk(KERN_DEBUG "%s\n", __FUNCTION__);
+}
+
+struct capi_driver mISDN_driver = {
+	"mISDN",
+	"0.01",
+	LoadFirmware,
+	ResetController,
+	Remove_Controller,
+	RegisterApplication,
+	ReleaseApplication,
+	SendMessage,
+	procinfo,
+	read_proc,
+	0,
+	0,
+};
+#endif
+
+void
+ControllerD2Trace(Controller_t *contr, u_char *buf, int len)
+{
+	struct list_head	*item;
+
+	list_for_each(item, &contr->Applications) {
+		applD2Trace((Application_t *)item, buf, len);
+	}
+}
+
+static __inline__ Plci_t *
+getPlci4L3id(Controller_t *contr, u_int l3id)
+{
+	Plci_t	*plci = contr->plcis;
+	int	i;
+
+	for (i = 0; i < contr->maxplci; i++) {
+		if (test_bit(PLCI_STATE_ACTIV, &plci->state) &&
+			(plci->l3id == l3id))
+			return(plci);
+		plci++;
+	}
+	return(NULL);
+}
+
+int
+ControllerNewPlci(Controller_t *contr, Plci_t  **plci_p, u_int l3id)
+{
+	int	i;
+	Plci_t	*plci = contr->plcis;
+
+	for (i = 0; i < contr->maxplci; i++) {
+		if (!test_and_set_bit(PLCI_STATE_ACTIV, &plci->state))
+			break;
+		plci++;
+	}
+	if (i == contr->maxplci) {
+		contrDebug(contr, CAPI_DBG_PLCI, "%s: no free PLCI",
+			__FUNCTION__);
+		return(-EBUSY); //FIXME
+	}
+	*plci_p = plci;
+	if (l3id == MISDN_ID_ANY) {
+		if (contr->entity == MISDN_ENTITY_NONE) {
+			printk(KERN_ERR "mISDN %s: no ENTITY id\n",
+				__FUNCTION__);
+			test_and_clear_bit(PLCI_STATE_ACTIV, &plci->state);
+			return(-EINVAL); //FIXME
+		}
+		plci->l3id = (contr->entity << 16) | plci->addr;
+	} else {
+		plci = getPlci4L3id(contr, l3id);
+		if (plci) {
+			printk(KERN_WARNING "mISDN %s: PLCI(%x) allready has l3id(%x)\n",
+				__FUNCTION__, plci->addr, l3id);
+			test_and_clear_bit(PLCI_STATE_ACTIV, &(*plci_p)->state);
+			return(-EBUSY); 
+		}
+		plci = *plci_p;
+		plci->l3id = l3id;
+	}
+	contrDebug(contr, CAPI_DBG_PLCI, "%s: PLCI(%x) plci(%p,%d) id(%x)",
+		__FUNCTION__, plci->addr, plci, sizeof(*plci), plci->l3id);
+	return(0);
+}
+
+int
+ControllerReleasePlci(Plci_t *plci)
+{
+	if (!plci->contr) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (plci->nAppl) {
+		contrDebug(plci->contr, CAPI_DBG_PLCI, "%s: PLCI(%x) still has %d Applications",
+			__FUNCTION__, plci->addr, plci->nAppl);
+		return(-EBUSY);
+	}
+	if (!list_empty(&plci->AppPlcis)) {
+		int_errtxt("PLCI(%x) AppPlcis list not empty", plci->addr);
+		return(-EBUSY);
+	}
+	test_and_clear_bit(PLCI_STATE_ALERTING, &plci->state);
+	test_and_clear_bit(PLCI_STATE_OUTGOING, &plci->state);
+	plci->l3id = MISDN_ID_NONE;
+	if (!test_and_clear_bit(PLCI_STATE_ACTIV, &plci->state))
+		int_errtxt("PLCI(%x) was not activ", plci->addr);
+	return(0);
+}
+
+void
+ControllerAddSSProcess(Controller_t *contr, SSProcess_t *sp)
+{
+	u_long	flags;
+
+	INIT_LIST_HEAD(&sp->head);
+	sp->contr = contr;
+	sp->addr = contr->addr;
+	spin_lock_irqsave(&contr->list_lock, flags);
+	contr->LastInvokeId++;
+	sp->invokeId = contr->LastInvokeId;
+	list_add(&sp->head, &contr->SSProcesse);
+	spin_unlock_irqrestore(&contr->list_lock, flags);
+}
+
+SSProcess_t
+*getSSProcess4Id(Controller_t *contr, __u16 id)
+{
+	struct list_head	*item;
+	SSProcess_t		*sp = NULL;
+
+	list_for_each(item, &contr->SSProcesse) {
+		sp = (SSProcess_t *)item;
+		if (sp->invokeId == id)
+			break;
+		sp = NULL;
+	}
+	return(sp);
+}
+
+static int
+Controller_function(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	Controller_t	*contr;
+	Plci_t		*plci;
+	int		ret = -EINVAL;
+	mISDN_head_t	*hh;
+
+	hh = mISDN_HEAD_P(skb);
+	contr = inst->privat;
+	contrDebug(contr, CAPI_DBG_CONTR_INFO, "%s: prim(%x) id(%x)",
+		__FUNCTION__, hh->prim, hh->dinfo);
+	if (hh->prim == CAPI_MESSAGE_REQUEST) {
+		Application_t	*appl = getApplication4Id(contr, hh->dinfo);
+		if (!appl) {
+			int_error();
+			return(ret);
+		}
+		ApplicationSendMessage(appl, skb);
+		return(0);
+	} else if (hh->prim == (CC_NEW_CR | INDICATION)) {
+		ret = ControllerNewPlci(contr, &plci, hh->dinfo);
+		if(!ret)
+			dev_kfree_skb(skb);
+	} else if (hh->dinfo == MISDN_ID_DUMMY) {
+		contrDebug(contr, CAPI_DBG_CONTR_INFO, "%s: call Supplementary_l3l4 len %d",
+			__FUNCTION__, skb->len);
+		ret = Supplementary_l3l4(contr, hh->prim, skb);
+	} else {
+		if (!(plci = getPlci4L3id(contr, hh->dinfo))) {
+			contrDebug(contr, CAPI_DBG_WARN, "%s: unknown plci prim(%x) id(%x)",
+				__FUNCTION__, hh->prim, hh->dinfo);
+			return(-ENODEV);
+		}
+		contrDebug(contr, CAPI_DBG_PLCI, "%s: PLCI(%x) plci(%p)", __FUNCTION__, plci->addr, plci);
+		ret = plci_l3l4(plci, hh->prim, skb);
+	}
+	return(ret);
+}
+
+int
+ControllerL4L3(Controller_t *contr, u_int prim, int dinfo, struct sk_buff *skb)
+{
+	return(mISDN_queuedown_newhead(&contr->inst, 0, prim, dinfo, skb));
+}
+
+void
+ControllerPutStatus(Controller_t *contr, char *msg)
+{
+	contrDebug(contr, CAPI_DBG_CONTR, "%s: %s", __FUNCTION__, msg);
+}
+
+int
+ControllerConstr(Controller_t **contr_p, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *ocapi)
+{
+	struct list_head	*head;
+	Controller_t		*contr;
+	int			retval;
+	mISDNstack_t		*cst;
+	PLInst_t		*plink;
+	u_long			flags;
+
+	if (!st)
+		return(-EINVAL);
+	if (list_empty(&st->childlist)) {
+		if ((st->id & FLG_CLONE_STACK) &&
+			(st->childlist.prev != &st->childlist)) {
+			head = st->childlist.prev;
+		} else {
+			printk(KERN_ERR "%s: invalid empty childlist (no clone) stid(%x) childlist(%p<-%p->%p)\n",
+				__FUNCTION__, st->id, st->childlist.prev, &st->childlist, st->childlist.next);
+			return(-EINVAL);
+		}
+	} else
+		head = &st->childlist;
+	if (!pid)
+		return(-EINVAL);
+	contr = kmalloc(sizeof(Controller_t), GFP_KERNEL);
+	if (!contr)
+		return(-ENOMEM);
+	memset(contr, 0, sizeof(Controller_t));
+	INIT_LIST_HEAD(&contr->Applications);
+	INIT_LIST_HEAD(&contr->SSProcesse);
+	INIT_LIST_HEAD(&contr->linklist);
+	spin_lock_init(&contr->list_lock);
+	contr->next_id = 1;
+	memcpy(&contr->inst.pid, pid, sizeof(mISDN_pid_t));
+#ifndef OLDCAPI_DRIVER_INTERFACE
+	if (!(contr->ctrl = kmalloc(sizeof(struct capi_ctr), GFP_KERNEL))) {
+		printk(KERN_ERR "no mem for contr->ctrl\n");
+		int_error();
+		ControllerDestr(contr);
+		return -ENOMEM;
+	}
+	memset(contr->ctrl, 0, sizeof(struct capi_ctr));
+#endif
+	list_for_each_entry(cst, head, list)
+		contr->nr_bc++;
+	if (!contr->nr_bc) {
+		printk(KERN_ERR "no bchannels\n");
+		ControllerDestr(contr);
+		return(-EINVAL); // FIXME
+	}
+	if (contr->nr_bc <= 2)
+		contr->maxplci = CAPI_MAXPLCI_BRI;
+	else if (contr->nr_bc <= 8)
+		contr->maxplci = contr->nr_bc * 2 + 4;
+	else
+		contr->maxplci = CAPI_MAXPLCI_PRI;
+	contr->plcis = kmalloc(contr->maxplci*sizeof(Plci_t), GFP_KERNEL);
+	if (!contr->plcis) {
+		printk(KERN_ERR "no mem for contr->plcis\n");
+		int_error();
+		contr->maxplci = 0;
+		ControllerDestr(contr);
+		return -ENOMEM;
+	}
+	contr->addr = (st->id >> 8) & 0xff;
+	sprintf(contr->inst.name, "CAPI %d", contr->addr);
+	mISDN_init_instance(&contr->inst, ocapi, contr, Controller_function);
+	if (!mISDN_SetHandledPID(ocapi, &contr->inst.pid)) {
+		int_error();
+		ControllerDestr(contr);
+		return(-ENOPROTOOPT);
+	}
+	list_for_each_entry(cst, head, list) {
+		if (!(plink = kmalloc(sizeof(PLInst_t), GFP_KERNEL))) {
+			printk(KERN_ERR "no mem for PLinst\n");
+			int_error();
+			ControllerDestr(contr);
+			return -ENOMEM;
+		}
+		memset(plink, 0, sizeof(PLInst_t));
+		plink->st = cst;
+		plink->inst.st = cst;
+		mISDN_init_instance(&plink->inst, ocapi, plink, NULL);
+		plink->inst.pid.layermask |= ISDN_LAYER(4);
+//		plink->inst.down.stat = IF_NOACTIV;
+		list_add_tail(&plink->list, &contr->linklist);
+	}
+	spin_lock_irqsave(&ocapi->lock, flags);
+	list_add_tail(&contr->list, &ocapi->ilist);
+	spin_unlock_irqrestore(&ocapi->lock, flags);
+	contr->entity = MISDN_ENTITY_NONE;
+	retval = mISDN_ctrl(&contr->inst, MGR_NEWENTITY | REQUEST, NULL);
+	if (retval) {
+		printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%d)\n",
+			__FUNCTION__, retval);
+	}
+	retval = 0;
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	{
+		char	tmp[10];
+
+		sprintf(tmp, "mISDN%d", (st->id >> 8) & 0xff);
+		contr->ctrl = cdrv_if->attach_ctr(&mISDN_driver, tmp, contr);
+		if (!contr->ctrl)
+			retval = -ENODEV;
+	}
+#else
+	contr->ctrl->owner = THIS_MODULE;
+	sprintf(contr->ctrl->name, "mISDN%d", contr->addr);
+	contr->ctrl->driver_name = "mISDN";
+	contr->ctrl->driverdata = contr;
+	contr->ctrl->register_appl = RegisterApplication;
+	contr->ctrl->release_appl = ReleaseApplication;
+	contr->ctrl->send_message = SendMessage;
+	contr->ctrl->load_firmware = LoadFirmware;
+	contr->ctrl->reset_ctr = ResetController;
+	contr->ctrl->procinfo = procinfo;
+	contr->ctrl->ctr_read_proc = read_proc;
+	retval = attach_capi_ctr(contr->ctrl);
+#endif
+	if (!retval) {
+		printk(KERN_DEBUG "contr->addr(%02x) cnr(%02x) st(%08x)\n",
+			contr->addr, contr->ctrl->cnr, st->id);
+		contr->addr = contr->ctrl->cnr;
+		plciInit(contr);
+		mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &contr->inst);
+//		contr->inst.up.stat = IF_DOWN;
+		*contr_p = contr;
+	} else {
+		ControllerDestr(contr);
+	}
+	return retval;
+}
+
+PLInst_t *
+ControllerSelChannel(Controller_t *contr, u_int channel)
+{ 
+	mISDNstack_t	*cst;
+	PLInst_t	*plink;
+	channel_info_t	ci;
+	int		ret;
+
+	if (list_empty(&contr->linklist)) {
+		int_errtxt("no linklist for controller(%x)", contr->addr);
+		return(NULL);
+	}
+	ci.channel = channel;
+	ci.st.p = NULL;
+	ret = mISDN_ctrl(contr->inst.st, MGR_SELCHANNEL | REQUEST, &ci);
+	if (ret) {
+		int_errtxt("MGR_SELCHANNEL ret(%d)", ret);
+		return(NULL);
+	}
+	cst = ci.st.p;
+	list_for_each_entry(plink, &contr->linklist, list) {
+		if (cst == plink->st)
+			return(plink);
+	}
+	return(NULL);
+}
+
+int
+ControllerNextId(Controller_t *contr)
+{
+	int	id;
+
+	id = contr->next_id++;
+	if (id == 0x7fff)
+		contr->next_id = 1;
+	id |= (contr->entity << 16);
+	return(id);
+}
+
+#if 0
+static void
+d2_listener(struct IsdnCardState *cs, u_char *buf, int len)
+{
+	Controller_t *contr = cs->contr;
+
+	if (!contr) {
+		int_error();
+		return;
+	}
+
+	ControllerD2Trace(contr, buf, len);
+}
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/core.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/core.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/core.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,844 @@
+/* $Id: core.c,v 1.40 2007/02/13 10:43:45 crich Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include "core.h"
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+#ifdef CONFIG_SMP
+#include <linux/smp_lock.h>
+#endif
+
+static char		*mISDN_core_revision = "$Revision: 1.40 $";
+static char		*mISDN_core_version = MISDNVERSION ;
+static void (*dt_new_frame) (mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb) = NULL;
+
+LIST_HEAD(mISDN_objectlist);
+static rwlock_t		mISDN_objects_lock = RW_LOCK_UNLOCKED;
+
+LIST_HEAD(mISDN_modulelist);
+static rwlock_t		mISDN_modules_lock = RW_LOCK_UNLOCKED;
+struct modulelist {
+	struct list_head list;
+	struct module *module;
+};
+
+int core_debug;
+
+static u_char		entityarray[MISDN_MAX_ENTITY/8];
+static spinlock_t	entity_lock = SPIN_LOCK_UNLOCKED;
+
+static uint debug;
+static int obj_id;
+
+static int dt_enabled = 0;
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#else
+module_param (debug, uint, S_IRUGO | S_IWUSR);
+#endif
+MODULE_PARM_DESC (debug, "mISDN core debug mask");
+#endif
+
+typedef struct _mISDN_thread {
+	/* thread */
+	struct task_struct	*thread;
+	wait_queue_head_t	waitq;
+	struct semaphore	*notify;
+	u_long			Flags;
+	struct sk_buff_head	workq;
+} mISDN_thread_t;
+
+#define	mISDN_TFLAGS_STARTED	0
+#define mISDN_TFLAGS_RMMOD	1
+#define mISDN_TFLAGS_ACTIV	2
+#define mISDN_TFLAGS_TEST	3
+
+static mISDN_thread_t	mISDN_thread;
+
+static moditem_t modlist[] = {
+	{"mISDN_l1", ISDN_PID_L1_TE_S0},
+	{"mISDN_l2", ISDN_PID_L2_LAPD},
+	{"mISDN_l2", ISDN_PID_L2_B_X75SLP},
+	{"l3udss1", ISDN_PID_L3_DSS1USER},
+	{"mISDN_dtmf", ISDN_PID_L2_B_TRANSDTMF},
+	{NULL, ISDN_PID_NONE}
+};
+
+/* 
+ * kernel thread to do work which cannot be done
+ *in interrupt context 
+ */
+
+static int
+mISDNd(void *data)
+{
+	mISDN_thread_t	*hkt = data;
+
+#ifdef CONFIG_SMP
+	lock_kernel();
+#endif
+	MAKEDAEMON("mISDNd");
+	sigfillset(&current->blocked);
+	hkt->thread = current;
+#ifdef CONFIG_SMP
+	unlock_kernel();
+#endif
+	printk(KERN_DEBUG "mISDNd: kernel daemon started (current:%p)\n", current);
+
+	test_and_set_bit(mISDN_TFLAGS_STARTED, &hkt->Flags);
+
+	for (;;) {
+		int		err;
+		struct sk_buff	*skb;
+		mISDN_headext_t	*hhe;
+
+		if (test_and_clear_bit(mISDN_TFLAGS_RMMOD, &hkt->Flags))
+			break;
+		if (hkt->notify != NULL)
+			up(hkt->notify);
+		wait_event_interruptible(hkt->waitq, ((!skb_queue_empty(&hkt->workq)) || (hkt->Flags & 0xfffffffe)));
+		if (test_and_clear_bit(mISDN_TFLAGS_RMMOD, &hkt->Flags))
+			break;
+		while ((skb = skb_dequeue(&hkt->workq))) {
+			test_and_set_bit(mISDN_TFLAGS_ACTIV, &hkt->Flags);
+			err = -EINVAL;
+			hhe=mISDN_HEADEXT_P(skb);
+			switch (hhe->addr) {
+				case MGR_FUNCTION:
+					err = hhe->func.ctrl(hhe->data[0], hhe->prim,
+						skb->len ? skb->data : NULL);
+					if (err) {
+						printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) failed err(%d)\n",
+							hhe->addr, hhe->prim, err);
+					} else {
+						if (debug)
+							printk(KERN_DEBUG "mISDNd: addr(%x) prim(%x) success\n",
+								hhe->addr, hhe->prim);
+						err--; /* to free skb */
+					}
+					break;
+#ifdef FIXME
+				case MGR_QUEUEIF:
+					err = hhe->func.iff(hhe->data[0], skb);
+					if (err) {
+						printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) failed err(%d)\n",
+							hhe->addr, hhe->prim, err);
+					}
+					break;
+#endif
+				default:
+					int_error();
+					printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) unknown\n",
+						hhe->addr, hhe->prim);
+					err = -EINVAL;
+					break;
+			}
+			if (err)
+				kfree_skb(skb);
+			test_and_clear_bit(mISDN_TFLAGS_ACTIV, &hkt->Flags);
+		}
+		if (test_and_clear_bit(mISDN_TFLAGS_TEST, &hkt->Flags))
+			printk(KERN_DEBUG "mISDNd: test event done\n");
+	}
+	
+	printk(KERN_DEBUG "mISDNd: daemon exit now (current:%p)\n", current);
+	test_and_clear_bit(mISDN_TFLAGS_STARTED, &hkt->Flags);
+	test_and_clear_bit(mISDN_TFLAGS_ACTIV, &hkt->Flags);
+	discard_queue(&hkt->workq);
+	hkt->thread = NULL;
+	if (hkt->notify != NULL)
+		up(hkt->notify);
+	return(0);
+}
+
+mISDNobject_t *
+get_object(int id) {
+	mISDNobject_t	*obj;
+
+	read_lock(&mISDN_objects_lock);
+	list_for_each_entry(obj, &mISDN_objectlist, list)
+		if (obj->id == id) {
+			read_unlock(&mISDN_objects_lock);
+			return(obj);
+		}
+	read_unlock(&mISDN_objects_lock);
+	return(NULL);
+}
+
+static mISDNobject_t *
+find_object(int protocol) {
+	mISDNobject_t	*obj;
+	int		err;
+
+	read_lock(&mISDN_objects_lock);
+	list_for_each_entry(obj, &mISDN_objectlist, list) {
+		err = obj->own_ctrl(NULL, MGR_HASPROTOCOL | REQUEST, &protocol);
+		if (!err)
+			goto unlock;
+		if (err != -ENOPROTOOPT) {
+			if (0 == mISDN_HasProtocol(obj, protocol))
+				goto unlock;
+		}	
+	}
+	obj = NULL;
+unlock:
+	read_unlock(&mISDN_objects_lock);
+	return(obj);
+}
+
+static mISDNobject_t *
+find_object_module(int protocol) {
+#ifdef CONFIG_KMOD
+	int		err;
+#endif
+	moditem_t	*m = modlist;
+	mISDNobject_t	*obj;
+
+	while (m->name != NULL) {
+		if (m->protocol == protocol) {
+#ifdef CONFIG_KMOD
+			if (debug)
+				printk(KERN_DEBUG
+					"find_object_module %s - trying to load\n",
+					m->name);
+			err=request_module(m->name);
+			if (debug)
+				printk(KERN_DEBUG "find_object_module: request_module(%s) returns(%d)\n",
+					m->name, err);
+#else
+			printk(KERN_WARNING "not possible to autoload %s please try to load manually\n",
+				m->name);
+#endif
+			if ((obj = find_object(protocol)))
+				return(obj);
+		}
+		m++;
+	}
+	if (debug)
+		printk(KERN_DEBUG "%s: no module for protocol %x found\n",
+			__FUNCTION__, protocol);
+	return(NULL);
+}
+
+#ifdef FIXME
+static int
+dummy_if(mISDNif_t *hif, struct sk_buff *skb)
+{
+	if (!skb) {
+		printk(KERN_WARNING "%s: hif(%p) without skb\n",
+			__FUNCTION__, hif);
+		return(-EINVAL);
+	}
+	if (debug & DEBUG_DUMMY_FUNC) {
+		mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+
+		printk(KERN_DEBUG "%s: hif(%p) skb(%p) len(%d) prim(%x)\n",
+			__FUNCTION__, hif, skb, skb->len, hh->prim);
+	}
+	dev_kfree_skb_any(skb);
+	return(0);
+}
+#endif
+
+mISDNinstance_t *
+get_next_instance(mISDNstack_t *st, mISDN_pid_t *pid)
+{
+	int		err;
+	mISDNinstance_t	*next;
+	int		layer, proto;
+	mISDNobject_t	*obj;
+
+	layer = mISDN_get_lowlayer(pid->layermask);
+	proto = pid->protocol[layer];
+	next = get_instance(st, layer, proto);
+	if (!next) {
+		obj = find_object(proto);
+		if (!obj)
+			obj = find_object_module(proto);
+		if (!obj) {
+			if (debug)
+				printk(KERN_WARNING "%s: no object found\n",
+					__FUNCTION__);
+			return(NULL);
+		}
+		err = obj->own_ctrl(st, MGR_NEWLAYER | REQUEST, pid);
+		if (err) {
+			printk(KERN_WARNING "%s: newlayer err(%d)\n",
+				__FUNCTION__, err);
+			return(NULL);
+		}
+		next = get_instance(st, layer, proto);
+	}
+	return(next);
+}
+
+static int
+sel_channel(mISDNstack_t *st, channel_info_t *ci)
+{
+	int	err = -EINVAL;
+
+	if (!ci)
+		return(err);
+	if (debug)
+		printk(KERN_DEBUG "%s: st(%p) st->mgr(%p)\n",
+			__FUNCTION__, st, st->mgr);
+	if (st->mgr) {
+		if (st->mgr->obj && st->mgr->obj->own_ctrl) {
+			err = st->mgr->obj->own_ctrl(st->mgr, MGR_SELCHANNEL | REQUEST, ci);
+			if (debug)
+				printk(KERN_DEBUG "%s: MGR_SELCHANNEL(%d)\n", __FUNCTION__, err);
+		} else
+			int_error();
+	} else {
+		printk(KERN_WARNING "%s: no mgr st(%p)\n", __FUNCTION__, st);
+	}
+	if (err) {
+		mISDNstack_t	*cst;
+		u_int		nr = 0;
+
+		ci->st.p = NULL;
+		if (!(ci->channel & (~CHANNEL_NUMBER))) {
+			/* only number is set */
+			struct list_head	*head;
+			if (list_empty(&st->childlist)) {
+				if ((st->id & FLG_CLONE_STACK) &&
+					(st->childlist.prev != &st->childlist)) {
+					head = st->childlist.prev;
+				} else {
+					printk(KERN_WARNING "%s: invalid empty childlist (no clone) stid(%x) childlist(%p<-%p->%p)\n",
+						__FUNCTION__, st->id, st->childlist.prev, &st->childlist, st->childlist.next);
+					return(err);
+				}
+			} else
+				head = &st->childlist;
+			list_for_each_entry(cst, head, list) {
+				nr++;
+				if (nr == (ci->channel & 3)) {
+					ci->st.p = cst;
+					return(0);
+				}
+			}
+		}
+	}
+	return(err);
+}
+
+#ifdef FIXME
+static int
+disconnect_if(mISDNinstance_t *inst, u_int prim, mISDNif_t *hif) {
+	int	err = 0;
+
+	if (hif) {
+		hif->stat = IF_NOACTIV;
+		hif->func = dummy_if;
+		hif->peer = NULL;
+		hif->fdata = NULL;
+	}
+	if (inst)
+		err = inst->obj->own_ctrl(inst, prim, hif);
+	return(err);
+}
+
+static int
+add_if(mISDNinstance_t *inst, u_int prim, mISDNif_t *hif) {
+	mISDNif_t *myif;
+
+	if (!inst)
+		return(-EINVAL);
+	if (!hif)
+		return(-EINVAL);
+	if (hif->stat & IF_UP) {
+		myif = &inst->down;
+	} else if (hif->stat & IF_DOWN) {
+		myif = &inst->up;
+	} else
+		return(-EINVAL);
+	while(myif->clone)
+		myif = myif->clone;
+	myif->clone = hif;
+	hif->predecessor = myif;
+	inst->obj->own_ctrl(inst, prim, hif);
+	return(0);
+}
+#endif
+
+static char tmpbuf[4096];
+static int
+debugout(mISDNinstance_t *inst, logdata_t *log)
+{
+	char *p = tmpbuf;
+
+	if (log->head && *log->head)
+		p += sprintf(p,"%s ", log->head);
+	else
+		p += sprintf(p,"%s ", inst->obj->name);
+	p += vsprintf(p, log->fmt, log->args);
+	printk(KERN_DEBUG "%s\n", tmpbuf);
+	return(0);
+}
+
+static int
+get_hdevice(mISDNdevice_t **dev, int *typ)
+{
+	if (!dev)
+		return(-EINVAL);
+	if (!typ)
+		return(-EINVAL);
+#ifdef FIXME
+	if (*typ == mISDN_RAW_DEVICE) {
+		*dev = get_free_rawdevice();
+		if (!(*dev))
+			return(-ENODEV);
+		return(0);
+	}
+#endif
+	return(-EINVAL);
+}
+
+#ifdef FIXME
+static int
+mgr_queue(void *data, u_int prim, struct sk_buff *skb)
+{
+	mISDN_headext_t *hhe = mISDN_HEADEXT_P(skb);
+
+	hhe->addr = prim;
+	skb_queue_tail(&mISDN_thread.workq, skb);
+	wake_up_interruptible(&mISDN_thread.waitq);
+	return(0);
+}
+
+#endif
+
+static int
+set_stack_req(mISDNstack_t *st, mISDN_pid_t *pid)
+{
+	struct sk_buff	*skb;
+	mISDN_headext_t	*hhe;
+	mISDN_pid_t	*npid;
+	u_char		*pbuf = NULL;
+	int		err;
+
+	if (!(skb = alloc_skb(sizeof(mISDN_pid_t) + pid->maxplen, GFP_ATOMIC)))
+		return(-ENOMEM);
+	hhe = mISDN_HEADEXT_P(skb);
+	hhe->prim = MGR_SETSTACK_NW | REQUEST;
+	hhe->addr = MGR_FUNCTION;
+	hhe->data[0] = st;
+	npid = (mISDN_pid_t *)skb_put(skb, sizeof(mISDN_pid_t));
+	if (pid->maxplen)
+		pbuf = skb_put(skb, pid->maxplen);
+	err = copy_pid(npid, pid, pbuf);
+	if (err) // FIXME error handling
+		int_errtxt("copy_pid error %d", err);
+	hhe->func.ctrl = mISDN_ctrl;
+	skb_queue_tail(&mISDN_thread.workq, skb);
+	wake_up_interruptible(&mISDN_thread.waitq);
+	return(0);
+}
+
+static int
+queue_ctrl_ready(mISDNstack_t *st, void *arg)
+{
+	struct sk_buff	*skb;
+	mISDN_headext_t	*hhe;
+
+	if (!(skb = alloc_skb(4, GFP_ATOMIC)))
+		return(-ENOMEM);
+	if (arg) /* maybe changed for future enhancements */
+		return(-EINVAL);
+	hhe = mISDN_HEADEXT_P(skb);
+	hhe->prim = MGR_CTRLREADY | INDICATION;
+	hhe->addr = MGR_FUNCTION;
+	hhe->data[0] = st;
+	hhe->func.ctrl = do_for_all_layers;
+	skb_queue_tail(&mISDN_thread.workq, skb);
+	wake_up_interruptible(&mISDN_thread.waitq);
+	return(0);
+}
+
+int
+mISDN_alloc_entity(int *entity)
+{
+	u_long	flags;
+
+	spin_lock_irqsave(&entity_lock, flags);
+	*entity = 1;
+	while(*entity < MISDN_MAX_ENTITY) {
+		if (!test_and_set_bit(*entity, (u_long *)&entityarray[0]))
+			break;
+		(*entity)++;
+	}
+	spin_unlock_irqrestore(&entity_lock, flags);
+	if (*entity == MISDN_MAX_ENTITY)
+		return(-EBUSY);
+	return(0);
+}
+
+int
+mISDN_delete_entity(int entity)
+{
+	u_long	flags;
+	int	ret = 0;
+
+	spin_lock_irqsave(&entity_lock, flags);
+	if (!test_and_clear_bit(entity, (u_long *)&entityarray[0])) {
+		printk(KERN_WARNING "mISDN: del_entity(%d) but entity not allocated\n", entity);
+		ret = -ENODEV;
+	}
+	spin_unlock_irqrestore(&entity_lock, flags);
+	return(ret);
+}
+
+static int
+new_entity(mISDNinstance_t *inst)
+{
+	int	entity;
+	int	ret;
+
+	if (!inst)
+		return(-EINVAL);
+	ret = mISDN_alloc_entity(&entity);
+	if (ret) {
+		printk(KERN_WARNING "mISDN: no more entity available(max %d)\n", MISDN_MAX_ENTITY);
+		return(ret);
+	}
+	ret = inst->obj->own_ctrl(inst, MGR_NEWENTITY | CONFIRM, (void *)((u_long)entity));
+	if (ret)
+		mISDN_delete_entity(entity);
+	return(ret);
+}
+
+int 
+mISDN_ctrl(void *data, u_int prim, void *arg) {
+	mISDNstack_t *st = data;
+
+	switch(prim) {
+	    case MGR_NEWSTACK | REQUEST:
+		if (!(st = new_stack(data, arg)))
+			return(-EINVAL);
+		return(0);
+	    case MGR_NEWENTITY | REQUEST:
+		return(new_entity(data));
+	    case MGR_DELENTITY | REQUEST:
+	    case MGR_DELENTITY | INDICATION:
+	    	return(mISDN_delete_entity((u_long)arg & 0xffffffff));
+	    case MGR_REGLAYER | INDICATION:
+		return(register_layer(st, arg));
+	    case MGR_REGLAYER | REQUEST:
+		if (!register_layer(st, arg)) {
+			mISDNinstance_t *inst = arg;
+			return(inst->obj->own_ctrl(arg, MGR_REGLAYER | CONFIRM, NULL));
+		}
+		return(-EINVAL);
+	    case MGR_UNREGLAYER | REQUEST:
+		return(unregister_instance(data));
+#ifdef FIXME
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		return(disconnect_if(data, prim, arg));
+#endif
+	    case MGR_GETDEVICE | REQUEST:
+	    	return(get_hdevice(data, arg));
+	    case MGR_DELDEVICE | REQUEST:
+	    	return(free_device(data));
+#ifdef FIXME
+	    case MGR_QUEUEIF | REQUEST:
+	    	return(mgr_queue(data, MGR_QUEUEIF, arg));
+#endif
+	}
+	if (!data)
+		return(-EINVAL);
+	switch(prim) {
+	    case MGR_ADDLAYER | REQUEST:
+		return(preregister_layer(st, arg));
+	    case MGR_SETSTACK | REQUEST:
+		/* can sleep in case of module reload */
+#ifdef CONFIG_MISDN_NETDEV
+		misdn_netdev_addstack(st);
+#endif
+		return(set_stack_req(st, arg));
+	    case MGR_SETSTACK_NW | REQUEST:
+		return(set_stack(st, arg));
+	    case MGR_CLEARSTACK | REQUEST:
+		return(clear_stack(st, arg ? 1 : 0));
+	    case MGR_DELSTACK | REQUEST:
+		return(release_stack(st));
+	    case MGR_SELCHANNEL | REQUEST:
+		return(sel_channel(st, arg));
+	    case MGR_STOPSTACK | REQUEST:
+		return(mISDN_start_stop(st, 0));
+	    case MGR_STARTSTACK | REQUEST:
+		return(mISDN_start_stop(st, 1));
+#ifdef FIXME
+	    case MGR_ADDIF | REQUEST:
+		return(add_if(data, prim, arg));
+#endif
+	    case MGR_CTRLREADY | INDICATION:
+	    	return(queue_ctrl_ready(st, arg));
+	    case MGR_ADDSTPARA | REQUEST:
+	    case MGR_CLRSTPARA | REQUEST:
+		return(change_stack_para(st, prim, arg));
+#ifdef FIXME
+	    case MGR_CONNECT | REQUEST:
+		return(mISDN_ConnectIF(data, arg));
+#endif
+	    case MGR_EVALSTACK  | REQUEST:
+	    	return(evaluate_stack_pids(data, arg));
+	    case MGR_GLOBALOPT | REQUEST:
+	    case MGR_LOADFIRM | REQUEST:
+	    	if (st->mgr && st->mgr->obj && st->mgr->obj->own_ctrl)
+	    		return(st->mgr->obj->own_ctrl(st->mgr, prim, arg));
+		break;
+	    case MGR_DEBUGDATA | REQUEST:
+		return(debugout(data, arg));
+	    default:
+	    	if (debug)
+			printk(KERN_WARNING "manager prim %x not handled\n", prim);
+		break;
+	}
+	return(-EINVAL);
+}
+
+void
+mISDN_dt_set_callback(void (*new_frame) (mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb))
+{
+	dt_new_frame = new_frame;
+}
+
+void
+mISDN_dt_enable(void)
+{
+	dt_enabled = dt_new_frame ? 1 : 0;
+}
+
+void
+mISDN_dt_disable(void)
+{
+	dt_enabled = 0;
+}
+
+void
+mISDN_dt_new_frame(mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb)
+{
+	if (dt_enabled)
+		dt_new_frame(stack, type, skb, duplicate_skb);
+}
+
+void
+mISDN_module_register(struct module *module)
+{
+	struct modulelist *ml = kmalloc(sizeof(struct modulelist), GFP_KERNEL);
+
+	if (!ml) {
+		printk(KERN_DEBUG "mISDN_register_module: kmalloc failed!\n");
+		return;
+	}
+	ml->module = module;
+	write_lock(&mISDN_modules_lock);
+	list_add(&ml->list, &mISDN_modulelist);
+	write_unlock(&mISDN_modules_lock);
+	if (debug)
+                printk(KERN_DEBUG "mISDN_register_module(%s)\n", module->name);
+}
+
+void
+mISDN_module_unregister(struct module *module)
+{
+	struct modulelist *ml, *mi;
+
+	write_lock(&mISDN_modules_lock);
+	list_for_each_entry_safe(ml, mi, &mISDN_modulelist, list)
+		if (ml->module == module) {
+			list_del(&ml->list);
+			kfree(ml);
+			write_unlock(&mISDN_modules_lock);
+			if (debug)
+			  printk(KERN_DEBUG "mISDN_unregister_module(%s)\n",
+			      module->name);
+			return;
+		}
+	write_unlock(&mISDN_modules_lock);
+}
+
+void
+mISDN_inc_usage(void)
+{
+	struct modulelist *ml;
+	
+	read_lock(&mISDN_modules_lock);
+	list_for_each_entry(ml, &mISDN_modulelist, list)
+		try_module_get(ml->module);
+	read_unlock(&mISDN_modules_lock);
+}
+
+void
+mISDN_dec_usage(void)
+{
+	struct modulelist *ml;
+	
+	read_lock(&mISDN_modules_lock);
+	list_for_each_entry(ml, &mISDN_modulelist, list)
+		module_put(ml->module);
+	read_unlock(&mISDN_modules_lock);
+}
+
+int mISDN_register(mISDNobject_t *obj) {
+	u_long	flags;
+	int	retval;
+
+	if (!obj)
+		return(-EINVAL);
+	write_lock_irqsave(&mISDN_objects_lock, flags);
+	obj->id = obj_id++;
+	list_add_tail(&obj->list, &mISDN_objectlist);
+	write_unlock_irqrestore(&mISDN_objects_lock, flags);
+	// register_prop
+	if (debug)
+		printk(KERN_DEBUG "mISDN_register %s id %x\n", obj->name,
+			obj->id);
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "mISDN_register: obj(%p)\n", obj);
+	retval = mISDN_register_sysfs_obj(obj);
+	if (retval) {
+		printk(KERN_ERR "mISDN_register class_device_register return(%d)\n", retval);
+		write_lock_irqsave(&mISDN_objects_lock, flags);
+		list_del(&obj->list);
+		write_unlock_irqrestore(&mISDN_objects_lock, flags);
+	}
+	return(retval);
+}
+
+int mISDN_unregister(mISDNobject_t *obj) {
+	u_long	flags;
+
+	if (!obj)
+		return(-EINVAL);
+	if (debug)
+		printk(KERN_DEBUG "mISDN_unregister %s %d refs\n",
+			obj->name, obj->refcnt);
+	if (obj->DPROTO.protocol[0]) {
+		if (debug)
+			printk(KERN_DEBUG "mISDN_unregister stacks(%s)\n",
+				obj->name);
+		release_stacks(obj);
+	} else
+		cleanup_object(obj);
+	write_lock_irqsave(&mISDN_objects_lock, flags);
+	list_del(&obj->list);
+	write_unlock_irqrestore(&mISDN_objects_lock, flags);
+
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "mISDN_unregister: mISDN_objectlist(%p<-%p->%p)\n",
+			mISDN_objectlist.prev, &mISDN_objectlist, mISDN_objectlist.next);
+	class_device_unregister(&obj->class_dev);
+	return(0);
+}
+
+int
+mISDNInit(void)
+{
+	DECLARE_MUTEX_LOCKED(sem);
+	int err;
+
+	printk(KERN_INFO "Modular ISDN Stack core version (%s) revision (%s)\n", mISDN_core_version, mISDN_core_revision);
+	core_debug = debug;
+#ifdef MISDN_MEMDEBUG
+	err = __mid_init();
+	if (err)
+		return(err);
+#endif
+	err = mISDN_sysfs_init();
+	if (err)
+		goto sysfs_fail;
+
+	err = init_mISDNdev(debug);
+	if (err)
+		goto dev_fail;
+
+#ifdef CONFIG_MISDN_NETDEV
+	misdn_netdev_init();
+#endif
+
+	init_waitqueue_head(&mISDN_thread.waitq);
+	skb_queue_head_init(&mISDN_thread.workq);
+	mISDN_thread.notify = &sem;
+	kernel_thread(mISDNd, (void *)&mISDN_thread, 0);
+	down(&sem);
+	mISDN_thread.notify = NULL;
+	test_and_set_bit(mISDN_TFLAGS_TEST, &mISDN_thread.Flags);
+	wake_up_interruptible(&mISDN_thread.waitq);
+	return(err);
+
+dev_fail:
+	mISDN_sysfs_cleanup();
+sysfs_fail:
+#ifdef MISDN_MEMDEBUG
+	__mid_cleanup();
+#endif
+	return(err);
+}
+
+void mISDN_cleanup(void) {
+	DECLARE_MUTEX_LOCKED(sem);
+
+	free_mISDNdev();
+	if (!list_empty(&mISDN_objectlist)) {
+		printk(KERN_WARNING "mISDNcore mISDN_objects not empty\n");
+	}
+	check_stacklist();
+	if (!list_empty(&mISDN_modulelist))
+		printk(KERN_WARNING "mISDNcore mISDN_modulelist not empty\n");
+	if (mISDN_thread.thread) {
+		/* abort mISDNd kernel thread */
+		mISDN_thread.notify = &sem;
+		test_and_set_bit(mISDN_TFLAGS_RMMOD, &mISDN_thread.Flags);
+		wake_up_interruptible(&mISDN_thread.waitq);
+		down(&sem);
+		mISDN_thread.notify = NULL;
+	}
+#ifdef MISDN_MEMDEBUG
+	__mid_cleanup();
+#endif
+
+
+#ifdef CONFIG_MISDN_NETDEV
+	misdn_netdev_exit();
+#endif
+	
+	mISDN_sysfs_cleanup();
+	printk(KERN_DEBUG "mISDNcore unloaded\n");
+}
+
+module_init(mISDNInit);
+module_exit(mISDN_cleanup);
+
+EXPORT_SYMBOL(mISDN_module_register);
+EXPORT_SYMBOL(mISDN_module_unregister);
+EXPORT_SYMBOL(mISDN_inc_usage);
+EXPORT_SYMBOL(mISDN_dec_usage);
+EXPORT_SYMBOL(mISDN_ctrl);
+EXPORT_SYMBOL(mISDN_register);
+EXPORT_SYMBOL(mISDN_unregister);
+EXPORT_SYMBOL(mISDN_dt_set_callback);
+EXPORT_SYMBOL(mISDN_dt_enable);
+EXPORT_SYMBOL(mISDN_dt_disable);
+EXPORT_SYMBOL(mISDN_dt_new_frame);
+#ifdef CONFIG_MISDN_NETDEV
+EXPORT_SYMBOL(misdn_log_frame);
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/core.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/core.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/core.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,113 @@
+/* $Id: core.h,v 1.19 2006/12/21 15:25:06 nadi Exp $
+ * 
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/mISDNif.h>
+#include <linux/mISDNdebugtool.h>
+#include "helper.h"
+#ifdef MISDN_MEMDEBUG
+#include "memdbg.h"
+#endif
+
+#define	mISDN_MAJOR		46
+#define mISDN_MINOR_CORE	0
+#define mISDN_MINOR_RAW_MIN	128
+#define mISDN_MINOR_RAW_MAX	255
+
+/* debugging */
+#define DEBUG_CORE_FUNC		0x0001
+//#define DEBUG_DUMMY_FUNC	0x0002
+#define DEBUG_MSG_THREAD_ERR	0x0010
+#define DEBUG_MSG_THREAD_INFO	0x0020
+#define DEBUG_QUEUE_FUNC	0x0040
+#define DEBUG_DEV_OP		0x0100
+#define DEBUG_MGR_FUNC		0x0200
+#define DEBUG_DEV_TIMER		0x0400
+#define DEBUG_RDATA		0x1000
+#define DEBUG_WDATA		0x2000
+#define DEBUG_SYSFS		0x4000
+#define DEBUG_THREADS		0x8000
+
+
+/* from udevice.c */
+extern int		init_mISDNdev(int);
+extern int		free_mISDNdev(void);
+extern mISDNdevice_t	*get_free_rawdevice(void);
+extern int		free_device(mISDNdevice_t *dev);
+
+/* from stack.c */
+extern void		get_stack_info(struct sk_buff *);
+extern int		get_stack_cnt(void);
+extern void		check_stacklist(void);
+extern void		cleanup_object(mISDNobject_t *);
+extern mISDNstack_t	*get_stack4id(u_int);
+extern int		mISDN_start_stack_thread(mISDNstack_t *);
+extern mISDNstack_t	*new_stack(mISDNstack_t *, mISDNinstance_t *);
+extern int		mISDN_start_stop(mISDNstack_t *, int);
+extern int		release_stack(mISDNstack_t *);
+extern int		do_for_all_layers(void *, u_int, void *);
+extern int		change_stack_para(mISDNstack_t *, u_int, mISDN_stPara_t *);
+extern void		release_stacks(mISDNobject_t *);
+extern int		copy_pid(mISDN_pid_t *, mISDN_pid_t *, u_char *);
+extern int		set_stack(mISDNstack_t *, mISDN_pid_t *);
+extern int		clear_stack(mISDNstack_t *, int);
+extern int		evaluate_stack_pids(mISDNstack_t *, mISDN_pid_t *);
+extern mISDNinstance_t	*getlayer4lay(mISDNstack_t *, int);
+extern mISDNinstance_t	*get_instance(mISDNstack_t *, int, int);
+
+/* from sysfs_obj.c */
+extern int		mISDN_register_sysfs_obj(mISDNobject_t *);
+extern int		mISDN_sysfs_init(void);
+extern void		mISDN_sysfs_cleanup(void);
+
+/* from sysfs_inst.c */
+extern int		mISDN_register_sysfs_inst(mISDNinstance_t *);
+extern void		mISDN_unregister_sysfs_inst(mISDNinstance_t *);
+extern int		mISDN_sysfs_inst_init(void);
+extern void		mISDN_sysfs_inst_cleanup(void);
+
+/* from sysfs_stack.c */
+extern int		mISDN_register_sysfs_stack(mISDNstack_t *);
+extern void		mISDN_unregister_sysfs_st(mISDNstack_t *);
+extern int		mISDN_sysfs_st_init(void);
+extern void		mISDN_sysfs_st_cleanup(void);
+
+/* from core.c */
+extern int core_debug;
+extern int		register_layer(mISDNstack_t *, mISDNinstance_t *);
+extern int		preregister_layer(mISDNstack_t *, mISDNinstance_t *);
+extern int		unregister_instance(mISDNinstance_t *);
+extern mISDNinstance_t	*get_next_instance(mISDNstack_t *, mISDN_pid_t *);
+extern mISDNobject_t	*get_object(int);
+extern mISDNinstance_t	*get_instance4id(u_int);
+extern int		mISDN_alloc_entity(int *);
+extern int		mISDN_delete_entity(int);
+extern void		mISDN_module_register(struct module *);
+extern void		mISDN_module_unregister(struct module *);
+extern void		mISDN_inc_usage(void);
+extern void		mISDN_dec_usage(void);
+
+/* debugtool helpers from core.c */
+extern void     mISDN_dt_set_callback(void (*new_frame) (mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb));
+extern void     mISDN_dt_enable(void);
+extern void     mISDN_dt_disable(void);
+extern void     mISDN_dt_new_frame(mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb);
+
+#ifdef CONFIG_MISDN_NETDEV
+/* from netdev_main.c */
+void misdn_log_frame(mISDNstack_t *, 		/* Stack for which to log */
+		unsigned char *,		/* frame to log */
+		int, 				/* frame len */
+		int );				/* direction (0=rx,1=tx) */
+
+int misdn_netdev_addstack(mISDNstack_t *); 	/* create new netdevice by 
+						   stack */
+
+int              misdn_netdev_init(void); 	/* initialize netdevices */
+void             misdn_netdev_exit(void);	/* exit netdeivces */
+#endif
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debug.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debug.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debug.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,98 @@
+/* $Id: debug.c,v 1.7 2006/03/23 13:11:43 keil Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mISDNif.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include "debug.h"
+
+#define mISDN_STATUS_BUFSIZE 4096
+
+static char tmpbuf[mISDN_STATUS_BUFSIZE];
+
+void
+vmISDN_debug(int id, char *head, char *fmt, va_list args)
+{
+/* if head == NULL the fmt contains the full info */
+	char *p = tmpbuf;
+
+	p += sprintf(p,"%d ", id);
+	if (head)
+		p += sprintf(p, "%s ", head);
+	p += vsprintf(p, fmt, args);
+	printk(KERN_DEBUG "%s\n", tmpbuf);
+} 
+
+void
+mISDN_debug(int id, char *head, char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	vmISDN_debug(id, head, fmt, args);
+	va_end(args);
+}
+
+void
+mISDN_debugprint(mISDNinstance_t *inst, char *fmt, ...)
+{
+	logdata_t log;
+
+	va_start(log.args, fmt);
+	log.head = inst->name;
+	log.fmt = fmt;
+	mISDN_ctrl(inst, MGR_DEBUGDATA | REQUEST, &log);
+	va_end(log.args);
+}
+
+char *
+mISDN_getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		if (p)
+			*--p = 0;
+	} else
+		rev = "???";
+	return rev;
+}
+
+int
+mISDN_QuickHex(char *txt, u_char * p, int cnt)
+{
+	register int i;
+	register char *t = txt;
+	register u_char w;
+
+	for (i = 0; i < cnt; i++) {
+		*t++ = ' ';
+		w = (p[i] >> 4) & 0x0f;
+		if (w < 10)
+			*t++ = '0' + w;
+		else
+			*t++ = 'A' - 10 + w;
+		w = p[i] & 0x0f;
+		if (w < 10)
+			*t++ = '0' + w;
+		else
+			*t++ = 'A' - 10 + w;
+	}
+	*t++ = 0;
+	return (t - txt);
+}
+
+EXPORT_SYMBOL(vmISDN_debug);
+EXPORT_SYMBOL(mISDN_debug);
+EXPORT_SYMBOL(mISDN_getrev);
+EXPORT_SYMBOL(mISDN_debugprint);
+EXPORT_SYMBOL(mISDN_QuickHex);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debug.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debug.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debug.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,17 @@
+/* $Id: debug.h,v 1.3 2006/03/06 12:52:07 keil Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+#ifndef MISDN_DEBUG_H
+
+#define MISDN_DEBUG_MANAGER	0x10000
+
+extern void vmISDN_debug(int id, char *head, char *fmt, va_list args);
+extern void mISDN_debug(int id, char *head, char *fmt, ...);
+extern char * mISDN_getrev(const char *revision);
+extern void mISDN_debugprint(mISDNinstance_t *inst, char *fmt, ...);
+extern int mISDN_QuickHex(char *, u_char *, int);
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debugtool.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debugtool.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/debugtool.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,256 @@
+/*
+ * debugtool.c: Debug-Tool for mISDN
+ *
+ * Copyright (C) 2007, Nadi Sarrar
+ *
+ * Nadi Sarrar <nadi at beronet.com>
+ *
+ * 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 of the License, 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., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kthread.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+#include "core.h"
+#include <linux/mISDNdebugtool.h>
+
+#define DT_VERSION 1
+#define MODULE_NAME "mISDN_debugtool"
+
+#define ADDR INADDR_LOOPBACK
+static int PORT = 50501;
+
+static int dt_enabled = 0;
+
+static struct task_struct *thread;
+static struct sk_buff_head skb_q;
+static DECLARE_WAIT_QUEUE_HEAD(skb_q_wait);
+
+static void dt_new_frame (mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb)
+{
+	struct sk_buff *dup;
+	mISDN_dt_header_t *hdr;
+
+	dup = skb ? (duplicate_skb ? skb_copy(skb, GFP_ATOMIC) : skb) : alloc_skb(0, GFP_ATOMIC);
+	if (!dup)
+		return;
+
+	hdr = (mISDN_dt_header_t *)dup->cb;
+	memset(hdr, 0, sizeof(mISDN_dt_header_t));
+	hdr->version = DT_VERSION;
+	hdr->type = type;
+	hdr->stack_id = stack->id;
+	hdr->stack_protocol = stack->pid.modparm_protocol;
+	hdr->time = current_kernel_time();
+	hdr->plength = skb ? skb->len : 0;
+
+	skb_queue_tail(&skb_q, dup);
+	wake_up_interruptible(&skb_q_wait);
+}
+
+static inline int dt_send_buf (struct socket *sock, struct sockaddr_in *addr, unsigned char *buf, int len)
+{
+	struct msghdr msg;
+	struct iovec iov;
+	mm_segment_t oldfs;
+	int size = 0;
+
+	if (!sock->sk)
+		return 0;
+
+	iov.iov_base = buf;
+	iov.iov_len = len;
+
+	msg.msg_flags = 0;
+	msg.msg_name = addr;
+	msg.msg_namelen  = sizeof(struct sockaddr_in);
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = NULL;
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	size = sock_sendmsg(sock, &msg, len);
+	set_fs(oldfs);
+
+	return size;
+}
+
+static inline void dt_send_skb (struct socket *sock, struct sockaddr_in *addr, const struct sk_buff *skb)
+{
+	if (skb->len) {
+		unsigned char buf[sizeof(mISDN_dt_header_t) + skb->len];
+		memcpy(buf, skb->cb, sizeof(mISDN_dt_header_t));
+		memcpy(buf + sizeof(mISDN_dt_header_t), skb->data, skb->len);
+		dt_send_buf(sock, addr, buf, sizeof(buf));
+	} else
+		dt_send_buf(sock, addr, (unsigned char *)skb->cb, sizeof(mISDN_dt_header_t));
+}
+
+static void dt_run (void)
+{
+	int ret;
+	struct sk_buff *skb;
+	struct socket *sock;
+	struct sockaddr_in addr;
+
+	lock_kernel();
+	current->flags |= PF_NOFREEZE;
+	daemonize(MODULE_NAME);
+	allow_signal(SIGKILL);
+	unlock_kernel();
+
+	/* init socket */
+	ret = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
+	if (ret < 0) {
+		printk(KERN_INFO "%s: sock_create failed! (%d)\n", __FUNCTION__, -ret);
+		sock = NULL;
+		return;
+	}
+	memset(&addr, 0, sizeof(struct sockaddr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = htonl(ADDR);
+	addr.sin_port = htons(PORT);
+	ret = sock->ops->connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr), 0);
+	if (ret < 0) {
+		printk(KERN_INFO "%s: Could not connect to socket (%d)\n", __FUNCTION__, -ret);
+		sock_release(sock);
+		sock = NULL;
+		return;
+	}
+
+	printk(KERN_INFO MODULE_NAME ": Using destination port %d.\n", PORT);
+
+	for (;;) {
+		wait_event_interruptible(skb_q_wait, signal_pending(current) || !skb_queue_empty(&skb_q));
+		if (signal_pending(current))
+			break;
+		skb = skb_dequeue(&skb_q);
+		dt_send_skb(sock, &addr, skb);
+		kfree_skb(skb);
+	}
+
+	printk(KERN_INFO MODULE_NAME ": Leaving thread successfully.\n");
+	
+	sock_release(sock);
+}
+
+/* sysfs */
+static void dt_class_release (struct class_device *dev)
+{}
+
+static struct class dt_class = {
+	.name = "mISDN-debugtool",
+#ifndef CLASS_WITHOUT_OWNER
+	.owner = THIS_MODULE,
+#endif
+	.release = &dt_class_release,
+};
+
+static ssize_t attr_show_enabled (struct class *class, char *buf)
+{
+	return sprintf(buf, "%d\n", dt_enabled);
+}
+
+static ssize_t attr_store_enabled (struct class *class, const char *buf, size_t count)
+{
+	if (count > 0 && *buf == '1') {
+		mISDN_dt_enable();
+		dt_enabled = 1;
+	} else {
+		mISDN_dt_disable();
+		dt_enabled = 0;
+	}
+
+	return count;
+}
+
+static CLASS_ATTR(enabled, 0644, attr_show_enabled, attr_store_enabled);
+
+module_param(PORT, int, S_IRUGO);
+
+int __init dt_init(void)
+{
+	/* init queue */
+	skb_queue_head_init(&skb_q);
+
+	/* init sysfs */
+	if (class_register(&dt_class) ||
+		class_create_file(&dt_class, &class_attr_enabled)) {
+		printk(KERN_INFO MODULE_NAME "%s: Failed to initialize sysfs!\n", __FUNCTION__);
+		return -EPERM;
+	}
+
+	/* start thread */
+	thread = kthread_run((void *)dt_run, NULL, MODULE_NAME);
+	if (IS_ERR(thread)) {
+		printk(KERN_INFO MODULE_NAME "%s: Could not start kernel thread!\n", __FUNCTION__);
+		class_unregister(&dt_class);
+		return -ENOMEM;
+	}
+
+	/* register with mISDN */
+	mISDN_module_register(THIS_MODULE);
+	mISDN_dt_set_callback(dt_new_frame);
+
+	printk(KERN_INFO MODULE_NAME ": module loaded\n");
+
+	return 0;
+}
+
+void __exit dt_exit(void)
+{
+	int ret;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if (thread) {
+		lock_kernel();
+		ret = kill_proc(thread->pid, SIGKILL, 1);
+		unlock_kernel();
+		if (ret < 0)
+			printk(KERN_INFO MODULE_NAME ": Unknown error (%d) while trying to terminate kernel thread!\n", -ret);
+		wake_up_interruptible(&skb_q_wait);
+	}
+
+	class_unregister(&dt_class);
+
+	skb_queue_purge(&skb_q);
+
+	printk(KERN_INFO MODULE_NAME ": module unloaded\n");
+}
+
+module_init(dt_init);
+module_exit(dt_exit);
+
+MODULE_DESCRIPTION("Debug-Tool for mISDN");
+MODULE_AUTHOR("Nadi Sarrar <nadi at beronet.com>");
+MODULE_LICENSE("GPL");
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,297 @@
+/* $Id: dsp.h,v 1.13 2007/03/27 15:06:29 jolly Exp $
+ *
+ * Audio support data for ISDN4Linux.
+ *
+ * Copyright 2002/2003 by Andreas Eversberg (jolly at eversberg.eu)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#define DEBUG_DSP_MGR		0x0001
+#define DEBUG_DSP_CORE		0x0002
+#define DEBUG_DSP_DTMF		0x0004
+#define DEBUG_DSP_DTMFCOEFF	0x0008
+#define DEBUG_DSP_CMX		0x0010
+#define DEBUG_DSP_TONE		0x0020
+#define DEBUG_DSP_BLOWFISH	0x0040
+#define DEBUG_DSP_DELAY		0x0080
+
+/* options may be:
+ *
+ * bit 0 = use ulaw instead of alaw
+ * bit 1 = enable hfc hardware accelleration for all channels
+ *
+ */
+#define DSP_OPT_ULAW		(1<<0)
+#define DSP_OPT_NOHARDWARE	(1<<1)
+
+#define FEAT_STATE_INIT	1
+#define FEAT_STATE_WAIT	2
+#define FEAT_STATE_RECEIVED 3
+
+#include <linux/timer.h>
+
+#ifdef MISDN_MEMDEBUG
+#include "memdbg.h"
+#endif
+
+#include "dsp_ecdis.h"
+
+/*
+ * You are now able to choose between the Mark2 and the 
+ * kb1 Echo cancellor. Just comment the one and comment 
+ * out the other.
+ */
+
+
+//#define AGGRESSIVE_SUPPRESSOR
+
+//#include "dsp_mec2.h"
+//#include "dsp_kb1ec.h"
+#include "dsp_mg2ec.h"
+
+
+
+/*
+*  uncomment this one to cancel echo more aggressive
+*/
+//#define AGGRESSIVE_SUPPRESSOR
+
+extern int dsp_options;
+extern int dsp_debug;
+extern int dsp_poll;
+extern int dsp_tics;
+
+/***************
+ * audio stuff *
+ ***************/
+
+extern s32 dsp_audio_alaw_to_s32[256];
+extern s32 dsp_audio_ulaw_to_s32[256];
+extern s32 *dsp_audio_law_to_s32;
+extern u8 dsp_audio_s16_to_law[65536];
+extern u8 dsp_audio_alaw_to_ulaw[256];
+extern u8 dsp_audio_mix_law[65536];
+extern u8 dsp_audio_seven2law[128];
+extern u8 dsp_audio_law2seven[256];
+extern void dsp_audio_generate_s2law_table(void);
+extern void dsp_audio_generate_seven(void);
+extern void dsp_audio_generate_mix_table(void);
+extern void dsp_audio_generate_ulaw_samples(void);
+extern void dsp_audio_generate_volume_changes(void);
+extern u8 dsp_silence;
+
+
+/*************
+ * cmx stuff *
+ *************/
+
+#define MAX_POLL	256	/* maximum number of send-chunks */
+
+#define CMX_BUFF_SIZE	0x8000	/* must be 2**n (0x1000 about 1/2 second) */
+#define CMX_BUFF_HALF	0x4000	/* CMX_BUFF_SIZE / 2 */
+#define CMX_BUFF_MASK	0x7fff	/* CMX_BUFF_SIZE - 1 */
+
+/* how many seconds will we check the lowest delay until the jitter buffer
+   is reduced by that delay */
+#define MAX_SECONDS_JITTER_CHECK 5
+
+extern struct timer_list dsp_spl_tl;
+extern u64 dsp_spl_jiffies;
+
+/* the structure of conferences:
+ *
+ * each conference has a unique number, given by user space.
+ * the conferences are linked in a chain.
+ * each conference has members linked in a chain.
+ * each dsplayer points to a member, each member points to a dsplayer.
+ */
+
+/* all members within a conference (this is linked 1:1 with the dsp) */
+struct _dsp;
+typedef struct _conf_member {
+	struct list_head	list;
+	struct _dsp		*dsp;
+} conf_member_t;
+
+/* the list of all conferences */
+typedef struct _conference {
+	struct list_head	list;
+	u32			id; /* all cmx stacks with the same ID are connected */
+	struct list_head	mlist;
+	int			software; /* conf is processed by software */
+	int			hardware; /* conf is processed by hardware */
+} conference_t;
+
+extern mISDNobject_t dsp_obj;
+
+
+/**************
+ * DTMF stuff *
+ **************/
+
+#define DSP_DTMF_NPOINTS 102
+
+#define ECHOCAN_BUFLEN 4*128
+
+typedef struct _dtmf_t {
+	int 		treshold; /* above this is dtmf (square of) */
+	int		software; /* dtmf uses software decoding */
+	int 		hardware; /* dtmf uses hardware decoding */
+	int 		size; /* number of bytes in buffer */
+	signed short	buffer[DSP_DTMF_NPOINTS]; /* buffers one full dtmf frame */
+	u8		lastwhat, lastdigit;
+	int		count;
+	u8		digits[16]; /* just the dtmf result */
+} dtmf_t;
+
+
+/****************
+ * cancel stuff *
+ ****************/
+
+
+
+/***************
+ * tones stuff *
+ ***************/
+
+typedef struct _tone_t {
+	int		software; /* tones are generated by software */
+	int 		hardware; /* tones are generated by hardware */
+	int		tone;
+	void		*pattern;
+	int		count;
+	int		index;
+	struct timer_list tl;
+} tone_t;
+
+/*****************
+ * general stuff *
+ *****************/
+
+#define DELAY_CHECK 8000
+
+struct dsp_features {
+	int		hfc_id; /* unique id to identify the chip (or -1) */
+	int		hfc_dtmf; /* set if HFCmulti card supports dtmf */
+	int		hfc_loops; /* set if card supports tone loops */
+	int		hfc_echocanhw; /* set if card supports echocancelation*/
+	int		pcm_id; /* unique id to identify the pcm bus (or -1) */
+	int		pcm_slots; /* number of slots on the pcm bus */
+	int		pcm_banks; /* number of IO banks of pcm bus */
+	int		has_jitter; /* data is jittered and unsorted */
+};		
+
+typedef struct _dsp {
+	struct list_head list;
+	mISDNinstance_t	inst;
+	int		b_active;
+	int		echo; /* echo is done by software */
+	int		rx_disabled;
+	int		tx_mix;
+	tone_t		tone;
+	dtmf_t		dtmf;
+	int		tx_volume, rx_volume;
+
+	/* conference stuff */
+	u32		conf_id;
+	conference_t	*conf;
+	conf_member_t	*member;
+
+	/* while we're waiting for the hw */
+	u32		queue_conf_id;
+
+	/* buffer stuff */
+	int		rx_W; /* current write pos for data without timestamp */
+	int		rx_R; /* current read pos for transmit clock */
+	int		tx_W; /* current write pos for transmit data */
+	int		tx_R; /* current read pos for transmit clock */
+	int		delay[MAX_SECONDS_JITTER_CHECK];
+	u8		tx_buff[CMX_BUFF_SIZE];
+	u8		rx_buff[CMX_BUFF_SIZE];
+
+	/* hardware stuff */
+	struct dsp_features features; /* features */
+	struct timer_list feature_tl;
+
+	spinlock_t	feature_lock;
+	int		feature_state;
+	int		pcm_slot_rx; /* current PCM slot (or -1) */
+	int		pcm_bank_rx;
+	int		pcm_slot_tx;
+	int		pcm_bank_tx;
+	int		hfc_conf; /* unique id of current conference (or -1) */
+
+	/* encryption stuff */
+	int		bf_enable;
+	u32		bf_p[18];
+	u32		bf_s[1024];
+	int		bf_crypt_pos;
+	u8		bf_data_in[9];
+	u8		bf_crypt_out[9];
+	int		bf_decrypt_in_pos;
+	int		bf_decrypt_out_pos;
+	u8		bf_crypt_inring[16];
+	u8		bf_data_out[9];
+	int		bf_sync;
+
+	/* echo cancellation stuff */
+	int 		queue_cancel[3];
+	int		cancel_enable;
+	int             cancel_hardware; /*we are using hw echo canc*/
+	struct echo_can_state * ec;      /**< == NULL: echo cancellation disabled;
+				      != NULL: echo cancellation enabled */
+
+	echo_can_disable_detector_state_t* ecdis_rd;
+	echo_can_disable_detector_state_t* ecdis_wr;
+	
+	uint16_t echotimer;
+	uint16_t echostate;
+	uint16_t echolastupdate;
+	
+	char txbuf[ECHOCAN_BUFLEN];
+	int txbuflen;
+	
+	char rxbuf[ECHOCAN_BUFLEN];
+	int rxbuflen;
+	
+} dsp_t;
+
+/* functions */
+
+extern void dsp_change_volume(struct sk_buff *skb, int volume);
+
+extern struct list_head Conf_list;
+extern void dsp_cmx_debug(dsp_t *dsp);
+extern void dsp_cmx_hardware(conference_t *conf, dsp_t *dsp);
+extern int dsp_cmx_conf(dsp_t *dsp, u32 conf_id);
+extern void dsp_cmx_receive(dsp_t *dsp, struct sk_buff *skb);
+#ifdef OLDCMX
+extern struct sk_buff *dsp_cmx_send(dsp_t *dsp, int len, int dinfo);
+#else
+extern void dsp_cmx_send(void *data);
+#endif
+extern void dsp_cmx_transmit(dsp_t *dsp, struct sk_buff *skb);
+extern int dsp_cmx_del_conf_member(dsp_t *dsp);
+extern int dsp_cmx_del_conf(conference_t *conf);
+
+extern void dsp_dtmf_goertzel_init(dsp_t *dsp);
+extern u8 *dsp_dtmf_goertzel_decode(dsp_t *dsp, u8 *data, int len, int fmt);
+
+extern int dsp_tone(dsp_t *dsp, int tone);
+extern void dsp_tone_copy(dsp_t *dsp, u8 *data, int len);
+extern void dsp_tone_timeout(void *arg);
+
+extern void dsp_bf_encrypt(dsp_t *dsp, u8 *data, int len);
+extern void dsp_bf_decrypt(dsp_t *dsp, u8 *data, int len);
+extern int dsp_bf_init(dsp_t *dsp, const u8 *key, unsigned int keylen);
+extern void dsp_bf_cleanup(dsp_t *dsp);
+
+extern void dsp_cancel_tx(dsp_t *dsp, u8 *data, int len);
+extern void dsp_cancel_rx(dsp_t *dsp, u8 *data, int len);
+extern int dsp_cancel_init(dsp_t *dsp, int taps, int training, int delay);
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_arith.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_arith.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_arith.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,347 @@
+#ifndef _ZAPTEL_ARITH_H
+#define _ZAPTEL_ARITH_H
+/*
+ * Handy add/subtract functions to operate on chunks of shorts.
+ * Feel free to add customizations for additional architectures
+ *
+ */
+
+#ifdef CONFIG_ZAPTEL_MMX
+#ifdef ZT_CHUNKSIZE
+static inline void __ACSS(volatile short *dst, const short *src)
+{
+	__asm__ __volatile__ (
+	        "movq 0(%0), %%mm0;\n"
+	        "movq 0(%1), %%mm1;\n"
+                "movq 8(%0), %%mm2;\n"
+	        "movq 8(%1), %%mm3;\n"
+	        "paddsw %%mm1, %%mm0;\n"
+	        "paddsw %%mm3, %%mm2;\n"
+                "movq %%mm0, 0(%0);\n"
+                "movq %%mm2, 8(%0);\n"
+	    : "=r" (dst)
+	    : "r" (src), "0" (dst)
+	    : "memory"
+#if CLOBBERMMX
+	    , "%mm0", "%mm1", "%mm2", "%mm3"
+#endif
+      );
+
+}
+static inline void __SCSS(volatile short *dst, const short *src)
+{
+	__asm__ __volatile__ (
+	        "movq 0(%0), %%mm0;\n"
+	        "movq 0(%1), %%mm1;\n"
+                "movq 8(%0), %%mm2;\n"
+	        "movq 8(%1), %%mm3;\n"
+	        "psubsw %%mm1, %%mm0;\n"
+	        "psubsw %%mm3, %%mm2;\n"
+                "movq %%mm0, 0(%0);\n"
+                "movq %%mm2, 8(%0);\n"
+	    : "=r" (dst)
+	    : "r" (src), "0" (dst)
+	    : "memory"
+#if CLOBBERMMX
+	    , "%mm0", "%mm1", "%mm2", "%mm3"
+#endif
+      );
+
+}
+
+#if (ZT_CHUNKSIZE == 8)
+#define ACSS(a,b) __ACSS(a,b)
+#define SCSS(a,b) __SCSS(a,b)
+#elif (ZT_CHUNKSIZE > 8)
+static inline void ACSS(volatile short *dst, const short *src)
+{
+	int x;
+	for (x=0;x<ZT_CHUNKSIZE;x+=8)
+		__ACSS(dst + x, src + x);
+}
+static inline void SCSS(volatile short *dst, const short *src)
+{
+	int x;
+	for (x=0;x<ZT_CHUNKSIZE;x+=8)
+		__SCSS(dst + x, src + x);
+}
+#else
+#error No MMX for ZT_CHUNKSIZE < 8
+#endif
+#endif
+static inline int CONVOLVE(const int *coeffs, const short *hist, int len)
+{
+	int sum;
+	/* Divide length by 16 */
+	len >>= 4;
+	
+	/* Clear our accumulator, mm4 */
+	
+	/* 
+	
+	   For every set of eight...
+	
+	   Load 16 coefficients into four registers...
+	   Shift each word right 16 to make them shorts...
+	   Pack the resulting shorts into two registers...
+	   With the coefficients now in mm0 and mm2, load the 
+	        history into mm1 and mm3...
+	   Multiply/add mm1 into mm0, and mm3 into mm2...
+	   Add mm2 into mm0 (without saturation, alas).  Now we have two half-results.
+	   Accumulate in mm4 (again, without saturation, alas)
+	*/
+	__asm__ (
+		"pxor %%mm4, %%mm4;\n"
+		"mov %1, %%edi;\n"
+		"mov %2, %%esi;\n"
+		"mov %3, %%ecx;\n"
+		"1:"
+			"movq  0(%%edi), %%mm0;\n"
+			"movq  8(%%edi), %%mm1;\n"
+			"movq 16(%%edi), %%mm2;\n"
+			"movq 24(%%edi), %%mm3;\n"
+			/* can't use 4/5 since 4 is the accumulator for us */
+			"movq 32(%%edi), %%mm6;\n"
+			"movq 40(%%edi), %%mm7;\n"
+			"psrad $16, %%mm0;\n"
+			"psrad $16, %%mm1;\n"
+			"psrad $16, %%mm2;\n"
+			"psrad $16, %%mm3;\n"
+			"psrad $16, %%mm6;\n"
+			"psrad $16, %%mm7;\n"
+			"packssdw %%mm1, %%mm0;\n"
+			"packssdw %%mm3, %%mm2;\n"
+			"packssdw %%mm7, %%mm6;\n"
+			"movq 0(%%esi), %%mm1;\n"
+			"movq 8(%%esi), %%mm3;\n"
+			"movq 16(%%esi), %%mm7;\n"
+			"pmaddwd %%mm1, %%mm0;\n"
+			"pmaddwd %%mm3, %%mm2;\n"
+			"pmaddwd %%mm7, %%mm6;\n"
+			"paddd %%mm6, %%mm4;\n"
+			"paddd %%mm2, %%mm4;\n"
+			"paddd %%mm0, %%mm4;\n"
+			/* Come back and do for the last few bytes */
+			"movq 48(%%edi), %%mm6;\n"
+			"movq 56(%%edi), %%mm7;\n"
+			"psrad $16, %%mm6;\n"
+			"psrad $16, %%mm7;\n"
+			"packssdw %%mm7, %%mm6;\n"
+			"movq 24(%%esi), %%mm7;\n"
+			"pmaddwd %%mm7, %%mm6;\n"
+			"paddd %%mm6, %%mm4;\n"
+			"add $64, %%edi;\n"
+			"add $32, %%esi;\n"
+			"dec %%ecx;\n"
+		"jnz 1b;\n"
+		"movq %%mm4, %%mm0;\n"
+		"psrlq $32, %%mm0;\n"
+		"paddd %%mm0, %%mm4;\n"
+		"movd %%mm4, %0;\n"
+		: "=r" (sum)
+		: "r" (coeffs), "r" (hist), "r" (len)
+		: "%ecx", "%edi", "%esi"
+	);
+		
+	return sum;
+}
+
+static inline void UPDATE(volatile int *taps, const short *history, const int nsuppr, const int ntaps)
+{
+	int i;
+	int correction;
+	for (i=0;i<ntaps;i++) {
+		correction = history[i] * nsuppr;
+		taps[i] += correction;
+	}
+}
+
+static inline void UPDATE2(volatile int *taps, volatile short *taps_short, const short *history, const int nsuppr, const int ntaps)
+{
+	int i;
+	int correction;
+#if 0
+	ntaps >>= 4;
+	/* First, load up taps, */
+	__asm__ (
+		"pxor %%mm4, %%mm4;\n"
+		"mov %0, %%edi;\n"
+		"mov %1, %%esi;\n"
+		"mov %3, %%ecx;\n"
+		"1:"
+		"jnz 1b;\n"
+		"movq %%mm4, %%mm0;\n"
+		"psrlq $32, %%mm0;\n"
+		"paddd %%mm0, %%mm4;\n"
+		"movd %%mm4, %0;\n"
+		: "=r" (taps), "=r" (taps_short)
+		: "r" (history), "r" (nsuppr), "r" (ntaps), "0" (taps)
+		: "%ecx", "%edi", "%esi"
+	);
+#endif
+#if 1
+	for (i=0;i<ntaps;i++) {
+		correction = history[i] * nsuppr;
+		taps[i] += correction;
+		taps_short[i] = taps[i] >> 16;
+	}
+#endif	
+}
+
+static inline int CONVOLVE2(const short *coeffs, const short *hist, int len)
+{
+	int sum;
+	/* Divide length by 16 */
+	len >>= 4;
+	
+	/* Clear our accumulator, mm4 */
+	
+	/* 
+	
+	   For every set of eight...
+	   Load in eight coefficients and eight historic samples, multliply add and
+	   accumulate the result
+	*/
+	__asm__ (
+		"pxor %%mm4, %%mm4;\n"
+		"mov %1, %%edi;\n"
+		"mov %2, %%esi;\n"
+		"mov %3, %%ecx;\n"
+		"1:"
+			"movq  0(%%edi), %%mm0;\n"
+			"movq  8(%%edi), %%mm2;\n"
+			"movq 0(%%esi), %%mm1;\n"
+			"movq 8(%%esi), %%mm3;\n"
+			"pmaddwd %%mm1, %%mm0;\n"
+			"pmaddwd %%mm3, %%mm2;\n"
+			"paddd %%mm2, %%mm4;\n"
+			"paddd %%mm0, %%mm4;\n"
+			"movq  16(%%edi), %%mm0;\n"
+			"movq  24(%%edi), %%mm2;\n"
+			"movq 16(%%esi), %%mm1;\n"
+			"movq 24(%%esi), %%mm3;\n"
+			"pmaddwd %%mm1, %%mm0;\n"
+			"pmaddwd %%mm3, %%mm2;\n"
+			"paddd %%mm2, %%mm4;\n"
+			"paddd %%mm0, %%mm4;\n"
+			"add $32, %%edi;\n"
+			"add $32, %%esi;\n"
+			"dec %%ecx;\n"
+		"jnz 1b;\n"
+		"movq %%mm4, %%mm0;\n"
+		"psrlq $32, %%mm0;\n"
+		"paddd %%mm0, %%mm4;\n"
+		"movd %%mm4, %0;\n"
+		: "=r" (sum)
+		: "r" (coeffs), "r" (hist), "r" (len)
+		: "%ecx", "%edi", "%esi"
+	);
+		
+	return sum;
+}
+static inline short MAX16(const short *y, int len, int *pos)
+{
+	int k;
+	short max = 0;
+	int bestpos = 0;
+	for (k=0;k<len;k++) {
+		if (max < y[k]) {
+			bestpos = k;
+			max = y[k];
+		}
+	}
+	*pos = (len - 1 - bestpos);
+	return max;
+}
+
+
+
+#else
+
+#ifdef ZT_CHUNKSIZE
+static inline void ACSS(short *dst, short *src)
+{
+	int x,sum;
+	/* Add src to dst with saturation, storing in dst */
+	for (x=0;x<ZT_CHUNKSIZE;x++) {
+		sum = dst[x]+src[x];
+		if (sum > 32767)
+			sum = 32767;
+		else if (sum < -32768)
+			sum = -32768;
+		dst[x] = sum;
+	}
+}
+
+static inline void SCSS(short *dst, short *src)
+{
+	int x,sum;
+	/* Add src to dst with saturation, storing in dst */
+	for (x=0;x<ZT_CHUNKSIZE;x++) {
+		sum = dst[x]-src[x];
+		if (sum > 32767)
+			sum = 32767;
+		else if (sum < -32768)
+			sum = -32768;
+		dst[x] = sum;
+	}
+}
+
+#endif	/* ZT_CHUNKSIZE */
+
+static inline int CONVOLVE(const int *coeffs, const short *hist, int len)
+{
+	int x;
+	int sum = 0;
+	for (x=0;x<len;x++)
+		sum += (coeffs[x] >> 16) * hist[x];
+	return sum;
+}
+
+static inline int CONVOLVE2(const short *coeffs, const short *hist, int len)
+{
+	int x;
+	int sum = 0;
+	for (x=0;x<len;x++)
+		sum += coeffs[x] * hist[x];
+	return sum;
+}
+
+static inline void UPDATE(int *taps, const short *history, const int nsuppr, const int ntaps)
+{
+	int i;
+	int correction;
+	for (i=0;i<ntaps;i++) {
+		correction = history[i] * nsuppr;
+		taps[i] += correction;
+	}
+}
+
+static inline void UPDATE2(int *taps, short *taps_short, const short *history, const int nsuppr, const int ntaps)
+{
+	int i;
+	int correction;
+	for (i=0;i<ntaps;i++) {
+		correction = history[i] * nsuppr;
+		taps[i] += correction;
+		taps_short[i] = taps[i] >> 16;
+	}
+}
+
+static inline short MAX16(const short *y, int len, int *pos)
+{
+	int k;
+	short max = 0;
+	int bestpos = 0;
+	for (k=0;k<len;k++) {
+		if (max < y[k]) {
+			bestpos = k;
+			max = y[k];
+		}
+	}
+	*pos = (len - 1 - bestpos);
+	return max;
+}
+
+#endif	/* MMX */
+#endif	/* _ZAPTEL_ARITH_H */

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_audio.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_audio.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_audio.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,583 @@
+/* $Id: dsp_audio.c,v 1.7 2007/03/27 15:06:29 jolly Exp $
+ *
+ * Audio support data for mISDN_dsp.
+ *
+ * Copyright 2002/2003 by Andreas Eversberg (jolly at eversberg.eu)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+#include "dsp.h"
+
+/* ulaw[unsigned char] -> signed 16-bit */
+s32 dsp_audio_ulaw_to_s32[256] =
+{
+	0xffff8284, 0xffff8684, 0xffff8a84, 0xffff8e84,
+	0xffff9284, 0xffff9684, 0xffff9a84, 0xffff9e84,
+	0xffffa284, 0xffffa684, 0xffffaa84, 0xffffae84,
+	0xffffb284, 0xffffb684, 0xffffba84, 0xffffbe84,
+	0xffffc184, 0xffffc384, 0xffffc584, 0xffffc784,
+	0xffffc984, 0xffffcb84, 0xffffcd84, 0xffffcf84,
+	0xffffd184, 0xffffd384, 0xffffd584, 0xffffd784,
+	0xffffd984, 0xffffdb84, 0xffffdd84, 0xffffdf84,
+	0xffffe104, 0xffffe204, 0xffffe304, 0xffffe404,
+	0xffffe504, 0xffffe604, 0xffffe704, 0xffffe804,
+	0xffffe904, 0xffffea04, 0xffffeb04, 0xffffec04,
+	0xffffed04, 0xffffee04, 0xffffef04, 0xfffff004,
+	0xfffff0c4, 0xfffff144, 0xfffff1c4, 0xfffff244,
+	0xfffff2c4, 0xfffff344, 0xfffff3c4, 0xfffff444,
+	0xfffff4c4, 0xfffff544, 0xfffff5c4, 0xfffff644,
+	0xfffff6c4, 0xfffff744, 0xfffff7c4, 0xfffff844,
+	0xfffff8a4, 0xfffff8e4, 0xfffff924, 0xfffff964,
+	0xfffff9a4, 0xfffff9e4, 0xfffffa24, 0xfffffa64,
+	0xfffffaa4, 0xfffffae4, 0xfffffb24, 0xfffffb64,
+	0xfffffba4, 0xfffffbe4, 0xfffffc24, 0xfffffc64,
+	0xfffffc94, 0xfffffcb4, 0xfffffcd4, 0xfffffcf4,
+	0xfffffd14, 0xfffffd34, 0xfffffd54, 0xfffffd74,
+	0xfffffd94, 0xfffffdb4, 0xfffffdd4, 0xfffffdf4,
+	0xfffffe14, 0xfffffe34, 0xfffffe54, 0xfffffe74,
+	0xfffffe8c, 0xfffffe9c, 0xfffffeac, 0xfffffebc,
+	0xfffffecc, 0xfffffedc, 0xfffffeec, 0xfffffefc,
+	0xffffff0c, 0xffffff1c, 0xffffff2c, 0xffffff3c,
+	0xffffff4c, 0xffffff5c, 0xffffff6c, 0xffffff7c,
+	0xffffff88, 0xffffff90, 0xffffff98, 0xffffffa0,
+	0xffffffa8, 0xffffffb0, 0xffffffb8, 0xffffffc0,
+	0xffffffc8, 0xffffffd0, 0xffffffd8, 0xffffffe0,
+	0xffffffe8, 0xfffffff0, 0xfffffff8, 0xffffffff,
+	0x00007d7c, 0x0000797c, 0x0000757c, 0x0000717c,
+	0x00006d7c, 0x0000697c, 0x0000657c, 0x0000617c,
+	0x00005d7c, 0x0000597c, 0x0000557c, 0x0000517c,
+	0x00004d7c, 0x0000497c, 0x0000457c, 0x0000417c,
+	0x00003e7c, 0x00003c7c, 0x00003a7c, 0x0000387c,
+	0x0000367c, 0x0000347c, 0x0000327c, 0x0000307c,
+	0x00002e7c, 0x00002c7c, 0x00002a7c, 0x0000287c,
+	0x0000267c, 0x0000247c, 0x0000227c, 0x0000207c,
+	0x00001efc, 0x00001dfc, 0x00001cfc, 0x00001bfc,
+	0x00001afc, 0x000019fc, 0x000018fc, 0x000017fc,
+	0x000016fc, 0x000015fc, 0x000014fc, 0x000013fc,
+	0x000012fc, 0x000011fc, 0x000010fc, 0x00000ffc,
+	0x00000f3c, 0x00000ebc, 0x00000e3c, 0x00000dbc,
+	0x00000d3c, 0x00000cbc, 0x00000c3c, 0x00000bbc,
+	0x00000b3c, 0x00000abc, 0x00000a3c, 0x000009bc,
+	0x0000093c, 0x000008bc, 0x0000083c, 0x000007bc,
+	0x0000075c, 0x0000071c, 0x000006dc, 0x0000069c,
+	0x0000065c, 0x0000061c, 0x000005dc, 0x0000059c,
+	0x0000055c, 0x0000051c, 0x000004dc, 0x0000049c,
+	0x0000045c, 0x0000041c, 0x000003dc, 0x0000039c,
+	0x0000036c, 0x0000034c, 0x0000032c, 0x0000030c,
+	0x000002ec, 0x000002cc, 0x000002ac, 0x0000028c,
+	0x0000026c, 0x0000024c, 0x0000022c, 0x0000020c,
+	0x000001ec, 0x000001cc, 0x000001ac, 0x0000018c,
+	0x00000174, 0x00000164, 0x00000154, 0x00000144,
+	0x00000134, 0x00000124, 0x00000114, 0x00000104,
+	0x000000f4, 0x000000e4, 0x000000d4, 0x000000c4,
+	0x000000b4, 0x000000a4, 0x00000094, 0x00000084,
+	0x00000078, 0x00000070, 0x00000068, 0x00000060,
+	0x00000058, 0x00000050, 0x00000048, 0x00000040,
+	0x00000038, 0x00000030, 0x00000028, 0x00000020,
+	0x00000018, 0x00000010, 0x00000008, 0x00000000
+};
+
+/* alaw[unsigned char] -> signed 16-bit */
+s32 dsp_audio_alaw_to_s32[256] =
+{
+	0x000013fc, 0xffffec04, 0x00000144, 0xfffffebc,
+	0x0000517c, 0xffffae84, 0x0000051c, 0xfffffae4,
+	0x00000a3c, 0xfffff5c4, 0x00000048, 0xffffffb8,
+	0x0000287c, 0xffffd784, 0x0000028c, 0xfffffd74,
+	0x00001bfc, 0xffffe404, 0x000001cc, 0xfffffe34,
+	0x0000717c, 0xffff8e84, 0x0000071c, 0xfffff8e4,
+	0x00000e3c, 0xfffff1c4, 0x000000c4, 0xffffff3c,
+	0x0000387c, 0xffffc784, 0x0000039c, 0xfffffc64,
+	0x00000ffc, 0xfffff004, 0x00000104, 0xfffffefc,
+	0x0000417c, 0xffffbe84, 0x0000041c, 0xfffffbe4,
+	0x0000083c, 0xfffff7c4, 0x00000008, 0xfffffff8,
+	0x0000207c, 0xffffdf84, 0x0000020c, 0xfffffdf4,
+	0x000017fc, 0xffffe804, 0x0000018c, 0xfffffe74,
+	0x0000617c, 0xffff9e84, 0x0000061c, 0xfffff9e4,
+	0x00000c3c, 0xfffff3c4, 0x00000084, 0xffffff7c,
+	0x0000307c, 0xffffcf84, 0x0000030c, 0xfffffcf4,
+	0x000015fc, 0xffffea04, 0x00000164, 0xfffffe9c,
+	0x0000597c, 0xffffa684, 0x0000059c, 0xfffffa64,
+	0x00000b3c, 0xfffff4c4, 0x00000068, 0xffffff98,
+	0x00002c7c, 0xffffd384, 0x000002cc, 0xfffffd34,
+	0x00001dfc, 0xffffe204, 0x000001ec, 0xfffffe14,
+	0x0000797c, 0xffff8684, 0x000007bc, 0xfffff844,
+	0x00000f3c, 0xfffff0c4, 0x000000e4, 0xffffff1c,
+	0x00003c7c, 0xffffc384, 0x000003dc, 0xfffffc24,
+	0x000011fc, 0xffffee04, 0x00000124, 0xfffffedc,
+	0x0000497c, 0xffffb684, 0x0000049c, 0xfffffb64,
+	0x0000093c, 0xfffff6c4, 0x00000028, 0xffffffd8,
+	0x0000247c, 0xffffdb84, 0x0000024c, 0xfffffdb4,
+	0x000019fc, 0xffffe604, 0x000001ac, 0xfffffe54,
+	0x0000697c, 0xffff9684, 0x0000069c, 0xfffff964,
+	0x00000d3c, 0xfffff2c4, 0x000000a4, 0xffffff5c,
+	0x0000347c, 0xffffcb84, 0x0000034c, 0xfffffcb4,
+	0x000012fc, 0xffffed04, 0x00000134, 0xfffffecc,
+	0x00004d7c, 0xffffb284, 0x000004dc, 0xfffffb24,
+	0x000009bc, 0xfffff644, 0x00000038, 0xffffffc8,
+	0x0000267c, 0xffffd984, 0x0000026c, 0xfffffd94,
+	0x00001afc, 0xffffe504, 0x000001ac, 0xfffffe54,
+	0x00006d7c, 0xffff9284, 0x000006dc, 0xfffff924,
+	0x00000dbc, 0xfffff244, 0x000000b4, 0xffffff4c,
+	0x0000367c, 0xffffc984, 0x0000036c, 0xfffffc94,
+	0x00000f3c, 0xfffff0c4, 0x000000f4, 0xffffff0c,
+	0x00003e7c, 0xffffc184, 0x000003dc, 0xfffffc24,
+	0x000007bc, 0xfffff844, 0x00000008, 0xfffffff8,
+	0x00001efc, 0xffffe104, 0x000001ec, 0xfffffe14,
+	0x000016fc, 0xffffe904, 0x00000174, 0xfffffe8c,
+	0x00005d7c, 0xffffa284, 0x000005dc, 0xfffffa24,
+	0x00000bbc, 0xfffff444, 0x00000078, 0xffffff88,
+	0x00002e7c, 0xffffd184, 0x000002ec, 0xfffffd14,
+	0x000014fc, 0xffffeb04, 0x00000154, 0xfffffeac,
+	0x0000557c, 0xffffaa84, 0x0000055c, 0xfffffaa4,
+	0x00000abc, 0xfffff544, 0x00000058, 0xffffffa8,
+	0x00002a7c, 0xffffd584, 0x000002ac, 0xfffffd54,
+	0x00001cfc, 0xffffe304, 0x000001cc, 0xfffffe34,
+	0x0000757c, 0xffff8a84, 0x0000075c, 0xfffff8a4,
+	0x00000ebc, 0xfffff144, 0x000000d4, 0xffffff2c,
+	0x00003a7c, 0xffffc584, 0x0000039c, 0xfffffc64,
+	0x000010fc, 0xffffef04, 0x00000114, 0xfffffeec,
+	0x0000457c, 0xffffba84, 0x0000045c, 0xfffffba4,
+	0x000008bc, 0xfffff744, 0x00000018, 0xffffffe8,
+	0x0000227c, 0xffffdd84, 0x0000022c, 0xfffffdd4,
+	0x000018fc, 0xffffe704, 0x0000018c, 0xfffffe74,
+	0x0000657c, 0xffff9a84, 0x0000065c, 0xfffff9a4,
+	0x00000cbc, 0xfffff344, 0x00000094, 0xffffff6c,
+	0x0000327c, 0xffffcd84, 0x0000032c, 0xfffffcd4
+};
+
+s32 *dsp_audio_law_to_s32;
+
+/* signed 16-bit -> law */
+u8 dsp_audio_s16_to_law[65536];
+
+/* table is used to generate s16_to_alaw */
+static short dsp_audio_alaw_relations[512] =
+{
+	0x8684, 0x55, 0x8a84, 0xd5, 0x8e84, 0x15, 0x9284, 0x95,
+	0x9684, 0x75, 0x9a84, 0xf5, 0x9e84, 0x35, 0xa284, 0xb5,
+	0xa684, 0x45, 0xaa84, 0xc5, 0xae84, 0x05, 0xb284, 0x85,
+	0xb684, 0x65, 0xba84, 0xe5, 0xbe84, 0x25, 0xc184, 0xa5,
+	0xc384, 0x5d, 0xc584, 0xdd, 0xc784, 0x1d, 0xc984, 0x9d,
+	0xcb84, 0x7d, 0xcd84, 0xfd, 0xcf84, 0x3d, 0xd184, 0xbd,
+	0xd384, 0x4d, 0xd584, 0xcd, 0xd784, 0x0d, 0xd984, 0x8d,
+	0xdb84, 0x6d, 0xdd84, 0xed, 0xdf84, 0x2d, 0xe104, 0xad,
+	0xe204, 0x51, 0xe304, 0xd1, 0xe404, 0x11, 0xe504, 0x91,
+	0xe604, 0x71, 0xe704, 0xf1, 0xe804, 0x31, 0xe904, 0xb1,
+	0xea04, 0x41, 0xeb04, 0xc1, 0xec04, 0x01, 0xed04, 0x81,
+	0xee04, 0x61, 0xef04, 0xe1, 0xf004, 0x21, 0xf0c4, 0x59,
+	0xf0c4, 0xa1, 0xf144, 0xd9, 0xf1c4, 0x19, 0xf244, 0x99,
+	0xf2c4, 0x79, 0xf344, 0xf9, 0xf3c4, 0x39, 0xf444, 0xb9,
+	0xf4c4, 0x49, 0xf544, 0xc9, 0xf5c4, 0x09, 0xf644, 0x89,
+	0xf6c4, 0x69, 0xf744, 0xe9, 0xf7c4, 0x29, 0xf844, 0x57,
+	0xf844, 0xa9, 0xf8a4, 0xd7, 0xf8e4, 0x17, 0xf924, 0x97,
+	0xf964, 0x77, 0xf9a4, 0xf7, 0xf9e4, 0x37, 0xfa24, 0xb7,
+	0xfa64, 0x47, 0xfaa4, 0xc7, 0xfae4, 0x07, 0xfb24, 0x87,
+	0xfb64, 0x67, 0xfba4, 0xe7, 0xfbe4, 0x27, 0xfc24, 0x5f,
+	0xfc24, 0xa7, 0xfc64, 0x1f, 0xfc64, 0xdf, 0xfc94, 0x9f,
+	0xfcb4, 0x7f, 0xfcd4, 0xff, 0xfcf4, 0x3f, 0xfd14, 0xbf,
+	0xfd34, 0x4f, 0xfd54, 0xcf, 0xfd74, 0x0f, 0xfd94, 0x8f,
+	0xfdb4, 0x6f, 0xfdd4, 0xef, 0xfdf4, 0x2f, 0xfe14, 0x53,
+	0xfe14, 0xaf, 0xfe34, 0x13, 0xfe34, 0xd3, 0xfe54, 0x73,
+	0xfe54, 0x93, 0xfe74, 0x33, 0xfe74, 0xf3, 0xfe8c, 0xb3,
+	0xfe9c, 0x43, 0xfeac, 0xc3, 0xfebc, 0x03, 0xfecc, 0x83,
+	0xfedc, 0x63, 0xfeec, 0xe3, 0xfefc, 0x23, 0xff0c, 0xa3,
+	0xff1c, 0x5b, 0xff2c, 0xdb, 0xff3c, 0x1b, 0xff4c, 0x9b,
+	0xff5c, 0x7b, 0xff6c, 0xfb, 0xff7c, 0x3b, 0xff88, 0xbb,
+	0xff98, 0x4b, 0xffa8, 0xcb, 0xffb8, 0x0b, 0xffc8, 0x8b,
+	0xffd8, 0x6b, 0xffe8, 0xeb, 0xfff8, 0x2b, 0xfff8, 0xab,
+	0x0008, 0x2a, 0x0008, 0xaa, 0x0018, 0xea, 0x0028, 0x6a,
+	0x0038, 0x8a, 0x0048, 0x0a, 0x0058, 0xca, 0x0068, 0x4a,
+	0x0078, 0xba, 0x0084, 0x3a, 0x0094, 0xfa, 0x00a4, 0x7a,
+	0x00b4, 0x9a, 0x00c4, 0x1a, 0x00d4, 0xda, 0x00e4, 0x5a,
+	0x00f4, 0xa2, 0x0104, 0x22, 0x0114, 0xe2, 0x0124, 0x62,
+	0x0134, 0x82, 0x0144, 0x02, 0x0154, 0xc2, 0x0164, 0x42,
+	0x0174, 0xb2, 0x018c, 0x32, 0x018c, 0xf2, 0x01ac, 0x72,
+	0x01ac, 0x92, 0x01cc, 0x12, 0x01cc, 0xd2, 0x01ec, 0x52,
+	0x01ec, 0xae, 0x020c, 0x2e, 0x022c, 0xee, 0x024c, 0x6e,
+	0x026c, 0x8e, 0x028c, 0x0e, 0x02ac, 0xce, 0x02cc, 0x4e,
+	0x02ec, 0xbe, 0x030c, 0x3e, 0x032c, 0xfe, 0x034c, 0x7e,
+	0x036c, 0x9e, 0x039c, 0x1e, 0x039c, 0xde, 0x03dc, 0x5e,
+	0x03dc, 0xa6, 0x041c, 0x26, 0x045c, 0xe6, 0x049c, 0x66,
+	0x04dc, 0x86, 0x051c, 0x06, 0x055c, 0xc6, 0x059c, 0x46,
+	0x05dc, 0xb6, 0x061c, 0x36, 0x065c, 0xf6, 0x069c, 0x76,
+	0x06dc, 0x96, 0x071c, 0x16, 0x075c, 0xd6, 0x07bc, 0x56,
+	0x07bc, 0xa8, 0x083c, 0x28, 0x08bc, 0xe8, 0x093c, 0x68,
+	0x09bc, 0x88, 0x0a3c, 0x08, 0x0abc, 0xc8, 0x0b3c, 0x48,
+	0x0bbc, 0xb8, 0x0c3c, 0x38, 0x0cbc, 0xf8, 0x0d3c, 0x78,
+	0x0dbc, 0x98, 0x0e3c, 0x18, 0x0ebc, 0xd8, 0x0f3c, 0x58,
+	0x0f3c, 0xa0, 0x0ffc, 0x20, 0x10fc, 0xe0, 0x11fc, 0x60,
+	0x12fc, 0x80, 0x13fc, 0x00, 0x14fc, 0xc0, 0x15fc, 0x40,
+	0x16fc, 0xb0, 0x17fc, 0x30, 0x18fc, 0xf0, 0x19fc, 0x70,
+	0x1afc, 0x90, 0x1bfc, 0x10, 0x1cfc, 0xd0, 0x1dfc, 0x50,
+	0x1efc, 0xac, 0x207c, 0x2c, 0x227c, 0xec, 0x247c, 0x6c,
+	0x267c, 0x8c, 0x287c, 0x0c, 0x2a7c, 0xcc, 0x2c7c, 0x4c,
+	0x2e7c, 0xbc, 0x307c, 0x3c, 0x327c, 0xfc, 0x347c, 0x7c,
+	0x367c, 0x9c, 0x387c, 0x1c, 0x3a7c, 0xdc, 0x3c7c, 0x5c,
+	0x3e7c, 0xa4, 0x417c, 0x24, 0x457c, 0xe4, 0x497c, 0x64,
+	0x4d7c, 0x84, 0x517c, 0x04, 0x557c, 0xc4, 0x597c, 0x44,
+	0x5d7c, 0xb4, 0x617c, 0x34, 0x657c, 0xf4, 0x697c, 0x74,
+	0x6d7c, 0x94, 0x717c, 0x14, 0x757c, 0xd4, 0x797c, 0x54
+};
+
+
+/* alaw -> ulaw */
+u8 dsp_audio_alaw_to_ulaw[256] =
+{
+	0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
+	0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
+	0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
+	0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
+	0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
+	0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
+	0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
+	0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
+	0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
+	0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
+	0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
+	0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
+	0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
+	0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
+	0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
+	0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
+	0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
+	0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
+	0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
+	0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
+	0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
+	0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
+	0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
+	0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
+	0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
+	0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
+	0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
+	0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
+	0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
+	0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
+	0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
+	0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
+};
+
+/* ulaw -> alaw */
+u8 dsp_audio_ulaw_to_alaw[256] =
+{
+	0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
+	0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
+	0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
+	0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
+	0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
+	0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
+	0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
+	0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
+	0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
+	0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
+	0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
+	0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
+	0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
+	0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
+	0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
+	0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
+	0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
+	0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
+	0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
+	0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
+	0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
+	0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
+	0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
+	0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
+	0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
+	0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
+	0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
+	0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
+	0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
+	0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
+	0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
+	0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
+};
+
+u8 dsp_silence;
+
+
+/*****************************************************
+ * generate table for conversion of s16 to alaw/ulaw *
+ *****************************************************/
+
+void
+dsp_audio_generate_s2law_table(void)
+{
+	int i, j;
+
+	if (dsp_options & DSP_OPT_ULAW) {
+		/* generating ulaw-table */
+		i = j = 0;
+		while(i < 32768) {
+			if (i-32768 > dsp_audio_law_to_s32[j])
+				j++;
+			dsp_audio_s16_to_law[(i-32768) & 0xffff] = j;
+			i++;
+		}
+		j = 255;
+		while(i < 65536) {
+			if (i-32768 > dsp_audio_law_to_s32[j])
+				j--;
+			dsp_audio_s16_to_law[(i-32768) & 0xffff] = j;
+			i++;
+		}
+	} else {
+		/* generating alaw-table */
+		i = j = 0;
+		while(i < 65536) {
+			if (i-32768 > dsp_audio_alaw_relations[j<<1])
+				j++;
+			if (j>255)
+				j=255;
+			dsp_audio_s16_to_law[(i-32768) & 0xffff]
+				 = dsp_audio_alaw_relations[(j<<1)|1];
+			i++;
+		}
+	}
+}
+
+
+/*
+ * the seven bit sample is the number of every second alaw-sample ordered by
+ * aplitude. 0x00 is negative, 0x7f is positive amplitude.
+ */
+u8 dsp_audio_seven2law[128];
+u8 dsp_audio_law2seven[256];
+
+/********************************************************************
+ * generate table for conversion law from/to 7-bit alaw-like sample *
+ ********************************************************************/
+
+void
+dsp_audio_generate_seven(void)
+{
+	int i, j;
+	u8 spl;
+
+	/* conversion from law to seven bit audio */
+	i = 0;
+	while(i < 256) {
+		/* spl is the source: the law-sample (converted to alaw) */
+		spl = i;
+		if (dsp_options & DSP_OPT_ULAW)
+			spl = dsp_audio_ulaw_to_alaw[i];
+		/* find the 7-bit-sample */
+		j = 0;
+		while(j < 256) {
+			if (dsp_audio_alaw_relations[(j<<1)|1] == spl)
+				break;
+			j++;
+		}
+		if (j == 256) {
+			printk(KERN_WARNING "fatal error in %s: alaw-sample '0x%2x' not found in relations-table.\n", __FUNCTION__, spl);
+		}
+		/* write 7-bit audio value */
+		dsp_audio_law2seven[i] = j >> 1;
+		i++;
+	}
+
+	/* conversion from seven bit audio to law */
+	i = 0;
+	while(i < 128) {
+		/* find alaw-spl */
+		spl = dsp_audio_alaw_relations[(i<<2)|1];
+		/* convert to ulaw, if required */
+		if (dsp_options & DSP_OPT_ULAW)
+			spl = dsp_audio_alaw_to_ulaw[spl];
+		/* write 8-bit law sample */
+		dsp_audio_seven2law[i] = spl;
+		i++;
+	}
+}
+
+
+/* mix 2*law -> law */
+u8 dsp_audio_mix_law[65536];
+
+/******************************************************
+ * generate mix table to mix two law samples into one *
+ ******************************************************/
+
+void
+dsp_audio_generate_mix_table(void)
+{
+	int i, j;
+	s32 sample;
+
+	i = 0;
+	while(i < 256) {
+		j = 0;
+		while(j < 256) {
+			sample = dsp_audio_law_to_s32[i];
+			sample += dsp_audio_law_to_s32[j];
+			if (sample > 32767)
+				sample = 32767;
+			if (sample < -32768)
+				sample = -32768;
+			dsp_audio_mix_law[(i<<8)|j] = dsp_audio_s16_to_law[sample & 0xffff];
+			j++;
+		}
+		i++;
+	}
+}
+
+
+/*************************************
+ * generate different volume changes *
+ *************************************/
+
+static u8 dsp_audio_reduce8[256];
+static u8 dsp_audio_reduce7[256];
+static u8 dsp_audio_reduce6[256];
+static u8 dsp_audio_reduce5[256];
+static u8 dsp_audio_reduce4[256];
+static u8 dsp_audio_reduce3[256];
+static u8 dsp_audio_reduce2[256];
+static u8 dsp_audio_reduce1[256];
+static u8 dsp_audio_increase1[256];
+static u8 dsp_audio_increase2[256];
+static u8 dsp_audio_increase3[256];
+static u8 dsp_audio_increase4[256];
+static u8 dsp_audio_increase5[256];
+static u8 dsp_audio_increase6[256];
+static u8 dsp_audio_increase7[256];
+static u8 dsp_audio_increase8[256];
+
+static u8 *dsp_audio_volume_change[16] = {
+	dsp_audio_reduce8,
+	dsp_audio_reduce7,
+	dsp_audio_reduce6,
+	dsp_audio_reduce5,
+	dsp_audio_reduce4,
+	dsp_audio_reduce3,
+	dsp_audio_reduce2,
+	dsp_audio_reduce1,
+	dsp_audio_increase1,
+	dsp_audio_increase2,
+	dsp_audio_increase3,
+	dsp_audio_increase4,
+	dsp_audio_increase5,
+	dsp_audio_increase6,
+	dsp_audio_increase7,
+	dsp_audio_increase8,
+};
+
+void
+dsp_audio_generate_volume_changes(void)
+{
+	register s32 sample;
+	int i;
+
+	i = 0;
+	while(i < 256) {
+		dsp_audio_reduce8[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>8) & 0xffff];
+		dsp_audio_reduce7[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>7) & 0xffff];
+		dsp_audio_reduce6[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>6) & 0xffff];
+		dsp_audio_reduce5[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>5) & 0xffff];
+		dsp_audio_reduce4[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>4) & 0xffff];
+		dsp_audio_reduce3[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>3) & 0xffff];
+		dsp_audio_reduce2[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>2) & 0xffff];
+		dsp_audio_reduce1[i] = dsp_audio_s16_to_law[(dsp_audio_law_to_s32[i]>>1) & 0xffff];
+		sample = dsp_audio_law_to_s32[i] << 1;
+		if (sample < -32768)
+			sample = -32768;
+		else if (sample > 32767)
+			sample = 32767;
+		dsp_audio_increase1[i] = dsp_audio_s16_to_law[sample & 0xffff];
+		sample = dsp_audio_law_to_s32[i] << 2;
+		if (sample < -32768)
+			sample = -32768;
+		else if (sample > 32767)
+			sample = 32767;
+		dsp_audio_increase2[i] = dsp_audio_s16_to_law[sample & 0xffff];
+		sample = dsp_audio_law_to_s32[i] << 3;
+		if (sample < -32768)
+			sample = -32768;
+		else if (sample > 32767)
+			sample = 32767;
+		dsp_audio_increase3[i] = dsp_audio_s16_to_law[sample & 0xffff];
+		sample = dsp_audio_law_to_s32[i] << 4;
+		if (sample < -32768)
+			sample = -32768;
+		else if (sample > 32767)
+			sample = 32767;
+		dsp_audio_increase4[i] = dsp_audio_s16_to_law[sample & 0xffff];
+		sample = dsp_audio_law_to_s32[i] << 5;
+		if (sample < -32768)
+			sample = -32768;
+		else if (sample > 32767)
+			sample = 32767;
+		dsp_audio_increase5[i] = dsp_audio_s16_to_law[sample & 0xffff];
+		sample = dsp_audio_law_to_s32[i] << 6;
+		if (sample < -32768)
+			sample = -32768;
+		else if (sample > 32767)
+			sample = 32767;
+		dsp_audio_increase6[i] = dsp_audio_s16_to_law[sample & 0xffff];
+		sample = dsp_audio_law_to_s32[i] << 7;
+		if (sample < -32768)
+			sample = -32768;
+		else if (sample > 32767)
+			sample = 32767;
+		dsp_audio_increase7[i] = dsp_audio_s16_to_law[sample & 0xffff];
+		sample = dsp_audio_law_to_s32[i] << 8;
+		if (sample < -32768)
+			sample = -32768;
+		else if (sample > 32767)
+			sample = 32767;
+		dsp_audio_increase8[i] = dsp_audio_s16_to_law[sample & 0xffff];
+
+		i++;
+	}
+}
+
+
+/**************************************
+ * change the volume of the given skb *
+ **************************************/
+
+/* this is a helper function for changing volume of skb. the range may be
+ * -8 to 8, which is a shift to the power of 2. 0 == no volume, 3 == volume*8
+ */
+void
+dsp_change_volume(struct sk_buff *skb, int volume)
+{
+	u8 *volume_change;
+	int i, ii;
+	u8 *p;
+	int shift;
+
+	if (volume == 0)
+		return;
+
+	/* get correct conversion table */
+	if (volume < 0) {
+		shift = volume + 8;
+		if (shift < 0)
+			shift = 0;
+	} else {
+		shift = volume + 7;
+		if (shift > 15)
+			shift = 15;
+	}
+	volume_change = dsp_audio_volume_change[shift];
+	i = 0;
+	ii = skb->len;
+	p = skb->data;
+	/* change volume */
+	while(i < ii) {
+		*p = volume_change[*p];
+		p++;
+		i++;
+	}
+}
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_biquad.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_biquad.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_biquad.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,73 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * biquad.h - General telephony bi-quad section routines (currently this just
+ *            handles canonic/type 2 form)
+ *
+ * Written by Steve Underwood <steveu at coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * 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 of the License, 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.
+ *
+ */
+
+typedef struct
+{
+    int32_t gain;
+    int32_t a1;
+    int32_t a2;
+    int32_t b1;
+    int32_t b2;
+
+    int32_t z1;
+    int32_t z2;
+} biquad2_state_t;
+
+static inline void biquad2_init (biquad2_state_t *bq,
+                	 	 int32_t gain,
+		                 int32_t a1,
+            	                 int32_t a2,
+		                 int32_t b1,
+		                 int32_t b2)
+{
+    bq->gain = gain;
+    bq->a1 = a1;
+    bq->a2 = a2;
+    bq->b1 = b1;
+    bq->b2 = b2;
+    
+    bq->z1 = 0;
+    bq->z2 = 0;    
+}
+/*- End of function --------------------------------------------------------*/
+    
+static inline int16_t biquad2 (biquad2_state_t *bq, int16_t sample)
+{
+    int32_t y;
+    int32_t z0;
+    
+    z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2;
+    y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2;
+
+    bq->z2 = bq->z1;
+    bq->z1 = z0 >> 15;
+    y >>= 15;
+    return  y;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_blowfish.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_blowfish.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_blowfish.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,658 @@
+/* $Id: dsp_blowfish.c,v 1.5 2007/03/27 15:06:29 jolly Exp $
+ *
+ * Blowfish encryption/decryption for mISDN_dsp.
+ *
+ * Copyright Andreas Eversberg (jolly at eversberg.eu)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+#include "dsp.h"
+
+/*
+ * how to encode a sample stream to 64-bit blocks that will be encryped
+ *
+ * first of all, data is collected until a block of 9 samples are received.
+ * of course, a packet may have much more than 9 sample, but is may have
+ * not excacly the multiple of 9 samples. if there is a rest, the next
+ * received data will complete the block.
+ *
+ * the block is then converted to 9 uLAW samples without the least sigificant
+ * bit. the result is a 7-bit encoded sample.
+ *
+ * the samples will be reoganised to form 8 bytes of data:
+ * (5(6) means: encoded sample no. 5, bit 6)
+ *
+ * 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) 0(0) 1(6)
+ * 1(5) 1(4) 1(3) 1(2) 1(1) 1(0) 2(6) 2(5)
+ * 2(4) 2(3) 2(2) 2(1) 2(0) 3(6) 3(5) 3(4)
+ * 3(3) 3(2) 3(1) 3(0) 4(6) 4(5) 4(4) 4(3)
+ * 4(2) 4(1) 4(0) 5(6) 5(5) 5(4) 5(3) 5(2)
+ * 5(1) 5(0) 6(6) 6(5) 6(4) 6(3) 6(2) 6(1)
+ * 6(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0)
+ * 8(6) 8(5) 8(4) 8(3) 8(2) 8(1) 8(0)
+ *
+ * the missing bit 0 of the last byte is filled with some
+ * random noise, to fill all 8 bytes.
+ *
+ * the 8 bytes will be encrypted using blowfish.
+ *
+ * the result will be converted into 9 bytes. the bit 7 is used for
+ * checksumme (CS) for sync (0, 1) and for the last bit:
+ * (5(6) means: crypted byte 5, bit 6)
+ *
+ * 1    0(7) 0(6) 0(5) 0(4) 0(3) 0(2) 0(1)
+ * 0    0(0) 1(7) 1(6) 1(5) 1(4) 1(3) 1(2)
+ * 0    1(1) 1(0) 2(7) 2(6) 2(5) 2(4) 2(3)
+ * 0    2(2) 2(1) 2(0) 3(7) 3(6) 3(5) 3(4)
+ * 0    3(3) 3(2) 3(1) 3(0) 4(7) 4(6) 4(5) 
+ * CS   4(4) 4(3) 4(2) 4(1) 4(0) 5(7) 5(6)
+ * CS   5(5) 5(4) 5(3) 5(2) 5(1) 5(0) 6(7) 
+ * CS   6(6) 6(5) 6(4) 6(3) 6(2) 6(1) 6(0)
+ * 7(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0)
+ *
+ * the checksum is used to detect transmission errors and frame drops.
+ *
+ * synchronisation of received block is done by shifting the upper bit of each
+ * byte (bit 7) to a shift register. if the rigister has the first five bits
+ * (10000), this is used to find the sync. only if sync has been found, the
+ * current block of 9 received bytes are decrypted. before that the check
+ * sum is calculated. if it is incorrect the block is dropped.
+ * this will avoid loud noise due to corrupt encrypted data.
+ *
+ * if the last block is corrupt, the current decoded block is repeated
+ * until a valid block has been received. 
+ */
+
+/* some blowfish parts are taken from the crypto-api for faster implementation
+*/
+
+struct bf_ctx {
+	u32 p[18];
+	u32 s[1024];
+};
+
+static const u32 bf_pbox[16 + 2] = {
+	0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+	0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+	0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+	0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+	0x9216d5d9, 0x8979fb1b,
+};
+
+static const u32 bf_sbox[256 * 4] = {
+	0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
+	0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
+	0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+	0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
+	0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
+	0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+	0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
+	0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
+	0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+	0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
+	0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
+	0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+	0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
+	0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
+	0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+	0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
+	0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
+	0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+	0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
+	0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
+	0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+	0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
+	0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
+	0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+	0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
+	0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
+	0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+	0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
+	0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
+	0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+	0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
+	0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
+	0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+	0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
+	0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
+	0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+	0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
+	0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
+	0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+	0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
+	0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
+	0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+	0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
+	0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
+	0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+	0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
+	0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
+	0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+	0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
+	0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
+	0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+	0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
+	0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
+	0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+	0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
+	0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
+	0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+	0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
+	0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
+	0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+	0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
+	0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
+	0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+	0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+	0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
+	0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
+	0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+	0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
+	0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
+	0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+	0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
+	0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
+	0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+	0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
+	0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
+	0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+	0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
+	0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
+	0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+	0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
+	0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
+	0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+	0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
+	0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
+	0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+	0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
+	0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
+	0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+	0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
+	0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
+	0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+	0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
+	0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
+	0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+	0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
+	0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
+	0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+	0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
+	0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
+	0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+	0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
+	0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
+	0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+	0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
+	0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
+	0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+	0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
+	0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
+	0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+	0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
+	0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
+	0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+	0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
+	0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
+	0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+	0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
+	0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
+	0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+	0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
+	0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
+	0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+	0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
+	0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
+	0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+	0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
+	0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
+	0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+	0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+	0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
+	0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
+	0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+	0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
+	0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
+	0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+	0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
+	0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
+	0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+	0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
+	0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
+	0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+	0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
+	0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
+	0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+	0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
+	0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
+	0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+	0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
+	0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
+	0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+	0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
+	0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
+	0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+	0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
+	0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
+	0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+	0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
+	0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
+	0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+	0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
+	0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
+	0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+	0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
+	0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
+	0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+	0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
+	0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
+	0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+	0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
+	0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
+	0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+	0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
+	0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
+	0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+	0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
+	0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
+	0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+	0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
+	0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
+	0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+	0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
+	0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
+	0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+	0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
+	0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
+	0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+	0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
+	0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
+	0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+	0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
+	0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
+	0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+	0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+	0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
+	0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
+	0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+	0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
+	0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
+	0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+	0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
+	0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
+	0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+	0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
+	0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
+	0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+	0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
+	0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
+	0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+	0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
+	0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
+	0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+	0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
+	0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
+	0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+	0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
+	0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
+	0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+	0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
+	0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
+	0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+	0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
+	0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
+	0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+	0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
+	0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
+	0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+	0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
+	0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
+	0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+	0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
+	0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
+	0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+	0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
+	0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
+	0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+	0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
+	0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
+	0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+	0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
+	0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
+	0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+	0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
+	0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
+	0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+	0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
+	0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
+	0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+	0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
+	0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
+	0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+	0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
+	0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
+	0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+	0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
+	0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
+	0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+	0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+};
+
+/* 
+ * Round loop unrolling macros, S is a pointer to a S-Box array
+ * organized in 4 unsigned longs at a row.
+ */
+#define GET32_3(x) (((x) & 0xff))
+#define GET32_2(x) (((x) >> (8)) & (0xff))
+#define GET32_1(x) (((x) >> (16)) & (0xff))
+#define GET32_0(x) (((x) >> (24)) & (0xff))
+
+#define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \
+          S[512 + GET32_2(x)]) + S[768 + GET32_3(x)])
+
+#define EROUND(a, b, n)  b ^= P[n]; a ^= bf_F (b)
+#define DROUND(a, b, n)  a ^= bf_F (b); b ^= P[n]
+
+
+/*
+ * encrypt isdn data frame
+ * every block with 9 samples is encrypted
+ */
+void
+dsp_bf_encrypt(dsp_t *dsp, u8 *data, int len)
+{
+	int i = 0, j = dsp->bf_crypt_pos;
+	u8 *bf_data_in = dsp->bf_data_in;
+	u8 *bf_crypt_out = dsp->bf_crypt_out;
+	u32 *P = dsp->bf_p;
+	u32 *S = dsp->bf_s;
+	u32 yl, yr;
+	u32 cs;
+	u8 nibble;
+
+	while(i < len) {
+		/* collect a block of 9 samples */
+		if (j < 9) {
+			bf_data_in[j] = *data;
+			*data++ = bf_crypt_out[j++];
+			i++;
+			continue;
+		}
+		j = 0;
+		/* transcode 9 samples xlaw to 8 bytes */
+		yl = dsp_audio_law2seven[bf_data_in[0]];
+		yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[1]];
+		yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[2]];
+		yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[3]];
+		yr = nibble = dsp_audio_law2seven[bf_data_in[4]];
+		yl = (yl<<4) | (nibble>>3);
+		yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[5]];
+		yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[6]];
+		yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[7]];
+		yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[8]];
+		yr = (yr<<1) | (bf_data_in[0] & 1); /* fill unused bit with random noise of audio input */
+		/* encrypt */
+		EROUND(yr, yl, 0);
+		EROUND(yl, yr, 1);
+		EROUND(yr, yl, 2);
+		EROUND(yl, yr, 3);
+		EROUND(yr, yl, 4);
+		EROUND(yl, yr, 5);
+		EROUND(yr, yl, 6);
+		EROUND(yl, yr, 7);
+		EROUND(yr, yl, 8);
+		EROUND(yl, yr, 9);
+		EROUND(yr, yl, 10);
+		EROUND(yl, yr, 11);
+		EROUND(yr, yl, 12);
+		EROUND(yl, yr, 13);
+		EROUND(yr, yl, 14);
+		EROUND(yl, yr, 15);
+		yl ^= P[16];
+		yr ^= P[17];
+		/* calculate 3-bit checksumme */
+		cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15)
+			^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30)
+			^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10)
+			^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25)
+			^ (yr>>28) ^ (yr>>31);
+		/* transcode 8 crypted bytes to 9 data bytes with sync
+		 * and checksum information
+		 */
+		bf_crypt_out[0] = (yl>>25) | 0x80;
+		bf_crypt_out[1] = (yl>>18) & 0x7f;
+		bf_crypt_out[2] = (yl>>11) & 0x7f;
+		bf_crypt_out[3] = (yl>>4) & 0x7f;
+		bf_crypt_out[4] = ((yl<<3) & 0x78) | ((yr>>29) & 0x07);
+		bf_crypt_out[5] = ((yr>>22) & 0x7f) | ((cs<<5) & 0x80);
+		bf_crypt_out[6] = ((yr>>15) & 0x7f) | ((cs<<6) & 0x80);
+		bf_crypt_out[7] = ((yr>>8) & 0x7f) | (cs<<7);
+		bf_crypt_out[8] = yr;
+	}
+
+	/* write current count */
+	dsp->bf_crypt_pos = j;
+			
+}
+
+
+/*
+ * decrypt isdn data frame
+ * every block with 9 bytes is decrypted
+ */
+void
+dsp_bf_decrypt(dsp_t *dsp, u8 *data, int len)
+{
+	int i = 0;
+	u8 j = dsp->bf_decrypt_in_pos;
+	u8 k = dsp->bf_decrypt_out_pos;
+	u8 *bf_crypt_inring = dsp->bf_crypt_inring;
+	u8 *bf_data_out = dsp->bf_data_out;
+	u16 sync = dsp->bf_sync;
+	u32 *P = dsp->bf_p;
+	u32 *S = dsp->bf_s;
+	u32 yl, yr;
+	u8 nibble;
+	u8 cs, cs0,cs1,cs2;
+
+	while(i < len) {
+		/* shift upper bit and rotate data to buffer ring
+		 * send current decrypted data
+		 */
+		sync = (sync<<1) | ((*data)>>7);
+		bf_crypt_inring[j++ & 15] = *data;
+		*data++ = bf_data_out[k++];
+		i++;
+		if (k == 9)
+			k = 0; /* repeat if no sync has been found */
+		/* check if not in sync */
+		if ((sync&0x1f0) != 0x100)
+			continue;
+		j -= 9;
+		/* transcode receive data to 64 bit block of encrypted data */
+		yl = bf_crypt_inring[j++ & 15];
+		yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
+		yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
+		yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
+		yr = nibble = bf_crypt_inring[j++ & 15]; /* bit7 = 0 */
+		yl = (yl<<4) | (nibble>>3);
+		cs2 = bf_crypt_inring[j++ & 15];
+		yr = (yr<<7) | (cs2 & 0x7f); 
+		cs1 = bf_crypt_inring[j++ & 15];
+		yr = (yr<<7) | (cs1 & 0x7f); 
+		cs0 = bf_crypt_inring[j++ & 15];
+		yr = (yr<<7) | (cs0 & 0x7f); 
+		yr = (yr<<8) | bf_crypt_inring[j++ & 15];
+		/* calculate 3-bit checksumme */
+		cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15)
+			^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30)
+			^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10)
+			^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25)
+			^ (yr>>28) ^ (yr>>31);
+		/* check if frame is valid */
+		if ((cs&0x7) != (((cs2>>5)&4) | ((cs1>>6)&2) | (cs0 >> 7)))
+		{
+			if (dsp_debug & DEBUG_DSP_BLOWFISH)
+				printk(KERN_DEBUG "DSP BLOWFISH: received corrupt frame, checksumme is not correct\n");
+			continue;
+		} 
+		/* decrypt */
+		yr ^= P[17];
+		yl ^= P[16];
+		DROUND(yl, yr, 15);
+		DROUND(yr, yl, 14);
+		DROUND(yl, yr, 13);
+		DROUND(yr, yl, 12);
+		DROUND(yl, yr, 11);
+		DROUND(yr, yl, 10);
+		DROUND(yl, yr, 9);
+		DROUND(yr, yl, 8);
+		DROUND(yl, yr, 7);
+		DROUND(yr, yl, 6);
+		DROUND(yl, yr, 5);
+		DROUND(yr, yl, 4);
+		DROUND(yl, yr, 3);
+		DROUND(yr, yl, 2);
+		DROUND(yl, yr, 1);
+		DROUND(yr, yl, 0);
+		/* transcode 8 crypted bytes to 9 sample bytes */
+		bf_data_out[0] = dsp_audio_seven2law[(yl>>25) & 0x7f];
+		bf_data_out[1] = dsp_audio_seven2law[(yl>>18) & 0x7f];
+		bf_data_out[2] = dsp_audio_seven2law[(yl>>11) & 0x7f];
+		bf_data_out[3] = dsp_audio_seven2law[(yl>>4) & 0x7f];
+		bf_data_out[4] = dsp_audio_seven2law[((yl<<3) & 0x78) | ((yr>>29) & 0x07)];
+		bf_data_out[5] = dsp_audio_seven2law[(yr>>22) & 0x7f];
+		bf_data_out[6] = dsp_audio_seven2law[(yr>>15) & 0x7f];
+		bf_data_out[7] = dsp_audio_seven2law[(yr>>8) & 0x7f];
+		bf_data_out[8] = dsp_audio_seven2law[(yr>>1) & 0x7f];
+		k = 0; /* start with new decoded frame */
+	}
+
+	/* write current count and sync */
+	dsp->bf_decrypt_in_pos = j;
+	dsp->bf_decrypt_out_pos = k;
+	dsp->bf_sync = sync;
+}
+
+
+/* used to encrypt S and P boxes */
+static inline void
+encrypt_block(const u32 *P, const u32 *S, u32 *dst, u32 *src)
+{
+        u32 yl = src[0];
+        u32 yr = src[1];
+                                                                                                                                   
+        EROUND(yr, yl, 0);
+        EROUND(yl, yr, 1);
+        EROUND(yr, yl, 2);
+        EROUND(yl, yr, 3);
+        EROUND(yr, yl, 4);
+        EROUND(yl, yr, 5);
+        EROUND(yr, yl, 6);
+        EROUND(yl, yr, 7);
+        EROUND(yr, yl, 8);
+        EROUND(yl, yr, 9);
+        EROUND(yr, yl, 10);
+        EROUND(yl, yr, 11);
+        EROUND(yr, yl, 12);
+        EROUND(yl, yr, 13);
+        EROUND(yr, yl, 14);
+        EROUND(yl, yr, 15);
+                                                                                                                                   
+        yl ^= P[16];
+        yr ^= P[17];
+                                                                                                                                   
+        dst[0] = yr;
+        dst[1] = yl;
+}
+
+/* 
+ * initialize the dsp for encryption and decryption using the same key
+ * Calculates the blowfish S and P boxes for encryption and decryption.
+ * The margin of keylen must be 4-56 bytes.
+ * returns 0 if ok.
+ */
+int
+dsp_bf_init(dsp_t *dsp, const u8 *key, uint keylen)
+{
+	short i, j, count;
+	u32 data[2], temp;
+	u32 *P = (u32 *)dsp->bf_p;
+	u32 *S = (u32 *)dsp->bf_s;
+
+	if (keylen<4 || keylen>56)
+		return(1);
+
+	/* Set dsp states */
+	i = 0;
+	while(i < 9)
+	{
+		dsp->bf_crypt_out[i] = 0xff;
+		dsp->bf_data_out[i] = dsp_silence;
+		i++;
+	}
+	dsp->bf_crypt_pos = 0;
+	dsp->bf_decrypt_in_pos = 0;
+	dsp->bf_decrypt_out_pos = 0;
+	dsp->bf_sync = 0x1ff;
+	dsp->bf_enable = 1;
+
+	/* Copy the initialization s-boxes */
+	for (i = 0, count = 0; i < 256; i++)
+		for (j = 0; j < 4; j++, count++)
+			S[count] = bf_sbox[count];
+
+	/* Set the p-boxes */
+	for (i = 0; i < 16 + 2; i++)
+		P[i] = bf_pbox[i];
+
+	/* Actual subkey generation */
+	for (j = 0, i = 0; i < 16 + 2; i++) {
+		temp = (((u32 )key[j] << 24) |
+			((u32 )key[(j + 1) % keylen] << 16) |
+			((u32 )key[(j + 2) % keylen] << 8) |
+			((u32 )key[(j + 3) % keylen]));
+
+		P[i] = P[i] ^ temp;
+		j = (j + 4) % keylen;
+	}
+
+	data[0] = 0x00000000;
+	data[1] = 0x00000000;
+
+	for (i = 0; i < 16 + 2; i += 2) {
+		encrypt_block(P, S, data, data);
+
+		P[i] = data[0];
+		P[i + 1] = data[1];
+	}
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0, count = i * 256; j < 256; j += 2, count += 2) {
+			encrypt_block(P, S, data, data);
+
+			S[count] = data[0];
+			S[count + 1] = data[1];
+		}
+	}
+
+	return(0);
+}
+
+
+/* turn encryption off
+ */
+void
+dsp_bf_cleanup(dsp_t *dsp)
+{
+	dsp->bf_enable = 0;
+}
+
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_cancel.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_cancel.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_cancel.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,350 @@
+/*
+ *
+ * Simple but fast Echo cancellation for mISDN_dsp.
+ *
+ * Copyright Chrisian Richter
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+#include "dsp.h"
+#ifdef ARCH_I386
+#include <asm/i387.h>
+#else
+#define kernel_fpu_begin()
+#define kernel_fpu_end()
+#endif
+
+
+/*
+ * how this works:
+ *
+ * 
+ * 
+ */
+
+/*
+ * send HW message to hfc card
+ */
+static void
+dsp_cancel_hw_message(dsp_t *dsp, u32 message, u32 param)
+{
+	struct sk_buff *nskb;
+
+	nskb = create_link_skb(PH_CONTROL | REQUEST, message, sizeof(param), &param, 0);
+	if (!nskb) {
+		printk(KERN_ERR "%s: No mem for skb.\n", __FUNCTION__);
+		return;
+	}
+	/* unlocking is not required, because we don't expect a response */
+	if (mISDN_queue_down(&dsp->inst, 0, nskb))
+		dev_kfree_skb(nskb);
+}
+
+
+
+void bchdev_echocancel_chunk(dsp_t* dev, uint8_t *rxchunk, uint8_t *txchunk, uint16_t size);
+int bchdev_echocancel_activate(dsp_t* dev, int deftaps, int train);
+void bchdev_echocancel_deactivate(dsp_t* dev);
+
+
+void
+dsp_cancel_tx(dsp_t *dsp, u8 *data, int len)
+{
+	if (!dsp ) return ;
+	if (!data) return;
+	
+	if (dsp->txbuflen + len < ECHOCAN_BUFLEN) {
+		memcpy(&dsp->txbuf[dsp->txbuflen],data,len);
+		dsp->txbuflen+=len;
+	} else {
+		static int i=0;
+		if(i==4000) {
+			printk("ECHOCAN: i:%d TXBUF Overflow txbuflen:%d txcancellen:%d\n", i, dsp->txbuflen,len);
+			i=0;
+		}
+		i+=len;
+
+		dsp->txbuflen=0;
+	}
+	
+}
+
+void
+dsp_cancel_rx(dsp_t *dsp, u8 *data, int len)
+{
+	if (!dsp ) return ;
+	if (!data) return;
+	
+	if (len <= dsp->txbuflen) {
+		char tmp[ECHOCAN_BUFLEN];
+		
+		int delta=dsp->txbuflen-len;
+		
+		memcpy(tmp,&dsp->txbuf[len],delta);
+	
+		kernel_fpu_begin();
+		bchdev_echocancel_chunk(dsp, data, dsp->txbuf, len);
+		kernel_fpu_end();
+		
+		memcpy(dsp->txbuf,tmp,delta);
+		dsp->txbuflen=delta;
+	} else {
+		static int i=0;
+		if(i==4000) {
+			printk("ECHOCAN: i:%d TXBUF Underrun txbuflen:%d rxcancellen:%d\n",i,dsp->txbuflen,len);
+			i=0;
+		}
+		i+=len;
+	}
+	
+}
+
+int
+dsp_cancel_init(dsp_t *dsp, int deftaps, int training, int delay)
+{
+	
+	if (!dsp) return -1;
+
+	if (dsp->feature_state != FEAT_STATE_RECEIVED) {
+		dsp->queue_cancel[0]=deftaps;
+		dsp->queue_cancel[1]=training;
+		dsp->queue_cancel[2]=delay;
+		return 0;
+	}
+	
+	//printk("DSP_CANCEL_INIT called\n");
+	
+	if (delay < 0)
+	{
+		//printk(KERN_NOTICE "Disabling EC\n");
+		dsp->cancel_enable = 0;
+		
+		dsp->txbuflen=0;
+
+		if (dsp->features.hfc_echocanhw) {
+			//printk(KERN_NOTICE "Disabling Hardware EC\n");
+			dsp_cancel_hw_message(dsp, HW_ECHOCAN_OFF, deftaps);
+		} else {
+			bchdev_echocancel_deactivate(dsp);
+		}
+		
+		return(0);
+	}
+	
+	
+	if (dsp->features.hfc_echocanhw) {
+		//printk(KERN_NOTICE "Using Hardware EC taps [%d]\n",deftaps);
+		dsp_cancel_hw_message(dsp, HW_ECHOCAN_ON, deftaps);
+		return 0;
+	}
+	
+	dsp->txbuflen=0;
+	dsp->rxbuflen=0;
+	
+	
+	bchdev_echocancel_activate(dsp,deftaps, training);
+	
+	//printk("Enabling EC\n");
+	dsp->cancel_enable = 1;
+	return(0);
+}
+
+
+
+
+
+/*****************************************************/
+#define __ECHO_STATE_MUTE                       (1 << 8)
+#define ECHO_STATE_IDLE                         (0)
+#define ECHO_STATE_PRETRAINING          (1 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_STARTTRAINING        (2 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_AWAITINGECHO         (3 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_TRAINING                     (4 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_ACTIVE                       (5)
+
+#define AMI_MASK 0x55
+
+
+
+/** @return string of given echo cancellation state */
+char* bchdev_echocancel_statestr(uint16_t state)
+{
+  switch(state) {
+  case ECHO_STATE_IDLE:
+    return "idle";
+    break;
+  case ECHO_STATE_PRETRAINING:
+    return "pre-training";
+    break;
+  case ECHO_STATE_STARTTRAINING:
+    return "transmit impulse";
+    break;
+  case ECHO_STATE_AWAITINGECHO:
+    return "awaiting echo";
+    break;
+  case ECHO_STATE_TRAINING:
+    return "training start";
+    break;
+  case ECHO_STATE_ACTIVE:
+    return "training finished";
+    break;
+  default:
+    return "unknown";
+  }
+}
+
+/** Changes state of echo cancellation to given state */
+void bchdev_echocancel_setstate(dsp_t* dev, uint16_t state)
+{
+#if 0
+  char* statestr = bchdev_echocancel_statestr(state);
+
+  printk("bchdev: echo cancel state %d (%s)\n", state & 0xff, statestr);
+  if (state == ECHO_STATE_ACTIVE)
+	  printk("bchdev: %d taps trained\n", dev->echolastupdate);
+#endif
+  dev->echostate = state;
+}
+
+static int buf_size=0;
+static int ec_timer=2000;
+//static int ec_timer=1000;
+
+
+/** Activates echo cancellation for the given bch_dev, device must have been locked before! */
+int bchdev_echocancel_activate(dsp_t* dev, int deftaps, int training)
+{
+  int taps;
+  
+  if (! dev) return -EINVAL;
+  
+  if (dev->ec && dev->ecdis_rd && dev->ecdis_wr) {
+	  // already active
+    return 0;
+  }
+  
+  if (deftaps>0) {
+	  taps=deftaps;
+  } else {
+	  taps=128;
+  }
+  
+  
+  switch (buf_size) {
+  case  0: taps +=    0; break;
+  case  1: taps +=  256-128; break;
+  case  2: taps +=  512-128; break;
+  default: taps += 1024-128;
+  }
+  
+  if (!dev->ec) dev->ec = echo_can_create(taps, 0);
+  if (!dev->ec) {
+	  return -ENOMEM;
+  }
+  
+  dev->echolastupdate = 0;
+
+  if (!training) {
+	  dev->echotimer=0;
+	  bchdev_echocancel_setstate(dev, ECHO_STATE_IDLE);
+  } else {
+	  if (training<10) 
+		  training= ec_timer;
+	  
+	  dev->echotimer      = training;
+	  bchdev_echocancel_setstate(dev, ECHO_STATE_PRETRAINING);
+
+  }
+  
+  if (!dev->ecdis_rd) dev->ecdis_rd = kmalloc(sizeof(echo_can_disable_detector_state_t), GFP_ATOMIC);
+  if (!dev->ecdis_rd) {
+	  kfree(dev->ec); dev->ec = NULL;
+	  return -ENOMEM;
+  }
+  echo_can_disable_detector_init(dev->ecdis_rd);
+  
+  if (!dev->ecdis_wr) dev->ecdis_wr = kmalloc(sizeof(echo_can_disable_detector_state_t), GFP_ATOMIC);
+  if (!dev->ecdis_wr) {
+	  kfree(dev->ec); dev->ec = NULL;
+	  kfree(dev->ecdis_rd); dev->ecdis_rd = NULL;
+    return -ENOMEM;
+  }
+  echo_can_disable_detector_init(dev->ecdis_wr);
+
+  return 0;
+}
+
+/** Deactivates echo cancellation for the given bch_dev, device must have been locked before! */
+void bchdev_echocancel_deactivate(dsp_t* dev)
+{
+  if (! dev) return;
+
+  //chan_misdn_log("bchdev: deactivating echo cancellation on port=%04x, chan=%02x\n", dev->stack->port, dev->channel);
+  
+  if (dev->ec) echo_can_free(dev->ec);
+  dev->ec = NULL;
+  
+  dev->echolastupdate = 0;
+  dev->echotimer      = 0;
+  bchdev_echocancel_setstate(dev, ECHO_STATE_IDLE);
+
+  if (dev->ecdis_rd) kfree(dev->ecdis_rd);
+  dev->ecdis_rd = NULL;
+  
+  if (dev->ecdis_wr) kfree(dev->ecdis_wr);
+  dev->ecdis_wr = NULL;
+}
+
+/** Processes one TX- and one RX-packet with echocancellation */
+void bchdev_echocancel_chunk(dsp_t* ss, uint8_t *rxchunk, uint8_t *txchunk, uint16_t size)
+{
+  int16_t rxlin, txlin;
+  uint16_t x;
+  
+  /* Perform echo cancellation on a chunk if requested */
+  if (ss->ec) {
+	  
+	  if (ss->echostate & __ECHO_STATE_MUTE) {
+		  /* Special stuff for training the echo can */
+		  for (x=0;x<size;x++) {
+			  rxlin = dsp_audio_law_to_s32[rxchunk[x]];
+			  txlin = dsp_audio_law_to_s32[txchunk[x]];
+			  if (ss->echostate == ECHO_STATE_PRETRAINING) {
+				  if (--ss->echotimer <= 0) {
+					  ss->echotimer = 0;
+					  ss->echostate = ECHO_STATE_STARTTRAINING;
+				  }
+			  }
+			  if ((ss->echostate == ECHO_STATE_AWAITINGECHO) && (txlin > 8000)) {
+				  ss->echolastupdate = 0;
+				  ss->echostate = ECHO_STATE_TRAINING;
+			  }
+			  if (ss->echostate == ECHO_STATE_TRAINING) {
+				  if (echo_can_traintap(ss->ec, ss->echolastupdate++, rxlin)) {
+#if 0
+					  printk("Finished training (%d taps trained)!\n", ss->echolastupdate);
+#endif
+					  ss->echostate = ECHO_STATE_ACTIVE;
+				  }
+			  }
+			  rxlin = 0;
+			  rxchunk[x] = dsp_audio_s16_to_law[(int)rxlin];
+		  }
+	  } else {
+		  for (x=0;x<size;x++) {
+			  rxlin = dsp_audio_law_to_s32[rxchunk[x]&0xff];
+			  txlin = dsp_audio_law_to_s32[txchunk[x]&0xff];
+			  rxlin = echo_can_update(ss->ec, txlin, rxlin);
+			  rxchunk[x] = dsp_audio_s16_to_law[rxlin &0xffff];
+		  }
+	  }
+  }
+}
+
+/******************************************************/

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_cmx.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_cmx.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_cmx.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1427 @@
+/* $Id: dsp_cmx.c,v 1.15 2007/03/27 15:06:29 jolly Exp $
+ *
+ * Audio crossconnecting/conferrencing (hardware level).
+ *
+ * Copyright 2002 by Andreas Eversberg (jolly at eversberg.eu)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+/*
+ * The process of adding and removing parties to/from a conference:
+ *
+ * There is a chain of conference_t which has one or more members in a chain
+ * of conf_member_t.
+ *
+ * After a party is added, the conference is checked for hardware capability.
+ * Also if a party is removed, the conference is checked again.
+ *
+ * There are 3 different solutions: -1 = software, 0 = hardware-crossconnect
+ * 1-n = hardware-conference. The n will give the conference number.
+ *
+ * Depending on the change after removal or insertion of a party, hardware
+ * commands are given.
+ *
+ * The current solution is stored within the conference_t entry.
+ */
+
+/* HOW THE CMX WORKS:
+ *
+ * There are 3 types of interaction: One member is alone, in this case only
+ * data flow from upper to lower layer is done.
+ * Two members will also exchange their data so they are crossconnected.
+ * Three or more members will be added in a conference and will hear each
+ * other but will not receive their own speech (echo) if not enabled.
+ *
+ * Features of CMX are:
+ *  - Crossconnecting or even conference, if more than two members are together.
+ *  - Force mixing of transmit data with other crossconnect/conference members.
+ *  - Echo generation to benchmark the delay of audio processing.
+ *  - Use hardware to minimize cpu load, disable FIFO load and minimize delay.
+ *  - Dejittering and clock generation.
+ *
+ * There are 2 buffers:
+ *
+ *
+ * RX-Buffer
+ *                 R             W
+ *                 |             |
+ * ----------------+-------------+-------------------
+ * 
+ * The rx-buffer is a ring buffer used to store the received data for each
+ * individual member. This is only the case if data needs to be dejittered
+ * or in case of a conference where different clocks require reclocking.
+ * The transmit-clock (R) will read the buffer.
+ * If the clock overruns the write-pointer, we will have a buffer underrun.
+ * If the write pointer always has a certain distance from the transmit-
+ * clock, we will have a delay. The delay will dynamically be increased and
+ * reduced.
+ *
+ *
+ * TX-Buffer
+ *                  R        W
+ *                  |        |
+ * -----------------+--------+-----------------------
+ *
+ * The tx-buffer is a ring buffer to queue the transmit data from user space
+ * until it will be mixed or sent. There are two pointers, R and W. If the write
+ * pointer W would reach or overrun R, the buffer would overrun. In this case
+ * (some) data is dropped so that it will not overrun.
+ *
+ *
+ * Clock:
+ * 
+ * A Clock is not required, if the data source has exactly one clock. In this
+ * case the data source is forwarded to the destination.
+ *
+ * A Clock is required, because the data source
+ *  - has multiple clocks.
+ *  - has no clock due to jitter (VoIP).
+ * In this case the system's clock is used. The clock resolution depends on
+ * the jiffie resolution.
+ *
+ * If a member joins a conference:
+ *
+ * - If a member joins, its rx_buff is set to silence and change read pointer
+ *   to transmit clock.
+ *
+ * The procedure of received data from card is explained in cmx_receive.
+ * The procedure of received data from user space is explained in cmx_transmit.
+ * The procedure of transmit data to card is cmx_send.
+ *
+ *
+ * Interaction with other features:
+ *
+ * DTMF:
+ * DTMF decoding is done before the data is crossconnected.
+ *
+ * Volume change:
+ * Changing rx-volume is done before the data is crossconnected. The tx-volume
+ * must be changed whenever data is transmitted to the card by the cmx.
+ *
+ * Tones:
+ * If a tone is enabled, it will be processed whenever data is transmitted to
+ * the card. It will replace the tx-data from the user space.
+ * If tones are generated by hardware, this conference member is removed for
+ * this time.
+ *
+ * Disable rx-data:
+ * If cmx is realized in hardware, rx data will be disabled if requested by
+ * the upper layer. If dtmf decoding is done by software and enabled, rx data
+ * will not be diabled but blocked to the upper layer.
+ *
+ * HFC conference engine:
+ * If it is possible to realize all features using hardware, hardware will be
+ * used if not forbidden by control command. Disabling rx-data provides
+ * absolutely traffic free audio processing. (except for the quick 1-frame
+ * upload of a tone loop, only once for a new tone)
+ *
+ */
+
+// delay.h is required for hw_lock.h
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+#include "dsp.h"
+
+//#define CMX_CONF_DEBUG /* debugging of multi party conference, by using conference even with two members */
+//#define CMX_DEBUG /* massive read/write pointer output */
+
+LIST_HEAD(Conf_list);
+
+/*
+ * debug cmx memory structure
+ */
+void
+dsp_cmx_debug(dsp_t *dsp)
+{
+	conference_t	*conf;
+	conf_member_t	*member;
+	dsp_t		*odsp;
+
+	printk(KERN_DEBUG "-----Current DSP\n");
+	list_for_each_entry(odsp, &dsp_obj.ilist, list) {
+		printk(KERN_DEBUG "* %s echo=%d txmix=%d", odsp->inst.name, odsp->echo, odsp->tx_mix);
+		if (odsp->conf)
+			printk(" (Conf %d)", odsp->conf->id);
+		if (dsp == odsp)
+			printk(" *this*");
+		printk("\n");
+	}
+	printk(KERN_DEBUG "-----Current Conf:\n");
+	list_for_each_entry(conf, &Conf_list, list) {
+		printk(KERN_DEBUG "* Conf %d (%p)\n", conf->id, conf);
+		list_for_each_entry(member, &conf->mlist, list) {
+			printk(KERN_DEBUG
+				"  - member = %s (slot_tx %d, bank_tx %d, slot_rx %d, bank_rx %d hfc_conf %d)%s\n",
+				member->dsp->inst.name, member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx,
+				member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx, member->dsp->hfc_conf,
+				(member->dsp==dsp)?" *this*":"");
+		}
+	}
+	printk(KERN_DEBUG "-----end\n");
+}
+
+/*
+ * search conference
+ */
+static conference_t 
+*dsp_cmx_search_conf(u32 id)
+{
+	conference_t *conf;
+
+	if (!id) {
+		printk(KERN_WARNING "%s: conference ID is 0.\n", 
+			__FUNCTION__);
+		return(NULL);
+	}
+
+	/* search conference */
+	list_for_each_entry(conf, &Conf_list, list)
+		if (conf->id == id)
+			return(conf);
+
+	return(NULL);
+}
+
+
+/*
+ * add member to conference
+ */
+static int
+dsp_cmx_add_conf_member(dsp_t *dsp, conference_t *conf)
+{
+	conf_member_t *member;
+
+	if (!conf || !dsp) {
+		printk(KERN_WARNING "%s: conf or dsp is 0.\n", __FUNCTION__);
+		return(-EINVAL);
+	}
+	if (dsp->member) {
+		printk(KERN_WARNING "%s: dsp is already member in a conf.\n", 
+			__FUNCTION__);
+		return(-EINVAL);
+	}
+
+	if (dsp->conf) {
+		printk(KERN_WARNING "%s: dsp is already in a conf.\n", 
+			__FUNCTION__);
+		return(-EINVAL);
+	}
+
+	if (!(member = kmalloc(sizeof(conf_member_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc conf_member_t failed\n");
+		return(-ENOMEM);
+	}
+	memset(member, 0, sizeof(conf_member_t));
+	member->dsp = dsp;
+	/* clear rx buffer */
+	memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));
+	dsp->rx_W = dsp->rx_R = -1; /* reset pointers */
+
+	list_add_tail(&member->list, &conf->mlist);
+
+	dsp->conf = conf;
+	dsp->member = member;
+
+	return(0);
+}
+
+
+/*
+ * del member from conference
+ */
+int
+dsp_cmx_del_conf_member(dsp_t *dsp)
+{
+	conf_member_t *member;
+
+	if (!dsp) {
+		printk(KERN_WARNING "%s: dsp is 0.\n", 
+			__FUNCTION__);
+		return(-EINVAL);
+	}
+
+	if (!dsp->conf) {
+		printk(KERN_WARNING "%s: dsp is not in a conf.\n", 
+			__FUNCTION__);
+		return(-EINVAL);
+	}
+
+	if (list_empty(&dsp->conf->mlist)) {
+		printk(KERN_WARNING "%s: dsp has linked an empty conf.\n", 
+			__FUNCTION__);
+		return(-EINVAL);
+	}
+
+	/* find us in conf */
+	list_for_each_entry(member, &dsp->conf->mlist, list) {
+		if (member->dsp == dsp) {
+			list_del(&member->list);
+			dsp->conf = NULL;
+			dsp->member = NULL;
+			kfree(member);
+			return(0);
+		}
+	}
+	printk(KERN_WARNING "%s: dsp is not present in its own conf_meber list.\n", 
+		__FUNCTION__);
+
+	return(-EINVAL);
+}
+
+
+/*
+ * new conference
+ */
+static conference_t
+*dsp_cmx_new_conf(u32 id)
+{
+	conference_t *conf;
+
+	if (!id) {
+		printk(KERN_WARNING "%s: id is 0.\n", 
+			__FUNCTION__);
+		return(NULL);
+	}
+
+	if (!(conf = kmalloc(sizeof(conference_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc conference_t failed\n");
+		return(NULL);
+	}
+	memset(conf, 0, sizeof(conference_t));
+	INIT_LIST_HEAD(&conf->mlist);
+	conf->id = id;
+
+	list_add_tail(&conf->list, &Conf_list);
+
+	return(conf);
+}
+
+
+/*
+ * del conference
+ */
+int
+dsp_cmx_del_conf(conference_t *conf)
+{
+	if (!conf) {
+		printk(KERN_WARNING "%s: conf is null.\n", 
+			__FUNCTION__);
+		return(-EINVAL);
+	}
+
+	if (!list_empty(&conf->mlist)) {
+		printk(KERN_WARNING "%s: conf not empty.\n", 
+			__FUNCTION__);
+		return(-EINVAL);
+	}
+	list_del(&conf->list);
+	kfree(conf);
+
+	return(0);
+}
+
+
+/*
+ * send HW message to hfc card
+ */
+static void
+dsp_cmx_hw_message(dsp_t *dsp, u32 message, u32 param1, u32 param2, u32 param3, u32 param4)
+{
+	struct sk_buff *nskb;
+	u32 param[4];
+
+	param[0] = param1;
+	param[1] = param2;
+	param[2] = param3;
+	param[3] = param4;
+	nskb = create_link_skb(PH_CONTROL | REQUEST, message, sizeof(param), param, 0);
+	if (!nskb) {
+		printk(KERN_ERR "%s: No mem for skb.\n", __FUNCTION__);
+		return;
+	}
+	/* unlocking is not required, because we don't expect a response */
+	if (mISDN_queue_down(&dsp->inst, 0, nskb))
+		dev_kfree_skb(nskb);
+}
+
+
+/*
+ * do hardware update and set the software/hardware flag
+ *
+ * either a conference or a dsp instance can be given
+ * if only dsp instance is given, the instance is not associated with a conf
+ * and therefore removed. if a conference is given, the dsp is expected to
+ * be member of that conference.
+ */
+void 
+dsp_cmx_hardware(conference_t *conf, dsp_t *dsp)
+{
+	conf_member_t	*member, *nextm;
+	dsp_t		*finddsp;
+	int		memb = 0, i, ii, i1, i2;
+	int		freeunits[8];
+	u_char		freeslots[256];
+	int		same_hfc = -1, same_pcm = -1, current_conf = -1, all_conf = 1;
+
+	/* dsp gets updated (no conf) */
+//printk("-----1\n");
+	if (!conf) {
+//printk("-----2\n");
+		if (!dsp)
+			return;
+//printk("-----3\n");
+		if (dsp_debug & DEBUG_DSP_CMX)
+			printk(KERN_DEBUG "%s checking dsp %s\n", __FUNCTION__, dsp->inst.name);
+//printk("-----a\n");
+		one_member:
+		/* remove HFC conference if enabled */
+		if (dsp->hfc_conf >= 0) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s removing %s from HFC conf %d because dsp is split\n", __FUNCTION__, dsp->inst.name, dsp->hfc_conf);
+			dsp_cmx_hw_message(dsp, HW_CONF_SPLIT, 0, 0, 0, 0);
+			dsp->hfc_conf = -1;
+		}
+		if (!dsp->echo) {
+			/* NO ECHO: remove PCM slot if assigned */
+			if (dsp->pcm_slot_tx>=0 || dsp->pcm_slot_rx>=0) {
+				if (dsp_debug & DEBUG_DSP_CMX)
+					printk(KERN_DEBUG "%s removing %s from PCM slot %d (TX) %d (RX) because dsp is split (no echo)\n", __FUNCTION__, dsp->inst.name, dsp->pcm_slot_tx, dsp->pcm_slot_rx);
+				dsp_cmx_hw_message(dsp, HW_PCM_DISC, 0, 0, 0, 0);
+				dsp->pcm_slot_tx = -1;
+				dsp->pcm_bank_tx = -1;
+				dsp->pcm_slot_rx = -1;
+				dsp->pcm_bank_rx = -1;
+			}
+			return;
+		}
+		/* ECHO: already echo */
+		if (dsp->pcm_slot_tx>=0 && dsp->pcm_slot_rx<0
+		 && dsp->pcm_bank_tx==2 && dsp->pcm_bank_rx==2)
+			return;
+		/* ECHO: if slot already assigned */
+		if (dsp->pcm_slot_tx>=0) {
+			dsp->pcm_slot_rx = dsp->pcm_slot_tx;
+			dsp->pcm_bank_tx = 2; /* loop */
+			dsp->pcm_bank_rx = 2;
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s refresh %s for echo using slot %d\n", __FUNCTION__, dsp->inst.name, dsp->pcm_slot_tx);
+			dsp_cmx_hw_message(dsp, HW_PCM_CONN, dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);
+			return;
+		}
+		/* ECHO: find slot */
+		dsp->pcm_slot_tx = -1;
+		dsp->pcm_slot_rx = -1;
+		memset(freeslots, 1, sizeof(freeslots));
+		list_for_each_entry(finddsp, &dsp_obj.ilist, list) {
+			 if (finddsp->features.pcm_id==dsp->features.pcm_id) {
+				if (finddsp->pcm_slot_rx>=0
+				 && finddsp->pcm_slot_rx<sizeof(freeslots))
+					freeslots[finddsp->pcm_slot_tx] = 0;
+				if (finddsp->pcm_slot_tx>=0
+				 && finddsp->pcm_slot_tx<sizeof(freeslots))
+					freeslots[finddsp->pcm_slot_rx] = 0;
+			}
+		}
+		i = 0;
+		ii = dsp->features.pcm_slots;
+		while(i < ii) {
+			if (freeslots[i])
+				break;
+			i++;
+		}
+		if (i == ii) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s no slot available for echo\n", __FUNCTION__);
+			/* no more slots available */
+			return;
+		}
+		/* assign free slot */
+		dsp->pcm_slot_tx = i;
+		dsp->pcm_slot_rx = i;
+		dsp->pcm_bank_tx = 2; /* loop */
+		dsp->pcm_bank_rx = 2;
+		if (dsp_debug & DEBUG_DSP_CMX)
+			printk(KERN_DEBUG "%s assign echo for %s using slot %d\n", __FUNCTION__, dsp->inst.name, dsp->pcm_slot_tx);
+		dsp_cmx_hw_message(dsp, HW_PCM_CONN, dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2);
+		return;
+	}
+
+//printk("-----4\n");
+	/* conf gets updated (all members) */
+	if (dsp_debug & DEBUG_DSP_CMX)
+		printk(KERN_DEBUG "%s checking conference %d\n", __FUNCTION__, conf->id);
+//printk("-----5\n");
+	
+	if (list_empty(&conf->mlist)) {
+		printk(KERN_ERR "%s: conference whithout members\n", __FUNCTION__);
+		return;
+	}
+	member = list_entry(conf->mlist.next, conf_member_t, list);
+	same_hfc = member->dsp->features.hfc_id;
+	same_pcm = member->dsp->features.pcm_id;
+	/* check all members in our conference */
+	list_for_each_entry(member, &conf->mlist, list) {
+		/* check if member uses mixing */
+		if (member->dsp->tx_mix) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s dsp %s cannot form a conf, because tx_mix is turned on\n", __FUNCTION__, member->dsp->inst.name);
+			conf_software:
+//			printk(KERN_NOTICE "****** SOFTWARE CONFERENCE\n");
+			list_for_each_entry(member, &conf->mlist, list) {
+				dsp = member->dsp;
+				/* remove HFC conference if enabled */
+				if (dsp->hfc_conf >= 0) {
+					if (dsp_debug & DEBUG_DSP_CMX)
+						printk(KERN_DEBUG "%s removing %s from HFC conf %d because not possible with hardware\n", __FUNCTION__, dsp->inst.name, dsp->hfc_conf);
+					dsp_cmx_hw_message(dsp, HW_CONF_SPLIT, 0, 0, 0, 0);
+					dsp->hfc_conf = -1;
+				}
+				/* remove PCM slot if assigned */
+				if (dsp->pcm_slot_tx>=0 || dsp->pcm_slot_rx>=0) {
+					if (dsp_debug & DEBUG_DSP_CMX)
+						printk(KERN_DEBUG "%s removing %s from PCM slot %d (TX) slot %d (RX) because not possible with hardware\n", __FUNCTION__, dsp->inst.name, dsp->pcm_slot_tx, dsp->pcm_slot_rx);
+					dsp_cmx_hw_message(dsp, HW_PCM_DISC, 0, 0, 0, 0);
+					dsp->pcm_slot_tx = -1;
+					dsp->pcm_bank_tx = -1;
+					dsp->pcm_slot_rx = -1;
+					dsp->pcm_bank_rx = -1;
+				}
+			}
+			conf->hardware = 0;
+			conf->software = 1;
+			return;
+		}
+		/* check if member has echo turned on */
+		if (member->dsp->echo) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s dsp %s cannot form a conf, because echo is turned on\n", __FUNCTION__, member->dsp->inst.name);
+			goto conf_software;
+		}
+		/* check if member has tx_mix turned on */
+		if (member->dsp->tx_mix) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s dsp %s cannot form a conf, because tx_mix is turned on\n", __FUNCTION__, member->dsp->inst.name);
+			goto conf_software;
+		}
+		/* check if member changes volume at an not suppoted level */
+		if (member->dsp->tx_volume) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s dsp %s cannot form a conf, because tx_volume is changed\n", __FUNCTION__, member->dsp->inst.name);
+			goto conf_software;
+		}
+		if (member->dsp->rx_volume) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s dsp %s cannot form a conf, because rx_volume is changed\n", __FUNCTION__, member->dsp->inst.name);
+			goto conf_software;
+		}
+		/* check if encryption is enabled */
+		if (member->dsp->bf_enable) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s dsp %s cannot form a conf, because encryption is enabled\n", __FUNCTION__, member->dsp->inst.name);
+			goto conf_software;
+		}
+		/* check if echo cancellation is enabled */
+		if (member->dsp->cancel_enable) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s dsp %s cannot form a conf, because echo cancellation is enabled\n", __FUNCTION__, member->dsp->inst.name);
+			goto conf_software;
+		}
+		/* check if member is on a card with PCM support */
+		if (member->dsp->features.pcm_id < 0) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s dsp %s cannot form a conf, because dsp has no PCM bus\n", __FUNCTION__, member->dsp->inst.name);
+			goto conf_software;
+		}
+		/* check if relations are on the same PCM bus */
+		if (member->dsp->features.pcm_id != same_pcm) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s dsp %s cannot form a conf, because dsp is on a different PCM bus than the first dsp\n",
+					__FUNCTION__, member->dsp->inst.name);
+			goto conf_software;
+		}
+		/* determine if members are on the same hfc chip */
+		if (same_hfc != member->dsp->features.hfc_id)
+			same_hfc = -1;
+		/* if there are members already in a conference */
+		if (current_conf<0 && member->dsp->hfc_conf>=0)
+			current_conf = member->dsp->hfc_conf;
+		/* if any member is not in a conference */
+		if (member->dsp->hfc_conf < 0)
+			all_conf = 0;
+
+		memb++;
+	}
+
+	/* if no member, this is an error */
+	if (memb < 1)
+		return;
+
+	/* one member */
+	if (memb == 1) {
+		if (dsp_debug & DEBUG_DSP_CMX)
+			printk(KERN_DEBUG "%s conf %d cannot form a HW conference, because dsp is alone\n", __FUNCTION__, conf->id);
+		conf->hardware = 0;
+		conf->software = 1;
+		member = list_entry(conf->mlist.next, conf_member_t, list);
+		dsp = member->dsp;
+		goto one_member;
+	}
+
+	/* ok, now we are sure that all members are on the same pcm.
+	 * now we will see if we have only two members, so we can do
+	 * crossconnections, which don't have any limitations.
+	 */
+
+	/* if we have only two members */
+	if (memb == 2) {
+		member = list_entry(conf->mlist.next, conf_member_t, list);
+		nextm = list_entry(member->list.next, conf_member_t, list);
+		/* remove HFC conference if enabled */
+		if (member->dsp->hfc_conf >= 0) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s removing %s from HFC conf %d because two parties require only a PCM slot\n", __FUNCTION__, member->dsp->inst.name, member->dsp->hfc_conf);
+			dsp_cmx_hw_message(member->dsp, HW_CONF_SPLIT, 0, 0, 0, 0);
+			member->dsp->hfc_conf = -1;
+		}
+		if (nextm->dsp->hfc_conf >= 0) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s removing %s from HFC conf %d because two parties require only a PCM slot\n", __FUNCTION__, nextm->dsp->inst.name, nextm->dsp->hfc_conf);
+			dsp_cmx_hw_message(nextm->dsp, HW_CONF_SPLIT, 0, 0, 0, 0);
+			nextm->dsp->hfc_conf = -1;
+		}
+		/* if members have two banks (and not on the same chip) */
+		if (member->dsp->features.pcm_banks>1
+		 && nextm->dsp->features.pcm_banks>1
+		 && member->dsp->features.hfc_id!=nextm->dsp->features.hfc_id) {
+			/* if both members have same slots with crossed banks */
+			if (member->dsp->pcm_slot_tx>=0
+			 && member->dsp->pcm_slot_rx>=0
+			 && nextm->dsp->pcm_slot_tx>=0
+			 && nextm->dsp->pcm_slot_rx>=0
+			 && nextm->dsp->pcm_slot_tx==member->dsp->pcm_slot_rx
+			 && nextm->dsp->pcm_slot_rx==member->dsp->pcm_slot_tx
+			 && nextm->dsp->pcm_slot_tx==member->dsp->pcm_slot_tx
+			 && member->dsp->pcm_bank_tx!=member->dsp->pcm_bank_rx
+			 && nextm->dsp->pcm_bank_tx!=nextm->dsp->pcm_bank_rx) {
+				/* all members have same slot */
+				if (dsp_debug & DEBUG_DSP_CMX)
+					printk(KERN_DEBUG "%s dsp %s & %s stay joined on PCM slot %d bank %d (TX) bank %d (RX) (on different chips)\n", __FUNCTION__,
+						member->dsp->inst.name, nextm->dsp->inst.name,
+						member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, member->dsp->pcm_bank_rx);
+				conf->hardware = 0;
+				conf->software = 1;
+				return;
+			}
+			/* find a new slot */
+			memset(freeslots, 1, sizeof(freeslots));
+			list_for_each_entry(dsp, &dsp_obj.ilist, list) {
+				if (dsp!=member->dsp
+				 && dsp!=nextm->dsp
+				 && member->dsp->features.pcm_id==dsp->features.pcm_id) {
+					if (dsp->pcm_slot_rx>=0
+					 && dsp->pcm_slot_rx<sizeof(freeslots))
+						freeslots[dsp->pcm_slot_tx] = 0;
+					if (dsp->pcm_slot_tx>=0
+					 && dsp->pcm_slot_tx<sizeof(freeslots))
+						freeslots[dsp->pcm_slot_rx] = 0;
+				}
+			}
+			i = 0;
+			ii = member->dsp->features.pcm_slots;
+			while(i < ii) {
+				if (freeslots[i])
+					break;
+				i++;
+			}
+			if (i == ii) {
+				if (dsp_debug & DEBUG_DSP_CMX)
+					printk(KERN_DEBUG "%s no slot available for %s & %s\n", __FUNCTION__,
+						member->dsp->inst.name, nextm->dsp->inst.name);
+				/* no more slots available */
+				goto conf_software;
+			}
+			/* assign free slot */
+			member->dsp->pcm_slot_tx = i;
+			member->dsp->pcm_slot_rx = i;
+			nextm->dsp->pcm_slot_tx = i;
+			nextm->dsp->pcm_slot_rx = i;
+			member->dsp->pcm_bank_rx = 0;
+			member->dsp->pcm_bank_tx = 1;
+			nextm->dsp->pcm_bank_rx = 1;
+			nextm->dsp->pcm_bank_tx = 0;
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s adding %s & %s to new PCM slot %d (TX and RX on different chips) because both members have not same slots\n", __FUNCTION__,
+					member->dsp->inst.name, nextm->dsp->inst.name, member->dsp->pcm_slot_tx);
+			dsp_cmx_hw_message(member->dsp, HW_PCM_CONN, member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx,
+				member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx);
+			dsp_cmx_hw_message(nextm->dsp, HW_PCM_CONN, nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx,
+				nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);
+			conf->hardware = 1;
+			conf->software = 0;
+			return;
+		/* if members have one bank (or on the same chip) */
+		} else {
+			/* if both members have different crossed slots */
+			if (member->dsp->pcm_slot_tx>=0
+			 && member->dsp->pcm_slot_rx>=0
+			 && nextm->dsp->pcm_slot_tx>=0
+			 && nextm->dsp->pcm_slot_rx>=0
+			 && nextm->dsp->pcm_slot_tx==member->dsp->pcm_slot_rx
+			 && nextm->dsp->pcm_slot_rx==member->dsp->pcm_slot_tx
+			 && member->dsp->pcm_slot_tx!=member->dsp->pcm_slot_rx
+			 && member->dsp->pcm_bank_tx==0
+			 && member->dsp->pcm_bank_rx==0
+			 && nextm->dsp->pcm_bank_tx==0
+			 && nextm->dsp->pcm_bank_rx==0) {
+				/* all members have same slot */
+				if (dsp_debug & DEBUG_DSP_CMX)
+					printk(KERN_DEBUG "%s dsp %s & %s stay joined on PCM slot %d (TX) %d (RX) on same chip or one bank PCM)\n", __FUNCTION__,
+						member->dsp->inst.name, nextm->dsp->inst.name, member->dsp->pcm_slot_tx, member->dsp->pcm_slot_rx);
+				conf->hardware = 0;
+				conf->software = 1;
+				return;
+			}
+			/* find two new slot */
+			memset(freeslots, 1, sizeof(freeslots));
+			list_for_each_entry(dsp, &dsp_obj.ilist, list) {
+				if (dsp!=member->dsp
+				 && dsp!=nextm->dsp
+				 && member->dsp->features.pcm_id==dsp->features.pcm_id) {
+					if (dsp->pcm_slot_rx>=0
+					 && dsp->pcm_slot_rx<sizeof(freeslots))
+						freeslots[dsp->pcm_slot_tx] = 0;
+					if (dsp->pcm_slot_tx>=0
+					 && dsp->pcm_slot_tx<sizeof(freeslots))
+						freeslots[dsp->pcm_slot_rx] = 0;
+				}
+			}
+			i1 = 0;
+			ii = member->dsp->features.pcm_slots;
+			while(i1 < ii) {
+				if (freeslots[i1])
+					break;
+				i1++;
+			}
+			if (i1 == ii) {
+				if (dsp_debug & DEBUG_DSP_CMX)
+					printk(KERN_DEBUG "%s no slot available for %s & %s\n", __FUNCTION__,
+						member->dsp->inst.name, nextm->dsp->inst.name);
+				/* no more slots available */
+				goto conf_software;
+			}
+			i2 = i1+1;
+			while(i2 < ii) {
+				if (freeslots[i2])
+					break;
+				i2++;
+			}
+			if (i2 == ii) {
+				if (dsp_debug & DEBUG_DSP_CMX)
+					printk(KERN_DEBUG "%s no slot available for %s & %s\n", __FUNCTION__,
+						member->dsp->inst.name, nextm->dsp->inst.name);
+				/* no more slots available */
+				goto conf_software;
+			}
+			/* assign free slots */
+			member->dsp->pcm_slot_tx = i1;
+			member->dsp->pcm_slot_rx = i2;
+			nextm->dsp->pcm_slot_tx = i2;
+			nextm->dsp->pcm_slot_rx = i1;
+			member->dsp->pcm_bank_rx = 0;
+			member->dsp->pcm_bank_tx = 0;
+			nextm->dsp->pcm_bank_rx = 0;
+			nextm->dsp->pcm_bank_tx = 0;
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s adding %s & %s to new PCM slot %d (TX) %d (RX) on same chip or one bank PCM, because both members have not crossed slots\n", __FUNCTION__,
+					member->dsp->inst.name, nextm->dsp->inst.name, member->dsp->pcm_slot_tx,
+					member->dsp->pcm_slot_rx);
+			dsp_cmx_hw_message(member->dsp, HW_PCM_CONN, member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx);
+			dsp_cmx_hw_message(nextm->dsp, HW_PCM_CONN, nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx);
+			conf->hardware = 1;
+			conf->software = 0;
+			return;
+		}
+	}
+
+	/* if we have more than two, we may check if we have a conference
+	 * unit available on the chip. also all members must be on the same
+	 */
+
+	/* if not the same HFC chip */
+	if (same_hfc < 0) {
+		if (dsp_debug & DEBUG_DSP_CMX)
+			printk(KERN_DEBUG "%s conference %d cannot be formed, because members are on different chips or not on HFC chip\n",
+				__FUNCTION__, conf->id);
+		goto conf_software;
+	}
+
+	/* if all members already have the same conference */
+	if (all_conf)
+		return;
+
+	/* if there is an existing conference, but not all members have joined
+	 */
+	if (current_conf >= 0) {
+		join_members:
+		list_for_each_entry(member, &conf->mlist, list) {
+			/* join to current conference */
+			if (member->dsp->hfc_conf == current_conf) {
+				continue;
+			}
+			/* get a free timeslot first */
+			memset(freeslots, 1, sizeof(freeslots));
+			list_for_each_entry(dsp, &dsp_obj.ilist, list) {
+				/* not checking current member, because
+				 * slot will be overwritten.
+				 */
+				if (dsp!=member->dsp
+				/* dsp must be on the same PCM */
+				 && member->dsp->features.pcm_id==dsp->features.pcm_id) {
+					/* dsp must be on a slot */
+					if (dsp->pcm_slot_tx>=0
+					 && dsp->pcm_slot_tx<sizeof(freeslots))
+						freeslots[dsp->pcm_slot_tx] = 0;
+					if (dsp->pcm_slot_rx>=0
+					 && dsp->pcm_slot_rx<sizeof(freeslots))
+						freeslots[dsp->pcm_slot_rx] = 0;
+				}
+			}
+			i = 0;
+			ii = member->dsp->features.pcm_slots;
+			while(i < ii) {
+				if (freeslots[i])
+					break;
+				i++;
+			}
+			if (i == ii) {
+				/* no more slots available */
+				if (dsp_debug & DEBUG_DSP_CMX)
+					printk(KERN_DEBUG "%s conference %d cannot be formed, because no slot free\n", __FUNCTION__, conf->id);
+				goto conf_software;
+			}
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "%s changing dsp %s to HW conference %d slot %d\n", __FUNCTION__, member->dsp->inst.name, current_conf, i);
+			/* assign free slot & set PCM & join conf */
+			member->dsp->pcm_slot_tx = i;
+			member->dsp->pcm_slot_rx = i;
+			member->dsp->pcm_bank_tx = 2; /* loop */
+			member->dsp->pcm_bank_rx = 2;
+			member->dsp->hfc_conf = current_conf;
+			dsp_cmx_hw_message(member->dsp, HW_PCM_CONN, i, 2, i, 2);
+			dsp_cmx_hw_message(member->dsp, HW_CONF_JOIN, current_conf, 0, 0, 0);
+		}
+		return;
+	}
+
+	/* no member is in a conference yet, so we find a free one
+	 */
+	memset(freeunits, 1, sizeof(freeunits));
+	list_for_each_entry(dsp, &dsp_obj.ilist, list) {
+		/* dsp must be on the same chip */
+		if (dsp->features.hfc_id==same_hfc
+		/* dsp must have joined a HW conference */
+		 && dsp->hfc_conf>=0
+		/* slot must be within range */
+		 && dsp->hfc_conf<8)
+			freeunits[dsp->hfc_conf] = 0;
+	}
+	i = 0;
+	ii = 8;
+	while(i < ii) {
+		if (freeunits[i])
+			break;
+		i++;
+	}
+	if (i == ii) {
+		/* no more conferences available */
+		if (dsp_debug & DEBUG_DSP_CMX)
+			printk(KERN_DEBUG "%s conference %d cannot be formed, because no conference number free\n", __FUNCTION__, conf->id);
+		goto conf_software;
+	}
+	/* join all members */
+	current_conf = i;
+	goto join_members;
+}
+
+
+/*
+ * conf_id != 0: join or change conference
+ * conf_id == 0: split from conference if not already
+ */
+int
+dsp_cmx_conf(dsp_t *dsp, u32 conf_id)
+{
+	int err;
+	conference_t *conf;
+
+	/* if conference doesn't change */
+	if (dsp->conf_id == conf_id)
+		return(0);
+
+	spin_lock(&dsp->feature_lock);
+	if (dsp->feature_state != FEAT_STATE_RECEIVED) {
+		dsp->queue_conf_id=conf_id;	
+		spin_unlock(&dsp->feature_lock);
+		return 0;
+	}
+	spin_unlock(&dsp->feature_lock);
+
+	/* first remove us from current conf */
+	if (dsp->conf_id) {
+		if (dsp_debug & DEBUG_DSP_CMX)
+			printk(KERN_DEBUG "removing us from conference %d\n",
+				dsp->conf->id);
+		/* remove us from conf */
+		conf = dsp->conf;
+		err = dsp_cmx_del_conf_member(dsp);
+		if (err)
+			return(err);
+		dsp->conf_id = 0;
+
+		/* update hardware */
+		dsp_cmx_hardware(NULL, dsp);
+
+		/* conf now empty? */
+		if (list_empty(&conf->mlist)) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "conference is empty, so we remove it.\n");
+			err = dsp_cmx_del_conf(conf);
+			if (err)
+				return(err);
+		} else {
+			/* update members left on conf */
+			dsp_cmx_hardware(conf, NULL);
+		}
+	}
+
+	/* if split */
+	if (!conf_id)
+		return(0);
+
+	/* now add us to conf */
+	if (dsp_debug & DEBUG_DSP_CMX)
+		printk(KERN_DEBUG "searching conference %d\n",
+			conf_id);
+	conf = dsp_cmx_search_conf(conf_id);
+	if (!conf) {
+		if (dsp_debug & DEBUG_DSP_CMX)
+			printk(KERN_DEBUG "conference doesn't exist yet, creating.\n");
+		/* the conference doesn't exist, so we create */
+		conf = dsp_cmx_new_conf(conf_id);
+		if (!conf)
+			return(-EINVAL);
+	}
+	/* add conference member */
+	err = dsp_cmx_add_conf_member(dsp, conf);
+	if (err)
+		return(err);
+	dsp->conf_id = conf_id;
+
+	/* if we are alone, we do nothing! */
+	if (list_empty(&conf->mlist)) {
+		if (dsp_debug & DEBUG_DSP_CMX)
+			printk(KERN_DEBUG "we are alone in this conference, so exit.\n");
+		/* update hardware */
+		dsp_cmx_hardware(NULL, dsp);
+		return(0);
+	}
+
+	/* update members on conf */
+	dsp_cmx_hardware(conf, NULL);
+
+	return(0);
+}
+
+
+/*
+ * audio data is received from card
+ */
+void 
+dsp_cmx_receive(dsp_t *dsp, struct sk_buff *skb)
+{
+//	s32 *c;
+	u8 *d, *p;
+	int len = skb->len;
+	mISDN_head_t *hh = mISDN_HEAD_P(skb);
+	int w, i, ii;
+//	int direct = 0; /* use rx data to clock tx-data */
+
+	/* check if we have sompen */
+	if (len < 1)
+		return;
+
+#if 0
+	/* check if we can use our clock and directly forward data */
+	if (!dsp->features.has_jitter) {
+		if (!conf)
+			direct = 1;
+		else {
+			if (count_list_member(&conf->mlist) <= 2)
+				direct = 1;
+		}
+	}
+#endif
+
+	/* half of the buffer should be larger than maximum packet size */
+	if (len >= CMX_BUFF_HALF) {
+		printk(KERN_ERR "%s line %d: packet from card is too large (%d bytes). please make card send smaller packets OR increase CMX_BUFF_SIZE\n", __FILE__, __LINE__, len);
+		return;
+	}
+
+	/* initialize pointers if not already */
+	if (dsp->rx_W < 0) {
+		if (dsp->features.has_jitter)
+			dsp->rx_R = dsp->rx_W = (hh->dinfo & CMX_BUFF_MASK);
+		else
+			dsp->rx_R = dsp->rx_W = 0;
+	} else {
+		if (dsp->features.has_jitter) {
+			dsp->rx_W = (hh->dinfo & CMX_BUFF_MASK);
+		}
+		/* if we underrun (or maybe overrun), we set our new read pointer, and write silence to buffer */
+		if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) {
+			if (dsp_debug & DEBUG_DSP_CMX)
+				printk(KERN_DEBUG "cmx_receive(dsp=%lx): UNDERRUN (or overrun), adjusting read pointer! (inst %s)\n", (u_long)dsp, dsp->inst.name);
+			dsp->rx_R = dsp->rx_W;
+			memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));
+		}
+	}
+
+	/* show where to write */
+#ifdef CMX_DEBUG
+	printk( KERN_DEBUG "cmx_receive(dsp=%lx): rx_R(dsp) rx_W(dsp)=%05x len=%d %s\n", (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->inst.name);
+#endif
+
+	/* write data into rx_buffer */
+	p = skb->data;
+	d = dsp->rx_buff;
+	w = dsp->rx_W;
+	i = 0;
+	ii = len;
+	while(i < ii) {
+		d[w++ & CMX_BUFF_MASK] = *p++;
+		i++;
+	}
+
+	/* increase write-pointer */
+	dsp->rx_W = ((dsp->rx_W+len) & CMX_BUFF_MASK);
+}
+
+
+/*
+ * send (mixed) audio data to card and control jitter
+ */
+static void
+dsp_cmx_send_member(dsp_t *dsp, int len, s32 *c, int members)
+{
+	int dinfo = 0;
+	conference_t *conf = dsp->conf;
+	dsp_t *member, *other;
+	register s32 sample;
+	u8 *d, *p, *q, *o_q;
+	struct sk_buff *nskb;
+	int r, rr, t, tt, o_r, o_rr;
+	
+	/* don't process if: */
+	if (dsp->pcm_slot_tx >= 0 /* connected to pcm slot */
+	 && dsp->tx_R == dsp->tx_W /* AND no tx-data */
+	 && !(dsp->tone.tone && dsp->tone.software)) /* AND not soft tones */
+		return;
+	if (!dsp->b_active) /* if not active */
+		return;
+
+#if 1
+	/* If we have 2 members and we are connected to pcm_slot, it looks
+	   like we're bridged on the pcm, so why should we send anything ? 
+	   */
+	if (	members==2 && (dsp->features.pcm_id>=0) && 
+		(dsp->pcm_slot_tx>=0) && (dsp->pcm_slot_rx>=0) ) {
+		return;
+	}
+#endif
+
+#ifdef CMX_DEBUG
+printk(KERN_DEBUG "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n", members, dsp->inst.name, conf, dsp->rx_R, dsp->rx_W);
+#endif
+
+	/* PREPARE RESULT */
+	nskb = alloc_skb(len, GFP_ATOMIC);
+	if (!nskb) {
+		printk(KERN_ERR "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n", len);
+		return;
+	}
+	mISDN_sethead(PH_DATA | REQUEST, dinfo, nskb);
+
+	/* set pointers, indexes and stuff */
+	member = dsp;
+	p = dsp->tx_buff; /* transmit data */
+	q = dsp->rx_buff; /* received data */
+	d = skb_put(nskb, len); /* result */
+	t = dsp->tx_R; /* tx-pointers */
+	tt = dsp->tx_W;
+	r = dsp->rx_R; /* rx-pointers */
+	rr = (r + len) & CMX_BUFF_MASK;
+
+	/* PROCESS TONES/TX-DATA ONLY */
+	if (dsp->tone.tone && dsp->tone.software) {
+		/* -> copy tone */
+		dsp_tone_copy(dsp, d, len);
+		dsp->tx_R = dsp->tx_W = 0; /* clear tx buffer */
+		goto send_packet;
+	}
+	/* if we have tx-data but do not use mixing */
+	if (!dsp->tx_mix && t!=tt) {
+		/* -> send tx-data and continue when not enough */
+		while(r!=rr && t!=tt) {
+			*d++ = p[t]; /* write tx_buff */
+			t = (t+1) & CMX_BUFF_MASK;
+			r = (r+1) & CMX_BUFF_MASK;
+		}
+		if(r == rr) {
+			dsp->tx_R = t;
+			goto send_packet;
+		}
+	}
+
+	/* PROCESS DATA (one member / no conf) */
+	if (!conf || members<=1) {
+		/* -> if echo is NOT enabled */
+		if (!dsp->echo) {
+			/* -> send tx-data if available or use 0-volume */
+			while(r!=rr && t!=tt) {
+				*d++ = p[t]; /* write tx_buff */
+				t = (t+1) & CMX_BUFF_MASK;
+				r = (r+1) & CMX_BUFF_MASK;
+			}
+			if(r != rr)
+				memset(d, dsp_silence, (rr-r)&CMX_BUFF_MASK);
+		/* -> if echo is enabled */
+		} else {
+			/* -> mix tx-data with echo if available, or use echo only */
+			while(r!=rr && t!=tt) {
+				*d++ = dsp_audio_mix_law[(p[t]<<8)|q[r]];
+				t = (t+1) & CMX_BUFF_MASK;
+				r = (r+1) & CMX_BUFF_MASK;
+			}
+			while(r != rr) {
+				*d++ = q[r]; /* echo */
+				r = (r+1) & CMX_BUFF_MASK;
+			}
+		}
+		dsp->tx_R = t;
+		goto send_packet;
+	}
+	/* PROCESS DATA (two members) */
+#ifdef CMX_CONF_DEBUG
+	if (0) {
+#else
+	if (members == 2) {
+#endif
+		/* "other" becomes other party */
+		other = (list_entry(conf->mlist.next, conf_member_t, list))->dsp;
+		if (other == member)
+			other = (list_entry(conf->mlist.prev, conf_member_t, list))->dsp;
+		o_q = other->rx_buff; /* received data */
+		o_r = other->rx_R; /* rx-pointers */
+		o_rr = (o_r + len) & CMX_BUFF_MASK;
+		/* -> if echo is NOT enabled */
+		if (!dsp->echo) {
+//if (o_r!=o_rr) printk(KERN_DEBUG "receive data=0x%02x\n", o_q[o_r]); else printk(KERN_DEBUG "NO R!!!\n");
+			/* -> copy other member's rx-data, if tx-data is available, mix */
+			while(o_r!=o_rr && t!=tt) {
+				*d++ = dsp_audio_mix_law[(p[t]<<8)|o_q[o_r]];
+				t = (t+1) & CMX_BUFF_MASK;
+				o_r = (o_r+1) & CMX_BUFF_MASK;
+			}
+			while(o_r != o_rr) {
+				*d++ = o_q[o_r];
+				o_r = (o_r+1) & CMX_BUFF_MASK;
+			}
+		/* -> if echo is enabled */
+		} else {
+			/* -> mix other member's rx-data with echo, if tx-data is available, mix */
+			while(r!=rr && t!=tt) {
+				sample = dsp_audio_law_to_s32[p[t]] + dsp_audio_law_to_s32[q[r]] + dsp_audio_law_to_s32[o_q[o_r]];
+				if (sample < -32768)
+					sample = -32768;
+				else if (sample > 32767)
+					sample = 32767;
+				*d++ = dsp_audio_s16_to_law[sample & 0xffff]; /* tx-data + rx_data + echo */
+				t = (t+1) & CMX_BUFF_MASK;
+				r = (r+1) & CMX_BUFF_MASK;
+				o_r = (o_r+1) & CMX_BUFF_MASK;
+			}
+			while(r != rr) {
+				*d++ = dsp_audio_mix_law[(q[r]<<8)|o_q[o_r]];
+				r = (r+1) & CMX_BUFF_MASK;
+				o_r = (o_r+1) & CMX_BUFF_MASK;
+			}
+		}
+		dsp->tx_R = t;
+		goto send_packet;
+	}
+	/* PROCESS DATA (three or more members) */
+	/* -> if echo is NOT enabled */
+	if (!dsp->echo) {
+		/* -> substract rx-data from conf-data, if tx-data is available, mix */
+		while(r!=rr && t!=tt) {
+			sample = dsp_audio_law_to_s32[p[t]] + *c++ - dsp_audio_law_to_s32[q[r]];
+			if (sample < -32768)
+				sample = -32768;
+			else if (sample > 32767)
+				sample = 32767;
+			*d++ = dsp_audio_s16_to_law[sample & 0xffff]; /* conf-rx+tx */
+			r = (r+1) & CMX_BUFF_MASK;
+			t = (t+1) & CMX_BUFF_MASK;
+		}
+		while(r != rr) {
+			sample = *c++ - dsp_audio_law_to_s32[q[r]];
+			if (sample < -32768)
+				sample = -32768;
+			else if (sample > 32767)
+				sample = 32767;
+			*d++ = dsp_audio_s16_to_law[sample & 0xffff]; /* conf-rx */
+			r = (r+1) & CMX_BUFF_MASK;
+		}
+	/* -> if echo is enabled */
+	} else {
+		/* -> encode conf-data, if tx-data is available, mix */
+		while(r!=rr && t!=tt) {
+			sample = dsp_audio_law_to_s32[p[t]] + *c++;
+			if (sample < -32768)
+				sample = -32768;
+			else if (sample > 32767)
+				sample = 32767;
+			*d++ = dsp_audio_s16_to_law[sample & 0xffff]; /* conf(echo)+tx */
+			t = (t+1) & CMX_BUFF_MASK;
+			r = (r+1) & CMX_BUFF_MASK;
+		}
+		while(r != rr) {
+			sample = *c++;
+			if (sample < -32768)
+				sample = -32768;
+			else if (sample > 32767)
+				sample = 32767;
+			*d++ = dsp_audio_s16_to_law[sample & 0xffff]; /* conf(echo) */
+			r = (r+1) & CMX_BUFF_MASK;
+		}
+	}
+	dsp->tx_R = t;
+	goto send_packet;
+
+send_packet:
+	/* adjust volume */
+	if (dsp->tx_volume)
+		dsp_change_volume(nskb, dsp->tx_volume);
+	
+	/* cancel echo */
+	if (dsp->cancel_enable)
+		dsp_cancel_tx(dsp, nskb->data, nskb->len);
+	
+	/* crypt */
+	if (dsp->bf_enable)
+		dsp_bf_encrypt(dsp, nskb->data, nskb->len);
+	
+	/* send packet */
+	if (mISDN_queue_down(&dsp->inst, 0, nskb)) {
+		dev_kfree_skb(nskb);
+		printk(KERN_ERR "%s: failed to send tx-packet\n", __FUNCTION__);
+	}
+}
+
+u32	samplecount;
+struct timer_list dsp_spl_tl;
+u64	dsp_spl_jiffies;
+
+void dsp_cmx_send(void *data)
+{
+	conference_t *conf;
+	conf_member_t *member;
+	dsp_t *dsp;
+	int mustmix, members;
+	s32 mixbuffer[MAX_POLL], *c;
+	u8 *q;
+	int r, rr;
+	int jittercheck = 0, delay, i;
+	u_long flags;
+
+	/* lock */
+	spin_lock_irqsave(&dsp_obj.lock, flags);
+
+	/* check if jitter needs to be checked */
+	samplecount += dsp_poll;
+	if (samplecount%8000 < dsp_poll)
+		jittercheck = 1;
+
+	/* loop all members that do not require conference mixing */
+	list_for_each_entry(dsp, &dsp_obj.ilist, list) {
+		conf = dsp->conf;
+		mustmix = 0;
+		members = 0;
+		if (conf) {
+			members = count_list_member(&conf->mlist);
+#ifdef CMX_CONF_DEBUG
+			if (conf->software && members>1)
+#else
+			if (conf->software && members>2)
+#endif
+				mustmix = 1;
+		}
+		
+		/* transmission required */
+		if (!mustmix && dsp->conf_id)
+			dsp_cmx_send_member(dsp, dsp_poll, mixbuffer, members); // unused mixbuffer is given to prevent a potential null-pointer-bug
+	}
+	
+	/* loop all members that require conference mixing */
+	list_for_each_entry(conf, &Conf_list, list) {
+		/* count members and check hardware */
+		members = count_list_member(&conf->mlist);
+#ifdef CMX_CONF_DEBUG
+		if (conf->software && members>1) {
+#else
+		if (conf->software && members>2) {
+#endif
+			/* mix all data */
+			memset(mixbuffer, 0, dsp_poll*sizeof(s32));
+			list_for_each_entry(member, &conf->mlist, list) {
+				dsp = member->dsp;
+				/* get range of data to mix */
+				c = mixbuffer;
+				q = dsp->rx_buff;
+				r = dsp->rx_R;
+				rr = (r + dsp_poll) & CMX_BUFF_MASK;
+				/* add member's data */
+				while(r != rr) {
+					*c++ += dsp_audio_law_to_s32[q[r]];
+					r = (r+1) & CMX_BUFF_MASK;
+				}
+			}
+
+			/* process each member */
+			list_for_each_entry(member, &conf->mlist, list) {
+				/* transmission */
+				if (member->dsp->conf_id)
+					dsp_cmx_send_member(member->dsp, dsp_poll, mixbuffer, members);
+			}
+		}
+	}
+
+	/* delete rx-data, increment buffers, change pointers */
+	list_for_each_entry(dsp, &dsp_obj.ilist, list) {
+		q = dsp->rx_buff;
+		r = dsp->rx_R;
+		rr = (r + dsp_poll) & CMX_BUFF_MASK;
+		/* delete rx-data */
+		while(r != rr) {
+			q[r] = dsp_silence;
+			r = (r+1) & CMX_BUFF_MASK;
+		}
+		/* increment rx-buffer pointer */
+		dsp->rx_R = r; /* write incremented read pointer */
+
+		/* check current delay */
+		delay = (dsp->rx_W-r) & CMX_BUFF_MASK;
+		if (delay >= CMX_BUFF_HALF)
+			delay = 0; /* will be the delay before next write */
+		/* check for lower delay */
+			if (delay < dsp->delay[0])
+				dsp->delay[0] = delay;
+		if (jittercheck) {
+			/* find the lowest of all delays */
+			delay = dsp->delay[0];
+			i = 1;
+			while (i < MAX_SECONDS_JITTER_CHECK) {
+				if (delay > dsp->delay[i])
+					delay = dsp->delay[i];
+				i++;
+			}
+			/* remove delay */
+			if (delay) {
+				if (dsp_debug & DEBUG_DSP_CMX)
+					printk(KERN_DEBUG "%s lowest delay of %d bytes for dsp %s are now removed.\n", __FUNCTION__, delay, dsp->inst.name);
+				r = dsp->rx_R;
+				rr = (r + delay) & CMX_BUFF_MASK;
+				/* delete rx-data */
+				while(r != rr) {
+					q[r] = dsp_silence;
+					r = (r+1) & CMX_BUFF_MASK;
+				}
+				/* increment rx-buffer pointer */
+				dsp->rx_R = r; /* write incremented read pointer */
+			}
+			/* scroll up delays */
+			i = MAX_SECONDS_JITTER_CHECK - 1;
+			while (i) {
+				dsp->delay[i] = dsp->delay[i-1];
+				i--;
+			}
+			dsp->delay[0] = CMX_BUFF_HALF; /* (infinite) delay */
+		}
+	}
+
+	/* restart timer */
+//	init_timer(&dsp_spl_tl);
+	if (dsp_spl_jiffies + dsp_tics < jiffies) /* if next event would be in the past ... */
+		dsp_spl_jiffies = jiffies;
+	else
+		dsp_spl_jiffies += dsp_tics;
+
+	dsp_spl_tl.expires = dsp_spl_jiffies;
+	add_timer(&dsp_spl_tl);
+
+	/* unlock */
+	spin_unlock_irqrestore(&dsp_obj.lock, flags);
+}
+
+/*
+ * audio data is transmitted from upper layer to the dsp
+ */
+void 
+dsp_cmx_transmit(dsp_t *dsp, struct sk_buff *skb)
+{
+	u_int w, ww;
+	u8 *d, *p;
+	int space, l;
+
+	/* check if we have sompen */
+	l = skb->len;
+	if (l < 1)
+		return;
+
+	/* check if there is enough space, and then copy */
+	w = dsp->tx_W;
+	ww = dsp->tx_R;
+	p = dsp->tx_buff;
+	d = skb->data;
+	space = ww-w;
+	if (space <= 0)
+		space += CMX_BUFF_SIZE;
+	/* write-pointer should not overrun nor reach read pointer */
+	if (space-1 < skb->len)
+		/* write to the space we have left */
+		ww = (ww - 1) & CMX_BUFF_MASK;
+	else
+		/* write until all byte are copied */
+		ww = (w + skb->len) & CMX_BUFF_MASK;
+	dsp->tx_W = ww;
+
+	/* show current buffer */
+#ifdef CMX_DEBUG
+	printk(KERN_DEBUG "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n", (u_long)dsp, (ww-w)&CMX_BUFF_MASK, w, ww, dsp->inst.name);
+#endif
+
+	/* copy transmit data to tx-buffer */
+	while(w != ww) {
+		p[w]= *d++;
+		w = (w+1) & CMX_BUFF_MASK;
+	}
+
+	return;
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_core.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_core.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_core.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1079 @@
+/* $Id: dsp_core.c,v 1.29 2007/03/27 15:06:29 jolly Exp $
+ *
+ * Author       Andreas Eversberg (jolly at eversberg.eu)
+ * Based on source code structure by
+ *		Karsten Keil (keil at isdn4linux.de)
+ *
+ *		This file is (c) under GNU PUBLIC LICENSE
+ *		For changes and modifications please read
+ *		../../../Documentation/isdn/mISDN.cert
+ *
+ * Thanks to    Karsten Keil (great drivers)
+ *              Cologne Chip (great chips)
+ *
+ * This module does:
+ *		Real-time tone generation
+ *		DTMF detection
+ *		Real-time cross-connection and conferrence
+ *		Compensate jitter due to system load and hardware fault.
+ *		All features are done in kernel space and will be realized
+ *		using hardware, if available and supported by chip set.
+ *		Blowfish encryption/decryption
+ */
+
+/* STRUCTURE:
+ *
+ * The dsp module provides layer 2 for b-channels (64kbit). It provides
+ * transparent audio forwarding with special digital signal processing:
+ *
+ * - (1) generation of tones
+ * - (2) detection of dtmf tones
+ * - (3) crossconnecting and conferences
+ * - (4) echo generation for delay test
+ * - (5) volume control
+ * - (6) disable receive data
+ * - (7) echo cancelation
+ * - (8) encryption/decryption
+ *
+ * Look:
+ *             TX            RX
+ *         ------upper layer------
+ *             |             ^
+ *             |             |(6)
+ *             v             |
+ *       +-----+-------------+-----+
+ *       |(3)(4)                   |
+ *       |           CMX           |
+ *       |                         |
+ *       |           +-------------+
+ *       |           |       ^
+ *       |           |       |
+ *       |+---------+|  +----+----+
+ *       ||(1)      ||  |(5)      |
+ *       ||         ||  |         |
+ *       ||  Tones  ||  |RX Volume|
+ *       ||         ||  |         |
+ *       ||         ||  |         |
+ *       |+----+----+|  +----+----+
+ *       +-----+-----+       ^
+ *             |             | 
+ *             v             |
+ *        +----+----+   +----+----+
+ *        |(5)      |   |(2)      |
+ *        |         |   |         |
+ *        |TX Volume|   |  DTMF   |
+ *        |         |   |         |
+ *        |         |   |         |
+ *        +----+----+   +----+----+
+ *             |             ^ 
+ *             |             |
+ *             v             |
+ *        +----+-------------+----+
+ *        |(7)                    |
+ *        |                       |
+ *        |   Echo Cancellation   |
+ *        |                       |
+ *        |                       |
+ *        +----+-------------+----+
+ *             |             ^ 
+ *             |             |
+ *             v             |
+ *        +----+----+   +----+----+
+ *        |(8)      |   |(8)      |
+ *        |         |   |         |
+ *        | Encrypt |   | Decrypt |
+ *        |         |   |         |
+ *        |         |   |         |
+ *        +----+----+   +----+----+
+ *             |             ^ 
+ *             |             |
+ *             v             |
+ *         ------card  layer------
+ *             TX            RX
+ *
+ * Above you can see the logical data flow. If software is used to do the
+ * process, it is actually the real data flow. If hardware is used, data
+ * may not flow, but hardware commands to the card, to provide the data flow
+ * as shown.
+ *
+ * NOTE: The channel must be activated in order to make dsp work, even if
+ * no data flow to the upper layer is intended. Activation can be done
+ * after and before controlling the setting using PH_CONTROL requests.
+ *
+ * DTMF: Will be detected by hardware if possible. It is done before CMX 
+ * processing.
+ *
+ * Tones: Will be generated via software if endless looped audio fifos are
+ * not supported by hardware. Tones will override all data from CMX.
+ * It is not required to join a conference to use tones at any time.
+ *
+ * CMX: Is transparent when not used. When it is used, it will do
+ * crossconnections and conferences via software if not possible through
+ * hardware. If hardware capability is available, hardware is used.
+ *
+ * Echo: Is generated by CMX and is used to check performane of hard and
+ * software CMX.
+ *
+ * The CMX has special functions for conferences with one, two and more
+ * members. It will allow different types of data flow. Receive and transmit
+ * data to/form upper layer may be swithed on/off individually without loosing
+ * features of CMX, Tones and DTMF.
+ *
+ * Echo Cancellation: Sometimes we like to cancel echo from the interface.
+ * Note that a VoIP call may not have echo caused by the IP phone. The echo
+ * is generated by the telephone line connected to it. Because the delay
+ * is high, it becomes an echo. RESULT: Echo Cachelation is required if
+ * both echo AND delay is applied to an interface.
+ * Remember that software CMX always generates a more or less delay.
+ *
+ * If all used features can be realized in hardware, and if transmit and/or
+ * receive data ist disabled, the card may not send/receive any data at all.
+ * Not receiving is usefull if only announcements are played. Not sending is
+ * usefull if an answering machine records audio. Not sending and receiving is
+ * usefull during most states of the call. If supported by hardware, tones
+ * will be played without cpu load. Small PBXs and NT-Mode applications will
+ * not need expensive hardware when processing calls.
+ *
+ *
+ * LOCKING:
+ *
+ * When data is received from upper or lower layer (card), the complete dsp
+ * module is locked by a global lock.  When data is ready to be transmitted
+ * to a different layer, the module is unlocked. It is not allowed to hold a
+ * lock outside own layer.
+ * Reasons: Multiple threads must not process cmx at the same time, if threads
+ * serve instances, that are connected in same conference.
+ * PH_CONTROL must not change any settings, join or split conference members
+ * during process of data.
+ * 
+ *
+ * TRANSMISSION:
+ *
+
+TBD
+
+There are three things that need to receive data from card:
+ - software DTMF decoder
+ - software cmx (if conference exists)
+ - upper layer, if rx-data not disabled
+
+Whenever dtmf decoder is turned on or off, software cmx changes, rx-data is disabled or enabled, or card becomes activated, then rx-data is disabled or enabled using a special command to the card.
+
+There are three things that need to transmit data to card:
+ - software tone generation (part of cmx)
+ - software cmx
+ - upper layer, if tx-data is written to tx-buffer
+
+
+
+ 
+ */
+
+const char *dsp_revision = "$Revision: 1.29 $";
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include "core.h"
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+#include "dsp.h"
+
+static char DSPName[] = "DSP";
+mISDNobject_t dsp_obj;
+
+static int debug = 0;
+int dsp_debug;
+static int options = 0;
+int dsp_options;
+static int poll = 0;
+int dsp_poll, dsp_tics;
+
+int dtmfthreshold=100L;
+
+#ifdef MODULE
+MODULE_AUTHOR("Andreas Eversberg");
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+MODULE_PARM(options, "1i");
+MODULE_PARM(poll, "1i");
+MODULE_PARM(dtmfthreshold, "1i");
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+module_param(options, uint, S_IRUGO | S_IWUSR);
+module_param(poll, uint, S_IRUGO | S_IWUSR);
+module_param(dtmfthreshold, uint, S_IRUGO | S_IWUSR);
+#endif
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#endif
+
+
+/*
+ * special message process for DL_CONTROL | REQUEST
+ */
+static int
+dsp_control_req(dsp_t *dsp, mISDN_head_t *hh, struct sk_buff *skb)
+{
+	struct		sk_buff *nskb;
+	int ret = 0;
+	int cont;
+	u8 *data;
+	int len;
+
+	if (skb->len < sizeof(int)) {
+		printk(KERN_ERR "%s: PH_CONTROL message too short\n", __FUNCTION__);
+	}
+	cont = *((int *)skb->data);
+	len = skb->len - sizeof(int);
+	data = skb->data + sizeof(int);
+
+	switch (cont) {
+		case DTMF_TONE_START: /* turn on DTMF */
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: start dtmf\n", __FUNCTION__);
+#if 0
+			if (len == sizeof(int)) {
+				printk(KERN_NOTICE "changing DTMF Threshold to %d\n",*((int*)data));
+				dsp->dtmf.treshold=(*(int*)data)*10000;
+			}
+#endif
+
+			dsp_dtmf_goertzel_init(dsp);
+			/* checking for hardware capability */
+			if (dsp->features.hfc_dtmf) {
+				dsp->dtmf.hardware = 1;
+				dsp->dtmf.software = 0;
+			} else {
+				dsp->dtmf.hardware = 0;
+				dsp->dtmf.software = 1;
+			}
+			break;
+		case DTMF_TONE_STOP: /* turn off DTMF */
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: stop dtmf\n", __FUNCTION__);
+			dsp->dtmf.hardware = 0;
+			dsp->dtmf.software = 0;
+			break;
+		case CMX_CONF_JOIN: /* join / update conference */
+			if (len != sizeof(int)) {
+				ret = -EINVAL;
+				break;
+			}
+			if (*((u32 *)data) == 0)
+				goto conf_split;
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: join conference %d\n", __FUNCTION__, *((u32 *)data));
+			ret = dsp_cmx_conf(dsp, *((u32 *)data));
+			if (dsp_debug & DEBUG_DSP_CMX)
+				dsp_cmx_debug(dsp);
+			break;
+		case CMX_CONF_SPLIT: /* remove from conference */
+			conf_split:
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: release conference\n", __FUNCTION__);
+			ret = dsp_cmx_conf(dsp, 0);
+			if (dsp_debug & DEBUG_DSP_CMX)
+				dsp_cmx_debug(dsp);
+			break;
+		case TONE_PATT_ON: /* play tone */
+			if (len != sizeof(int)) {
+				ret = -EINVAL;
+				break;
+			}
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: turn tone 0x%x on\n", __FUNCTION__, *((int *)skb->data));
+			ret = dsp_tone(dsp, *((int *)data));
+			if (!ret)
+				dsp_cmx_hardware(dsp->conf, dsp);
+			if (!dsp->tone.tone)
+				goto tone_off;
+			break;
+		case TONE_PATT_OFF: /* stop tone */
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: turn tone off\n", __FUNCTION__);
+			dsp_tone(dsp, 0);
+			dsp_cmx_hardware(dsp->conf, dsp);
+			/* reset tx buffers (user space data) */
+			tone_off:
+			dsp->tx_R = dsp->tx_W = 0;
+			break;
+		case VOL_CHANGE_TX: /* change volume */
+			if (len != sizeof(int)) {
+				ret = -EINVAL;
+				break;
+			}
+			dsp->tx_volume = *((int *)data);
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: change tx volume to %d\n", __FUNCTION__, dsp->tx_volume);
+			dsp_cmx_hardware(dsp->conf, dsp);
+			break;
+		case VOL_CHANGE_RX: /* change volume */
+			if (len != sizeof(int)) {
+				ret = -EINVAL;
+				break;
+			}
+			dsp->rx_volume = *((int *)data);
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: change rx volume to %d\n", __FUNCTION__, dsp->tx_volume);
+			dsp_cmx_hardware(dsp->conf, dsp);
+			break;
+		case CMX_ECHO_ON: /* enable echo */
+			dsp->echo = 1; /* soft echo */
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: enable cmx-echo\n", __FUNCTION__);
+			dsp_cmx_hardware(dsp->conf, dsp);
+			if (dsp_debug & DEBUG_DSP_CMX)
+				dsp_cmx_debug(dsp);
+			break;
+		case CMX_ECHO_OFF: /* disable echo */
+			dsp->echo = 0;
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: disable cmx-echo\n", __FUNCTION__);
+			dsp_cmx_hardware(dsp->conf, dsp);
+			if (dsp_debug & DEBUG_DSP_CMX)
+				dsp_cmx_debug(dsp);
+			break;
+		case CMX_RECEIVE_ON: /* enable receive to user space */
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: enable receive to user space\n", __FUNCTION__);
+			dsp->rx_disabled = 0;
+			dsp_cmx_hardware(dsp->conf, dsp);
+			break;
+		case CMX_RECEIVE_OFF: /* disable receive to user space */
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: disable receive to user space\n", __FUNCTION__);
+			dsp->rx_disabled = 1;
+			dsp_cmx_hardware(dsp->conf, dsp);
+			break;
+		case CMX_MIX_ON: /* enable mixing of transmit data with conference members */
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: enable mixing of tx-data with conf mebers\n", __FUNCTION__);
+			dsp->tx_mix = 1;
+			dsp_cmx_hardware(dsp->conf, dsp);
+			if (dsp_debug & DEBUG_DSP_CMX)
+				dsp_cmx_debug(dsp);
+			break;
+		case CMX_MIX_OFF: /* disable mixing of transmit data with conference members */
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: disable mixing of tx-data with conf mebers\n", __FUNCTION__);
+			dsp->tx_mix = 0;
+			dsp_cmx_hardware(dsp->conf, dsp);
+			if (dsp_debug & DEBUG_DSP_CMX)
+				dsp_cmx_debug(dsp);
+			break;
+		case ECHOCAN_ON: /* turn echo calcellation on */
+			if (len<4) {
+				ret = -EINVAL;
+			} else {
+				int ec_arr[2];
+				memcpy(&ec_arr,data,sizeof(ec_arr));
+				if (dsp_debug & DEBUG_DSP_CORE)
+					printk(KERN_DEBUG "%s: turn echo cancelation on (delay=%d attenuation-shift=%d\n",
+						__FUNCTION__, ec_arr[0], ec_arr[1]);
+			
+				ret = dsp_cancel_init(dsp, ec_arr[0], ec_arr[1] ,1);
+				dsp_cmx_hardware(dsp->conf, dsp);
+			}
+			break;
+		case ECHOCAN_OFF: /* turn echo calcellation off */
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: turn echo cancelation off\n", __FUNCTION__);
+			
+			ret = dsp_cancel_init(dsp, 0,0,-1);
+			dsp_cmx_hardware(dsp->conf, dsp);
+			break;
+		case BF_ENABLE_KEY: /* turn blowfish on */
+			if (len<4 || len>56) {
+				ret = -EINVAL;
+				break;
+			}
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: turn blowfish on (key not shown)\n", __FUNCTION__);
+			ret = dsp_bf_init(dsp, (u8*)data, len);
+			/* set new cont */
+			if (!ret)
+				cont = BF_ACCEPT;
+			else
+				cont = BF_REJECT;
+			/* send indication if it worked to set it */
+			nskb = create_link_skb(PH_CONTROL | INDICATION, 0, sizeof(int), &cont, 0);
+			if (mISDN_queue_up(&dsp->inst, 0, nskb))
+				dev_kfree_skb(nskb);
+			if (!ret)
+				dsp_cmx_hardware(dsp->conf, dsp);
+			break;
+		case BF_DISABLE: /* turn blowfish off */
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: turn blowfish off\n", __FUNCTION__);
+			dsp_bf_cleanup(dsp);
+			dsp_cmx_hardware(dsp->conf, dsp);
+			break;
+		default:
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: ctrl req %x unhandled\n", __FUNCTION__, cont);
+			ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+
+/*
+ * messages from upper layers
+ */
+static int
+dsp_from_up(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	dsp_t			*dsp;
+	mISDN_head_t		*hh;
+	int			ret = 0;
+	u_long		flags;
+
+	if (!skb)
+		return(-EINVAL);
+	dsp = inst->privat;
+	if (!dsp) {
+		return(-EIO);
+	}
+
+	hh = mISDN_HEAD_P(skb);
+	switch(hh->prim) {
+		case DL_DATA | RESPONSE:
+		case PH_DATA | RESPONSE:
+			/* ignore response */
+			dev_kfree_skb(skb);
+			break;
+		case DL_DATA | REQUEST:
+		case PH_DATA | REQUEST:
+			if (skb->len < 1)
+				return(-EINVAL);
+			
+			if (!dsp->conf_id) {
+				/* PROCESS TONES/TX-DATA ONLY */
+				if (dsp->tone.tone) {
+					/* -> copy tone */
+					dsp_tone_copy(dsp, skb->data, skb->len);
+				}
+
+				if (dsp->tx_volume)
+			                dsp_change_volume(skb, dsp->tx_volume);
+				/* cancel echo */
+				if (dsp->cancel_enable)
+					dsp_cancel_tx(dsp, skb->data, skb->len);
+				/* crypt */
+				if (dsp->bf_enable)
+					dsp_bf_encrypt(dsp, skb->data, skb->len);
+				/* send packet */
+				if (mISDN_queue_down(&dsp->inst, 0, skb)) {
+					dev_kfree_skb(skb);
+					printk(KERN_ERR "%s: failed to send tx-packet\n", __FUNCTION__);
+
+					return (-EIO);
+				}
+
+			} else {
+				if (dsp->features.pcm_id>=0) {
+					printk("Not sending Data to CMX -- > returning because of HW bridge\n");
+					dev_kfree_skb(skb);
+					break;
+				}
+				/* send data to tx-buffer (if no tone is played) */
+				spin_lock_irqsave(&dsp_obj.lock, flags);
+				if (!dsp->tone.tone) {
+					dsp_cmx_transmit(dsp, skb);
+				} 
+				spin_unlock_irqrestore(&dsp_obj.lock, flags);
+
+				dev_kfree_skb(skb);
+			}
+			break;
+		case PH_CONTROL | REQUEST:
+			
+			spin_lock_irqsave(&dsp_obj.lock, flags);
+			ret = dsp_control_req(dsp, hh, skb);
+			spin_unlock_irqrestore(&dsp_obj.lock, flags);
+			
+			break;
+		case DL_ESTABLISH | REQUEST:
+		case PH_ACTIVATE | REQUEST:
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: activating b_channel %s\n", __FUNCTION__, dsp->inst.name);
+			
+			if (dsp->dtmf.hardware || dsp->dtmf.software)
+				dsp_dtmf_goertzel_init(dsp);
+			hh->prim = PH_ACTIVATE | REQUEST;
+			ret = mISDN_queue_down(&dsp->inst, 0, skb);
+			
+			break;
+		case DL_RELEASE | REQUEST:
+		case PH_DEACTIVATE | REQUEST:
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: releasing b_channel %s\n", __FUNCTION__, dsp->inst.name);
+			
+			dsp->tone.tone = dsp->tone.hardware = dsp->tone.software = 0;
+			if (timer_pending(&dsp->tone.tl))
+				del_timer(&dsp->tone.tl);
+			hh->prim = PH_DEACTIVATE | REQUEST;
+			ret = mISDN_queue_down(&dsp->inst, 0, skb);
+			
+			break;
+		default:
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: msg %x unhandled %s\n", __FUNCTION__, hh->prim, dsp->inst.name);
+			ret = -EINVAL;
+			break;
+	}
+	return(ret);
+}
+
+
+/*
+ * messages from lower layers
+ */
+static int
+dsp_from_down(mISDNinstance_t *inst,  struct sk_buff *skb)
+{
+	dsp_t		*dsp;
+	mISDN_head_t	*hh;
+	int		ret = 0;
+	u8		*digits;
+	int 		cont;
+	struct		sk_buff *nskb;
+	u_long		flags;
+
+	if (!skb)
+		return(-EINVAL);
+	dsp = inst->privat;
+	if (!dsp)
+		return(-EIO);
+
+	hh = mISDN_HEAD_P(skb);
+	switch(hh->prim)
+	{
+		case PH_DATA | CONFIRM:
+		case DL_DATA | CONFIRM:
+			/* flush response, because no relation to upper layer */
+			dev_kfree_skb(skb);
+			break;
+		case PH_DATA | INDICATION:
+		case DL_DATA | INDICATION:
+			if (skb->len < 1)
+				return(-EINVAL);
+
+			
+			
+			/* decrypt if enabled */
+			if (dsp->bf_enable)
+				dsp_bf_decrypt(dsp, skb->data, skb->len);
+			/* if echo cancellation is enabled */
+			if (dsp->cancel_enable)
+				dsp_cancel_rx(dsp, skb->data, skb->len);
+			/* check if dtmf soft decoding is turned on */
+			if (dsp->dtmf.software) {
+				digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, (dsp_options&DSP_OPT_ULAW)?1:0);
+				if (digits) while(*digits) {
+					if (dsp_debug & DEBUG_DSP_DTMF)
+						printk(KERN_DEBUG "%s: sending software decoded digit(%c) to upper layer %s\n", __FUNCTION__, *digits, dsp->inst.name);
+					cont = DTMF_TONE_VAL | *digits;
+					nskb = create_link_skb(PH_CONTROL | INDICATION, 0, sizeof(int), &cont, 0);
+					if (mISDN_queue_up(&dsp->inst, 0, nskb))
+						dev_kfree_skb(nskb);
+					digits++;
+				}
+			}
+			/* change volume if requested */
+			if (dsp->rx_volume)
+				dsp_change_volume(skb, dsp->rx_volume);
+
+			if (dsp->conf_id) {
+				/* we need to process receive data if software */
+				spin_lock_irqsave(&dsp_obj.lock, flags);
+				if (dsp->pcm_slot_tx<0 && dsp->pcm_slot_rx<0) {
+					/* process data from card at cmx */
+					dsp_cmx_receive(dsp, skb);
+				}
+				spin_unlock_irqrestore(&dsp_obj.lock, flags);
+			}
+
+			if (dsp->rx_disabled) {
+				/* if receive is not allowed */
+				dev_kfree_skb(skb);
+				
+				break;
+			}
+			hh->prim = DL_DATA | INDICATION;
+			ret = mISDN_queue_up(&dsp->inst, 0, skb);
+			
+			break;
+		case PH_CONTROL | INDICATION:
+			
+			if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
+				printk(KERN_DEBUG "%s: PH_CONTROL received: %x (len %d) %s\n", __FUNCTION__, hh->dinfo, skb->len, dsp->inst.name);
+			switch (hh->dinfo) {
+				case HW_HFC_COEFF: /* getting coefficients */
+				if (!dsp->dtmf.hardware) {
+					if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
+						printk(KERN_DEBUG "%s: ignoring DTMF coefficients from HFC\n", __FUNCTION__);
+					dev_kfree_skb(skb);
+					break;
+				}
+				digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, 2);
+				if (digits) while(*digits) {
+					int k;
+					struct sk_buff *nskb;
+					if (dsp_debug & DEBUG_DSP_DTMF)
+						printk(KERN_DEBUG "%s: now sending software decoded digit(%c) to upper layer %s\n", __FUNCTION__, *digits, dsp->inst.name);
+					k = *digits | DTMF_TONE_VAL;
+					nskb = create_link_skb(PH_CONTROL | INDICATION, 0, sizeof(int), &k, 0);
+					if (mISDN_queue_up(&dsp->inst, 0, nskb))
+						dev_kfree_skb(nskb);
+					digits++;
+				}
+				dev_kfree_skb(skb);
+				break;
+
+				case VOL_CHANGE_TX: /* change volume */
+				if (skb->len != sizeof(int)) {
+					ret = -EINVAL;
+					break;
+				}
+				dsp->tx_volume = *((int *)skb->data);
+				if (dsp_debug & DEBUG_DSP_CORE)
+					printk(KERN_DEBUG "%s: change tx volume to %d\n", __FUNCTION__, dsp->tx_volume);
+				printk(KERN_DEBUG "%s: change tx volume to %d\n", __FUNCTION__, dsp->tx_volume);
+				dsp_cmx_hardware(dsp->conf, dsp);
+				break;
+				default:
+				if (dsp_debug & DEBUG_DSP_CORE)
+					printk(KERN_DEBUG "%s: ctrl ind %x unhandled %s\n", __FUNCTION__, hh->dinfo, dsp->inst.name);
+				ret = -EINVAL;
+			}
+			
+			break;
+		case PH_ACTIVATE | CONFIRM:
+			
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: b_channel is now active %s\n", __FUNCTION__, dsp->inst.name);
+			/* bchannel now active */
+			spin_lock_irqsave(&dsp_obj.lock, flags);
+			dsp->b_active = 1;
+			dsp->tx_W = dsp->tx_R = 0; /* clear TX buffer */
+			dsp->rx_W = dsp->rx_R = -1; /* reset RX buffer */
+			memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff));
+			dsp_cmx_hardware(dsp->conf, dsp);
+			spin_unlock_irqrestore(&dsp_obj.lock, flags);
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: done with activation, sending confirm to user space. %s\n", __FUNCTION__, dsp->inst.name);
+			/* send activation to upper layer */
+			hh->prim = DL_ESTABLISH | CONFIRM;
+			ret = mISDN_queue_up(&dsp->inst, 0, skb);
+			
+			break;
+		case PH_DEACTIVATE | CONFIRM:
+			
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: b_channel is now inactive %s\n", __FUNCTION__, dsp->inst.name);
+			/* bchannel now inactive */
+			spin_lock_irqsave(&dsp_obj.lock, flags);
+			dsp->b_active = 0;
+			dsp_cmx_hardware(dsp->conf, dsp);
+			spin_unlock_irqrestore(&dsp_obj.lock, flags);
+			hh->prim = DL_RELEASE | CONFIRM;
+			ret = mISDN_queue_up(&dsp->inst, 0, skb);
+			
+			break;
+		default:
+			if (dsp_debug & DEBUG_DSP_CORE)
+				printk(KERN_DEBUG "%s: msg %x unhandled %s\n", __FUNCTION__, hh->prim, dsp->inst.name);
+			ret = -EINVAL;
+	}
+	return(ret);
+}
+
+
+/*
+ * messages from queue
+ */
+static int
+dsp_function(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	mISDN_head_t *hh;
+	int ret = -EINVAL;
+
+	hh = mISDN_HEAD_P(skb);
+	switch (hh->addr & MSG_DIR_MASK) {
+		case FLG_MSG_DOWN:
+			ret = dsp_from_up(inst, skb);
+			break;
+		case FLG_MSG_UP:
+			ret = dsp_from_down(inst, skb);
+			break;
+	}
+
+	return(ret);
+}
+
+
+/*
+ * desroy DSP instances
+ */
+static void
+release_dsp(dsp_t *dsp)
+{
+	mISDNinstance_t	*inst = &dsp->inst;
+	conference_t	*conf;
+	u_long		flags;
+
+	spin_lock_irqsave(&dsp_obj.lock, flags);
+	if (timer_pending(&dsp->feature_tl))
+		del_timer(&dsp->feature_tl);
+	if (timer_pending(&dsp->tone.tl))
+		del_timer(&dsp->tone.tl);
+	if (dsp_debug & DEBUG_DSP_MGR)
+		printk(KERN_DEBUG "%s: removing conferences %s\n", __FUNCTION__, dsp->inst.name);
+	conf = dsp->conf;
+	if (conf) {
+		dsp_cmx_del_conf_member(dsp);
+		if (!list_empty(&conf->mlist)) {
+			dsp_cmx_del_conf(conf);
+		}
+	}
+
+	if (dsp_debug & DEBUG_DSP_MGR)
+		printk(KERN_DEBUG "%s: remove & destroy object %s\n", __FUNCTION__, dsp->inst.name);
+	list_del(&dsp->list);
+	spin_unlock_irqrestore(&dsp_obj.lock, flags);
+	mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+	vfree(dsp);
+
+	if (dsp_debug & DEBUG_DSP_MGR)
+		printk(KERN_DEBUG "%s: dsp instance released\n", __FUNCTION__);
+}
+
+
+/*
+ * ask for hardware features
+ */
+static void
+dsp_feat(void *arg)
+{
+	dsp_t *dsp = arg;
+	struct sk_buff *nskb;
+	void *feat;
+	
+
+	switch (dsp->feature_state) {
+		case FEAT_STATE_INIT:
+			feat = &dsp->features;
+			nskb = create_link_skb(PH_CONTROL | REQUEST, HW_FEATURES, sizeof(feat), &feat, 0);
+			if (!nskb)
+				break;
+			if (mISDN_queue_down(&dsp->inst, 0, nskb)) {
+				dev_kfree_skb(nskb);
+				break;
+			}
+			if (dsp_debug & DEBUG_DSP_MGR)
+				printk(KERN_DEBUG "%s: features will be quered now for instance %s\n", __FUNCTION__, dsp->inst.name);
+			spin_lock(&dsp->feature_lock);
+			dsp->feature_state = FEAT_STATE_WAIT;
+			spin_unlock(&dsp->feature_lock);
+			init_timer(&dsp->feature_tl);
+			dsp->feature_tl.expires = jiffies + (HZ / 100);
+			add_timer(&dsp->feature_tl);
+			break;
+		case FEAT_STATE_WAIT:
+			if (dsp_debug & DEBUG_DSP_MGR)
+				printk(KERN_DEBUG "%s: features of %s are: hfc_id=%d hfc_dtmf=%d hfc_loops=%d hfc_echocanhw:%d pcm_id=%d pcm_slots=%d pcm_banks=%d\n",
+				 __FUNCTION__, dsp->inst.name,
+				 dsp->features.hfc_id,
+				 dsp->features.hfc_dtmf,
+				 dsp->features.hfc_loops,
+				 dsp->features.hfc_echocanhw,
+				 dsp->features.pcm_id,
+				 dsp->features.pcm_slots,
+				 dsp->features.pcm_banks);
+
+			spin_lock(&dsp->feature_lock);
+			dsp->feature_state = FEAT_STATE_RECEIVED;
+			spin_unlock(&dsp->feature_lock);
+
+			if (dsp->queue_conf_id) {
+				/*work on queued conf id*/
+				dsp_cmx_conf(dsp, dsp->queue_conf_id );
+				if (dsp_debug & DEBUG_DSP_CMX)
+					dsp_cmx_debug(dsp);
+			}
+
+			if (dsp->queue_cancel[2]) {
+				dsp_cancel_init(dsp, 
+						dsp->queue_cancel[0],
+						dsp->queue_cancel[1],
+						dsp->queue_cancel[2]
+					       );
+						
+			}
+			break;
+	}
+
+}
+
+
+/*
+ * create new DSP instances
+ */
+static int
+new_dsp(mISDNstack_t *st, mISDN_pid_t *pid) 
+{
+	int	err = 0;
+	dsp_t	*ndsp;
+	u_long	flags;
+
+	if (dsp_debug & DEBUG_DSP_MGR)
+		printk(KERN_DEBUG "%s: creating new dsp instance\n", __FUNCTION__);
+
+	if (!st || !pid)
+		return(-EINVAL);
+	if (!(ndsp = vmalloc(sizeof(dsp_t)))) {
+		printk(KERN_ERR "%s: vmalloc dsp_t failed\n", __FUNCTION__);
+		return(-ENOMEM);
+	}
+	memset(ndsp, 0, sizeof(dsp_t));
+	memcpy(&ndsp->inst.pid, pid, sizeof(mISDN_pid_t));
+	mISDN_init_instance(&ndsp->inst, &dsp_obj, ndsp, dsp_function);
+	if (!mISDN_SetHandledPID(&dsp_obj, &ndsp->inst.pid)) {
+		int_error();
+		err = -ENOPROTOOPT;
+		free_mem:
+		vfree(ndsp);
+		return(err);
+	}
+	sprintf(ndsp->inst.name, "DSP_S%x/C%x",
+		(st->id&0xff00)>>8, (st->id&0xff0000)>>16);
+	/* set frame size to start */
+	ndsp->features.hfc_id = -1; /* current PCM id */
+	ndsp->features.pcm_id = -1; /* current PCM id */
+	ndsp->pcm_slot_rx = -1; /* current CPM slot */
+	ndsp->pcm_slot_tx = -1;
+	ndsp->pcm_bank_rx = -1;
+	ndsp->pcm_bank_tx = -1;
+	ndsp->hfc_conf = -1; /* current conference number */
+	/* set tone timer */
+	ndsp->tone.tl.function = (void *)dsp_tone_timeout;
+	ndsp->tone.tl.data = (long) ndsp;
+	init_timer(&ndsp->tone.tl);
+	/* set dsp feture timer */
+	ndsp->feature_tl.function = (void *)dsp_feat;
+	ndsp->feature_tl.data = (long) ndsp;
+	ndsp->feature_state = FEAT_STATE_INIT;
+
+	if (dtmfthreshold < 20 || dtmfthreshold> 500) {
+		dtmfthreshold=200;
+	}
+	ndsp->dtmf.treshold=dtmfthreshold*10000;
+
+	spin_lock_init(&ndsp->feature_lock);
+	init_timer(&ndsp->feature_tl);
+	if (!(dsp_options & DSP_OPT_NOHARDWARE)) {
+		ndsp->feature_tl.expires = jiffies + (HZ / 100);
+		add_timer(&ndsp->feature_tl);
+	}
+	spin_lock_irqsave(&dsp_obj.lock, flags);
+	/* append and register */
+	list_add_tail(&ndsp->list, &dsp_obj.ilist);
+	spin_unlock_irqrestore(&dsp_obj.lock, flags);
+	err = mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &ndsp->inst);
+	if (err) {
+		printk(KERN_ERR "%s: failed to register layer %s\n", __FUNCTION__, ndsp->inst.name);
+		spin_lock_irqsave(&dsp_obj.lock, flags);
+		list_del(&ndsp->list);
+		spin_unlock_irqrestore(&dsp_obj.lock, flags);
+		goto free_mem;
+	}
+	if (dsp_debug & DEBUG_DSP_MGR)
+		printk(KERN_DEBUG "%s: dsp instance created %s\n", __FUNCTION__, ndsp->inst.name);
+	return(err);
+}
+
+
+/*
+ * manager for DSP instances
+ */
+static int
+dsp_manager(void *data, u_int prim, void *arg) {
+	mISDNinstance_t	*inst = data;
+	dsp_t		*dspl;
+	int		ret = -EINVAL;
+	u_long		flags;
+
+	if (dsp_debug & DEBUG_DSP_MGR)
+		printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n", __FUNCTION__, data, prim, arg);
+	if (!data)
+		return(ret);
+	spin_lock_irqsave(&dsp_obj.lock, flags);
+	list_for_each_entry(dspl, &dsp_obj.ilist, list) {
+		if (&dspl->inst == inst) {
+			ret = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&dsp_obj.lock, flags);
+	if (ret && (prim != (MGR_NEWLAYER | REQUEST))) {
+		printk(KERN_WARNING "%s: given instance(%p) not in ilist.\n", __FUNCTION__, data);
+		return(ret);
+	}
+
+	switch(prim) {
+	    case MGR_NEWLAYER | REQUEST:
+		ret = new_dsp(data, arg);
+		break;
+	    case MGR_SETSTACK | INDICATION:
+		break;
+#ifdef OBSOLETE
+	    case MGR_CONNECT | REQUEST:
+		ret = mISDN_ConnectIF(inst, arg);
+		break;
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+		ret = mISDN_SetIF(inst, arg, prim, dsp_from_up, dsp_from_down, dspl);
+		break;
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		ret = mISDN_DisConnectIF(inst, arg);
+		break;
+#endif
+	    case MGR_UNREGLAYER | REQUEST:
+	    case MGR_RELEASE | INDICATION:
+		if (dsp_debug & DEBUG_DSP_MGR)
+			printk(KERN_DEBUG "%s: release_dsp id %x\n", __FUNCTION__, dspl->inst.st->id);
+
+	    	release_dsp(dspl);
+	    	break;
+	    default:
+		printk(KERN_WARNING "%s: prim %x not handled\n", __FUNCTION__, prim);
+		ret = -EINVAL;
+		break;
+	}
+	return(ret);
+}
+
+
+/*
+ * initialize DSP object
+ */
+static int dsp_init(void)
+{
+	int err;
+
+	/* copy variables */
+	dsp_options = options;
+	dsp_debug = debug;
+
+	/* display revision */
+	printk(KERN_INFO "mISDN_dsp: Audio DSP  Rev. %s (debug=0x%x) EchoCancellor %s dtmfthreshold(%d)\n", mISDN_getrev(dsp_revision), debug, EC_TYPE, dtmfthreshold);
+
+	/* set packet size */
+	if (poll == 0) {
+		if (HZ == 100)
+			poll = 80;
+		else
+			poll = 64;
+	}
+
+	if (poll > MAX_POLL) {
+		printk(KERN_ERR "%s: Wrong poll value (%d), using %d.\n", __FUNCTION__, poll, MAX_POLL);
+		poll = MAX_POLL;
+	}
+	if (poll < 8) {
+		printk(KERN_ERR "%s: Wrong poll value (%d), using 8.\n", __FUNCTION__, poll);
+		poll = 8;
+	}
+	dsp_poll = poll;
+	dsp_tics = poll * HZ / 8000;
+	if (dsp_tics * 8000 == poll * HZ) 
+		printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals %d jiffies.\n", poll, dsp_tics);
+	else {
+		printk(KERN_INFO "mISDN_dsp: Cannot clock ever %d samples. Use a multiple of %d (samples)\n", poll, 8000 / HZ);
+		err = -EINVAL;
+		return(err);
+	}
+
+	/* fill mISDN object (dsp_obj) */
+	memset(&dsp_obj, 0, sizeof(dsp_obj));
+#ifdef MODULE
+	SET_MODULE_OWNER(&dsp_obj);
+#endif
+	spin_lock_init(&dsp_obj.lock);
+	dsp_obj.name = DSPName;
+	dsp_obj.BPROTO.protocol[3] = ISDN_PID_L3_B_DSP;
+	dsp_obj.own_ctrl = dsp_manager;
+	INIT_LIST_HEAD(&dsp_obj.ilist);
+
+	/* initialize audio tables */
+	dsp_silence = (dsp_options&DSP_OPT_ULAW)?0xff:0x2a;
+	dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW)?dsp_audio_ulaw_to_s32:dsp_audio_alaw_to_s32;
+	dsp_audio_generate_s2law_table();
+	dsp_audio_generate_seven();
+	dsp_audio_generate_mix_table();
+	if (dsp_options & DSP_OPT_ULAW)
+		dsp_audio_generate_ulaw_samples();
+	dsp_audio_generate_volume_changes();
+
+	/* register object */
+	if ((err = mISDN_register(&dsp_obj))) {
+		printk(KERN_ERR "mISDN_dsp: Can't register %s error(%d)\n", DSPName, err);
+		return(err);
+	}
+
+	/* set sample timer */
+	dsp_spl_tl.function = (void *)dsp_cmx_send;
+	dsp_spl_tl.data = 0;
+	init_timer(&dsp_spl_tl);
+	dsp_spl_tl.expires = jiffies + dsp_tics + 1; /* safer */
+	dsp_spl_jiffies = dsp_spl_tl.expires;
+	add_timer(&dsp_spl_tl);
+	
+	mISDN_module_register(THIS_MODULE);
+	
+	return(0);
+}
+
+
+/*
+ * cleanup DSP object during module removal
+ */
+static void dsp_cleanup(void)
+{
+	dsp_t	*dspl, *nd;	
+	int	err;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if (timer_pending(&dsp_spl_tl))
+		del_timer(&dsp_spl_tl);
+
+	if (dsp_debug & DEBUG_DSP_MGR)
+		printk(KERN_DEBUG "%s: removing module\n", __FUNCTION__);
+
+	if ((err = mISDN_unregister(&dsp_obj))) {
+		printk(KERN_ERR "mISDN_dsp: Can't unregister Audio DSP error(%d)\n", 
+			err);
+	}
+	if (!list_empty(&dsp_obj.ilist)) {
+		printk(KERN_WARNING "mISDN_dsp: Audio DSP object inst list not empty.\n");
+		list_for_each_entry_safe(dspl, nd, &dsp_obj.ilist, list)
+			release_dsp(dspl);
+	}
+	if (!list_empty(&Conf_list)) {
+		printk(KERN_ERR "mISDN_dsp: Conference list not empty. Not all memory freed.\n");
+	}
+}
+
+#ifdef MODULE
+module_init(dsp_init);
+module_exit(dsp_cleanup);
+#endif
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_dtmf.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_dtmf.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_dtmf.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,249 @@
+/* $Id: dsp_dtmf.c,v 1.7 2007/03/27 15:06:29 jolly Exp $
+ *
+ * DTMF decoder.
+ *
+ * Copyright            by Andreas Eversberg (jolly at eversberg.eu)
+ *			based on different decoders such as ISDN4Linux
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+#include "dsp.h"
+
+#define NCOEFF            8     /* number of frequencies to be analyzed */
+
+/* For DTMF recognition:
+ * 2 * cos(2 * PI * k / N) precalculated for all k
+ */
+static u64 cos2pik[NCOEFF] =
+{
+	/* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */
+	55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630
+};
+
+/* digit matrix */
+static char dtmf_matrix[4][4] =
+{
+	{'1', '2', '3', 'A'},
+	{'4', '5', '6', 'B'},
+	{'7', '8', '9', 'C'},
+	{'*', '0', '#', 'D'}
+};
+
+/* dtmf detection using goertzel algorithm
+ * init function
+ */
+void dsp_dtmf_goertzel_init(dsp_t *dsp)
+{
+	dsp->dtmf.size = 0;
+	dsp->dtmf.lastwhat = '\0';
+	dsp->dtmf.lastdigit = '\0';
+	dsp->dtmf.count = 0;
+}
+
+
+/*************************************************************
+ * calculate the coefficients of the given sample and decode *
+ *************************************************************/
+
+/* the given sample is decoded. if the sample is not long enough for a
+ * complete frame, the decoding is finished and continued with the next
+ * call of this function.
+ *
+ * the algorithm is very good for detection with a minimum of errors. i
+ * tested it allot. it even works with very short tones (40ms). the only
+ * disadvantage is, that it doesn't work good with different volumes of both
+ * tones. this will happen, if accoustically coupled dialers are used.
+ * it sometimes detects tones during speach, which is normal for decoders.
+ * use sequences to given commands during calls.
+ *
+ * dtmf - points to a structure of the current dtmf state
+ * spl and len - the sample
+ * fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder
+ */
+
+u8
+*dsp_dtmf_goertzel_decode(dsp_t *dsp, u8 *data, int len, int fmt)
+{
+	u8 what;
+	int size;
+	signed short *buf;
+	s32 sk, sk1, sk2;
+	int k, n, i;
+	s32 *hfccoeff;
+	s32 result[NCOEFF], tresh, treshl;
+	int lowgroup, highgroup;
+	s64 cos2pik_;
+
+	dsp->dtmf.digits[0] = '\0';
+
+	/* note: the function will loop until the buffer are not enough samples
+	 * left to decode a full frame
+	 */
+again:
+	/* convert samples */
+	size = dsp->dtmf.size;
+	buf = dsp->dtmf.buffer;
+	switch(fmt) {
+		case 0: /* alaw */
+		case 1: /* ulaw */
+		while(size<DSP_DTMF_NPOINTS && len) {
+			buf[size++] = dsp_audio_law_to_s32[*data++];
+			len--;
+		}
+		break;
+
+		case 2: /* HFC coefficients */
+		default:
+		if (len < 64) {
+			if (len > 0)
+				printk(KERN_ERR "%s: coefficients have invalid size. (is=%d < must=%d)\n",
+					__FUNCTION__, len, 64);
+			return(dsp->dtmf.digits);
+		}
+		hfccoeff = (s32 *)data;
+		for (k = 0; k < NCOEFF; k++) {
+			sk2 = (*hfccoeff++)>>4;
+			sk = (*hfccoeff++)>>4;
+			if (sk>32767 || sk<-32767 || sk2>32767 || sk2<-32767)
+				printk(KERN_WARNING "DTMF-Detection overflow\n");
+			/* compute |X(k)|**2 */
+			result[k] =
+				 (sk * sk) -
+				 (((cos2pik[k] * sk) >> 15) * sk2) +
+				 (sk2 * sk2);
+		}
+		data += 64;
+		len -= 64;
+		goto coefficients;
+		break;
+	}
+	dsp->dtmf.size = size;
+
+	if (size < DSP_DTMF_NPOINTS)
+		return(dsp->dtmf.digits);
+
+	dsp->dtmf.size = 0;
+
+	/* now we have a full buffer of signed long samples - we do goertzel */
+	for (k = 0; k < NCOEFF; k++) {
+		sk = sk1 = sk2 = 0;
+		buf = dsp->dtmf.buffer;
+		cos2pik_ = cos2pik[k];
+		for (n = 0; n < DSP_DTMF_NPOINTS; n++) {
+			sk = ((cos2pik_*sk1)>>15) - sk2 + (*buf++);
+			sk2 = sk1;
+			sk1 = sk;
+		}
+		sk>>=8;
+		sk2>>=8;
+		if (sk>32767 || sk<-32767 || sk2>32767 || sk2<-32767)
+			printk(KERN_WARNING "DTMF-Detection overflow\n");
+		/* compute |X(k)|**2 */
+		result[k] =
+		   	 (sk * sk) -
+		   	 (((cos2pik[k] * sk) >> 15) * sk2) +
+		   	 (sk2 * sk2);
+	}
+
+	/* our (squared) coefficients have been calculated, we need to process
+	 * them.
+	 */
+	coefficients:
+	tresh = 0;
+	for (i = 0; i < NCOEFF; i++) {
+		if (result[i] < 0)
+			result[i] = 0;
+		if (result[i] > dsp->dtmf.treshold) {
+			if (result[i] > tresh)
+				tresh = result[i];
+		}
+	}
+
+	if (tresh == 0) {
+		what = 0;
+		goto storedigit;
+	}
+
+	if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
+		printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d"
+			" tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n",
+			result[0]/10000, result[1]/10000, result[2]/10000,
+			result[3]/10000, result[4]/10000, result[5]/10000,
+			result[6]/10000, result[7]/10000, tresh/10000,
+			result[0]/(tresh/100), result[1]/(tresh/100),
+			result[2]/(tresh/100), result[3]/(tresh/100),
+			result[4]/(tresh/100), result[5]/(tresh/100),
+			result[6]/(tresh/100), result[7]/(tresh/100));
+
+	/* calc digit (lowgroup/highgroup) */
+	lowgroup = highgroup = -1;
+	treshl = tresh >> 3;  /* tones which are not on, must be below 9 dB */
+	tresh = tresh >> 2;  /* touchtones must match within 6 dB */
+	for (i = 0; i < NCOEFF; i++) {
+		if (result[i] < treshl)
+			continue;  /* ignore */
+		if (result[i] < tresh) {
+			lowgroup = highgroup = -1;
+			break;  /* noise inbetween */
+		}
+		/* good level found. This is allowed only one time per group */
+		if (i < NCOEFF/2) {
+			/* lowgroup*/
+			if (lowgroup >= 0) {
+				// Bad. Another tone found. */
+				lowgroup = -1;
+				break;
+			} else
+				lowgroup = i;
+		} else {
+			/* higroup */
+			if (highgroup >= 0) {
+				// Bad. Another tone found. */
+				highgroup = -1;
+				break;
+			} else
+				highgroup = i-(NCOEFF/2);
+		}
+	}
+
+	/* get digit or null */
+	what = 0;
+	if (lowgroup>=0 && highgroup>=0)
+		what = dtmf_matrix[lowgroup][highgroup];
+
+storedigit:
+	if (what && (dsp_debug & DEBUG_DSP_DTMF))
+		printk(KERN_DEBUG "DTMF what: %c\n", what);
+
+	if (dsp->dtmf.lastwhat!=what)
+		dsp->dtmf.count = 0;
+
+	/* the tone (or no tone) must remain 3 times without change */
+	if (dsp->dtmf.count == 2) {
+		if (dsp->dtmf.lastdigit!=what) {
+			dsp->dtmf.lastdigit = what;
+			if (what) {
+				if (dsp_debug & DEBUG_DSP_DTMF)
+					printk(KERN_DEBUG "DTMF digit: %c\n",
+						what);
+				if ((strlen(dsp->dtmf.digits)+1) <sizeof(dsp->dtmf.digits)) {
+					dsp->dtmf.digits[strlen(dsp->dtmf.digits)+1] = '\0';
+					dsp->dtmf.digits[strlen(dsp->dtmf.digits)] = what;
+				}
+			}
+		}
+	} else
+		dsp->dtmf.count++;
+
+	dsp->dtmf.lastwhat = what;
+
+	goto again;
+}
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_ecdis.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_ecdis.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_ecdis.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,118 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * ec_disable_detector.h - A detector which should eventually meet the
+ *                         G.164/G.165 requirements for detecting the
+ *                         2100Hz echo cancellor disable tone.
+ *
+ * Written by Steve Underwood <steveu at coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * 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 of the License, 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.
+ *
+ */
+
+#include "dsp_biquad.h"
+
+typedef struct
+{
+    biquad2_state_t notch;
+    int notch_level;
+    int channel_level;
+    int tone_present;
+    int tone_cycle_duration;
+    int good_cycles;
+    int hit;
+} echo_can_disable_detector_state_t;
+
+
+#define FALSE 0
+#define TRUE (!FALSE)
+
+static inline void echo_can_disable_detector_init (echo_can_disable_detector_state_t *det)
+{
+    /* Elliptic notch */
+    /* This is actually centred at 2095Hz, but gets the balance we want, due
+       to the asymmetric walls of the notch */
+    biquad2_init (&det->notch,
+    	     	  (int32_t) (-0.7600000*32768.0),
+    	    	  (int32_t) (-0.1183852*32768.0),
+    	    	  (int32_t) (-0.5104039*32768.0),
+    	    	  (int32_t) ( 0.1567596*32768.0),
+    	    	  (int32_t) ( 1.0000000*32768.0));
+
+    det->channel_level = 0;
+    det->notch_level = 0;    
+    det->tone_present = FALSE;
+    det->tone_cycle_duration = 0;
+    det->good_cycles = 0;
+    det->hit = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline int echo_can_disable_detector_update (echo_can_disable_detector_state_t *det,
+                                      int16_t amp)
+{
+    int16_t notched;
+    
+    	notched = biquad2 (&det->notch, amp);
+    	/* Estimate the overall energy in the channel, and the energy in
+	   the notch (i.e. overall channel energy - tone energy => noise).
+	   Use abs instead of multiply for speed (is it really faster?).
+	   Damp the overall energy a little more for a stable result.
+	   Damp the notch energy a little less, so we don't damp out the
+	   blip every time the phase reverses */
+        det->channel_level += ((abs(amp) - det->channel_level) >> 5);
+	det->notch_level += ((abs(notched) - det->notch_level) >> 4);
+  	if (det->channel_level > 280)
+	{
+	    /* There is adequate energy in the channel. Is it mostly at 2100Hz? */
+	    if (det->notch_level*6 < det->channel_level)
+	    {
+                /* The notch says yes, so we have the tone. */
+		if (!det->tone_present)
+		{
+                    /* Do we get a kick every 450+-25ms? */
+		    if (det->tone_cycle_duration >= 425*8
+			&&
+			det->tone_cycle_duration <= 475*8)
+	            {
+			det->good_cycles++;
+			if (det->good_cycles > 2)
+			    det->hit = TRUE;
+		    }
+		    det->tone_cycle_duration = 0;
+		}
+		det->tone_present = TRUE;
+	    }
+	    else
+	    {
+		det->tone_present = FALSE;
+	    }
+   	    det->tone_cycle_duration++;
+	}
+	else
+	{
+	    det->tone_present = FALSE;
+	    det->tone_cycle_duration = 0;
+	    det->good_cycles = 0;
+	}
+    return  det->hit;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_kb1ec.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_kb1ec.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_kb1ec.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,574 @@
+/*
+ * ECHO_CAN_KB1
+ *
+ * by Kris Boutilier
+ *
+ * Based upon mech2.h
+ * 
+ * Copyright (C) 2002, Digium, Inc.
+ *
+ * This program is free software and may be used and
+ * distributed according to the terms of the GNU
+ * General Public License, incorporated herein by
+ * reference.
+ *
+ * Additional background on the techniques used in this code can be found in:
+ *
+ *  Messerschmitt, David; Hedberg, David; Cole, Christopher; Haoui, Amine; 
+ *  Winship, Peter; "Digital Voice Echo Canceller with a TMS32020," 
+ *  in Digital Signal Processing Applications with the TMS320 Family, 
+ *  pp. 415-437, Texas Instruments, Inc., 1986. 
+ *
+ * A pdf of which is available by searching on the document title at http://www.ti.com/
+ *
+ */
+
+#ifndef _MARK2_ECHO_H
+#define _MARK2_ECHO_H
+
+#define EC_TYPE "KB1"
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#define MALLOC(a) kmalloc((a), GFP_ATOMIC)
+#define FREE(a) kfree(a)
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#define MALLOC(a) malloc(a)
+#define FREE(a) free(a)
+#endif
+
+/* Uncomment to provide summary statistics for overall echo can performance every 4000 samples */ 
+/* #define MEC2_STATS 4000 */
+
+/* Uncomment to generate per-sample statistics - this will severely degrade system performance and audio quality */
+/* #define MEC2_STATS_DETAILED */
+
+/* Get optimized routines for math */
+#include "dsp_arith.h"
+
+/* Bring in definitions for the various constants and thresholds */
+#include "dsp_kb1ec_const.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+/* Generic circular buffer definition */
+typedef struct {
+	/* Pointer to the relative 'start' of the buffer */
+	int idx_d;
+	/* The absolute size of the buffer */
+	int size_d;			 
+	/* The actual sample -  twice as large as we need, however we do store values at idx_d and idx_d+size_d */
+	short *buf_d;			
+} echo_can_cb_s;
+
+/* Echo canceller definition */
+struct echo_can_state {
+	/* an arbitrary ID for this echo can - this really should be settable from the calling channel... */
+	int id;
+
+	/* absolute time - aka. sample number index - essentially the number of samples since this can was init'ed */
+	int i_d;
+  
+	/* Pre-computed constants */
+	/* ---------------------- */
+	/* Number of filter coefficents */
+	int N_d;
+	/* Rate of adaptation of filter */
+	int beta2_i;
+
+	/* Accumulators for power computations */
+	/* ----------------------------------- */
+	/* reference signal power estimate - aka. Average absolute value of y(k) */
+	int Ly_i;			
+	/* ... */
+	int Lu_i;
+
+	/* Accumulators for signal detectors */
+	/* --------------------------------- */
+	/* Power estimate of the recent past of the near-end hybrid signal - aka. Short-time average of: 2 x |s(i)| */
+	int s_tilde_i;		
+	/* Power estimate of the recent past of the far-end receive signal - aka. Short-time average of:     |y(i)| */
+	int y_tilde_i;
+
+	/* Near end speech detection counter - stores Hangover counter time remaining, in samples */
+	int HCNTR_d;			
+  
+	/* Circular buffers and coefficients */
+	/* --------------------------------- */
+	/* ... */
+	int *a_i;
+	/* ... */
+	short *a_s;
+	/* Reference samples of far-end receive signal */
+	echo_can_cb_s y_s;
+	/* Reference samples of near-end signal */
+	echo_can_cb_s s_s;
+	/* Reference samples of near-end signal minus echo estimate */
+	echo_can_cb_s u_s;
+	/* Reference samples of far-end receive signal used to calculate short-time average */
+	echo_can_cb_s y_tilde_s;
+
+	/* Peak far-end receive signal */
+	/* --------------------------- */
+	/* Highest y_tilde value in the sample buffer */
+	short max_y_tilde;
+	/* Index of the sample containing the max_y_tilde value */
+	int max_y_tilde_pos;
+
+#ifdef MEC2_STATS
+	/* Storage for performance statistics */
+	int cntr_nearend_speech_frames;
+	int cntr_residualcorrected_frames;
+	int cntr_residualcorrected_framesskipped;
+	int cntr_coeff_updates;
+	int cntr_coeff_missedupdates;
+ 
+	int avg_Lu_i_toolow; 
+	int avg_Lu_i_ok;
+#endif 
+
+};
+
+static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
+{
+	cb->buf_d = (short *)where;
+	cb->idx_d = 0;
+	cb->size_d = len;
+}
+
+static inline void add_cc_s(echo_can_cb_s *cb, short newval)
+{
+	/* Can't use modulus because N+M isn't a power of two (generally) */
+	cb->idx_d--;
+	if (cb->idx_d < (int)0) 
+		/* Whoops - the pointer to the 'start' wrapped around so reset it to the top of the buffer */
+	 	cb->idx_d += cb->size_d;
+  	
+	/* Load two copies into memory */
+	cb->buf_d[cb->idx_d] = newval;
+	cb->buf_d[cb->idx_d + cb->size_d] = newval;
+}
+
+static inline short get_cc_s(echo_can_cb_s *cb, int pos)
+{
+	/* Load two copies into memory */
+	return cb->buf_d[cb->idx_d + pos];
+}
+
+static inline void init_cc(struct echo_can_state *ec, int N, int maxy, int maxu) 
+{
+
+	void *ptr = ec;
+	unsigned long tmp;
+	/* Double-word align past end of state */
+	ptr += sizeof(struct echo_can_state);
+	tmp = (unsigned long)ptr;
+	tmp += 3;
+	tmp &= ~3L;
+	ptr = (void *)tmp;
+
+	/* Reset parameters */
+	ec->N_d = N;
+	ec->beta2_i = DEFAULT_BETA1_I;
+  
+	/* Allocate coefficient memory */
+	ec->a_i = ptr;
+	ptr += (sizeof(int) * ec->N_d);
+	ec->a_s = ptr;
+	ptr += (sizeof(short) * ec->N_d);
+
+	/* Reset Y circular buffer (short version) */
+	init_cb_s(&ec->y_s, maxy, ptr);
+	ptr += (sizeof(short) * (maxy) * 2);
+  
+	/* Reset Sigma circular buffer (short version for FIR filter) */
+	init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
+	ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
+
+	init_cb_s(&ec->u_s, maxu, ptr);
+	ptr += (sizeof(short) * maxu * 2);
+
+	/* Allocate a buffer for the reference signal power computation */
+	init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
+
+	/* Reset the absolute time index */
+	ec->i_d = (int)0;
+  
+	/* Reset the power computations (for y and u) */
+	ec->Ly_i = DEFAULT_CUTOFF_I;
+	ec->Lu_i = DEFAULT_CUTOFF_I;
+
+#ifdef MEC2_STATS
+	/* set the identity */
+	ec->id = (int)&ptr;
+  
+	/* Reset performance stats */
+	ec->cntr_nearend_speech_frames = (int)0;
+	ec->cntr_residualcorrected_frames = (int)0;
+	ec->cntr_residualcorrected_framesskipped = (int)0;
+	ec->cntr_coeff_updates = (int)0;
+	ec->cntr_coeff_missedupdates = (int)0;
+
+	ec->avg_Lu_i_toolow = (int)0;
+	ec->avg_Lu_i_ok = (int)0;
+#endif
+
+	/* Reset the near-end speech detector */
+	ec->s_tilde_i = (int)0;
+	ec->y_tilde_i = (int)0;
+	ec->HCNTR_d = (int)0;
+
+}
+
+static inline void echo_can_free(struct echo_can_state *ec)
+{
+	FREE(ec);
+}
+
+static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig) 
+{
+
+	/* Declare local variables that are used more than once */
+	/* ... */
+	int k;
+	/* ... */
+	int rs;
+	/* ... */
+	short u;
+	/* ... */
+	int Py_i;
+	/* ... */
+	int two_beta_i;
+	
+	/* flow A on pg. 428 */
+	/* eq. (16): high-pass filter the input to generate the next value;
+	 *           push the current value into the circular buffer
+	 *
+	 * sdc_im1_d = sdc_d;
+	 *     sdc_d = sig;
+	 *     s_i_d = sdc_d;
+	 *       s_d = s_i_d;
+	 *     s_i_d = (float)(1.0 - gamma_d) * s_i_d
+	 *	+ (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); 
+	 */
+
+	/* Update the Far-end receive signal circular buffers and accumulators */
+	/* ------------------------------------------------------------------- */
+	/* Delete the oldest sample from the power estimate accumulator */
+	ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
+	/* Add the new sample to the power estimate accumulator */
+	ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_ST_I;
+	/* Push a copy of the new sample into its circular buffer */
+	add_cc_s(&ec->y_s, iref);
+ 
+
+	/* eq. (2): compute r in fixed-point */
+	rs = CONVOLVE2(ec->a_s, 
+  			ec->y_s.buf_d + ec->y_s.idx_d, 
+  			ec->N_d);
+	rs >>= 15;
+
+	/* eq. (3): compute the output value (see figure 3) and the error
+	 * note: the error is the same as the output signal when near-end
+	 * speech is not present
+	 */
+	u = isig - rs;
+  
+	/* Push a copy of the output value sample into its circular buffer */
+	add_cc_s(&ec->u_s, u);
+
+
+	/* Update the Near-end hybrid signal circular buffers and accumulators */
+	/* ------------------------------------------------------------------- */
+	/* Delete the oldest sample from the power estimate accumulator */
+	ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
+	/* Add the new sample to the power estimate accumulator */
+	ec->s_tilde_i += abs(isig);
+	/* Push a copy of the new sample into it's circular buffer */
+	add_cc_s(&ec->s_s, isig);
+
+
+	/* Push a copy of the current short-time average of the far-end receive signal into it's circular buffer */
+	add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);		
+
+	/* flow B on pg. 428 */
+  
+	/* If the hangover timer isn't running then compute the new convergence factor, otherwise set Py_i to 32768 */
+	if (!ec->HCNTR_d) {
+		Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
+		Py_i >>= 15;
+	} else {
+	  	Py_i = (1 << 15);
+	}
+  
+#if 0
+	/* Vary rate of adaptation depending on position in the file
+	 *  Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
+	 *  has begun of the file to allow the echo cancellor to estimate the
+	 *  channel accurately
+	 * Still needs conversion!
+	 */
+
+	if (ec->start_speech_d != 0 ){
+		if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
+			ec->beta2_d = max_cc_float(MIN_BETA, DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) - DEFAULT_T0 - ec->start_speech_d)));
+		}
+	} else {
+		ec->beta2_d = DEFAULT_BETA1;
+	}
+#endif
+  
+	/* Fixed point, inverted */
+	ec->beta2_i = DEFAULT_BETA1_I;	
+  
+	/* Fixed point version, inverted */
+	two_beta_i = (ec->beta2_i * Py_i) >> 15;	
+	if (!two_beta_i)
+		two_beta_i++;
+
+	/* Update the Suppressed signal power estimate accumulator */
+        /* ------------------------------------------------------- */
+        /* Delete the oldest sample from the power estimate accumulator */
+	ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
+        /* Add the new sample to the power estimate accumulator */
+	ec->Lu_i += abs(u);
+
+	/* Update the Far-end reference signal power estimate accumulator */
+        /* -------------------------------------------------------------- */
+	/* eq. (10): update power estimate of the reference */
+        /* Delete the oldest sample from the power estimate accumulator */
+	ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
+        /* Add the new sample to the power estimate accumulator */
+	ec->Ly_i += abs(iref);
+
+	if (ec->Ly_i < DEFAULT_CUTOFF_I)
+		ec->Ly_i = DEFAULT_CUTOFF_I;
+
+
+	/* Update the Peak far-end receive signal detected */
+        /* ----------------------------------------------- */
+	if (ec->y_tilde_i > ec->max_y_tilde) {
+		/* New highest y_tilde with full life */
+		ec->max_y_tilde = ec->y_tilde_i;
+		ec->max_y_tilde_pos = ec->N_d - 1;
+	} else if (--ec->max_y_tilde_pos < 0) {
+		/* Time to find new max y tilde... */
+		ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos);
+	}
+
+	/* Determine if near end speech was detected in this sample */
+	/* -------------------------------------------------------- */
+	if (((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde) 
+	    && (ec->max_y_tilde > 0))  {
+		/* Then start the Hangover counter */
+		ec->HCNTR_d = DEFAULT_HANGT;
+#ifdef MEC2_STATS_DETAILED
+		printk(KERN_INFO "Reset near end speech timer with: s_tilde_i %d, stmnt %d, max_y_tilde %d\n", ec->s_tilde_i, (ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)), ec->max_y_tilde);
+#endif
+#ifdef MEC2_STATS
+		++ec->cntr_nearend_speech_frames;
+#endif
+	} else if (ec->HCNTR_d > (int)0) {
+  		/* otherwise, if it's still non-zero, decrement the Hangover counter by one sample */
+#ifdef MEC2_STATS
+		++ec->cntr_nearend_speech_frames;
+#endif
+		ec->HCNTR_d--;
+	} 
+
+	/* Update coefficients if no near-end speech in this sample (ie. HCNTR_d = 0)
+	 * and we have enough signal to bother trying to update.
+	 * --------------------------------------------------------------------------
+	 */
+	if (!ec->HCNTR_d && 				/* no near-end speech present */
+		!(ec->i_d % DEFAULT_M)) {		/* we only update on every DEFAULM_M'th sample from the stream */
+  			if (ec->Lu_i > MIN_UPDATE_THRESH_I) {	/* there is sufficient energy above the noise floor to contain meaningful data */
+  							/* so loop over all the filter coefficients */
+#ifdef MEC2_STATS_DETAILED
+				printk( KERN_INFO "updating coefficients with: ec->Lu_i %9d\n", ec->Lu_i);
+#endif
+#ifdef MEC2_STATS
+				ec->avg_Lu_i_ok = ec->avg_Lu_i_ok + ec->Lu_i;  
+				++ec->cntr_coeff_updates;
+#endif
+				for (k=0; k < ec->N_d; k++) {
+					/* eq. (7): compute an expectation over M_d samples */
+					int grad2;
+					grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
+							  ec->y_s.buf_d + ec->y_s.idx_d + k,
+							  DEFAULT_M);
+					/* eq. (7): update the coefficient */
+					ec->a_i[k] += grad2 / two_beta_i;
+					ec->a_s[k] = ec->a_i[k] >> 16;
+				}
+		 	 } else { 
+#ifdef MEC2_STATS_DETAILED
+				printk( KERN_INFO "insufficient signal to update coefficients ec->Lu_i %5d < %5d\n", ec->Lu_i, MIN_UPDATE_THRESH_I);
+#endif
+#ifdef MEC2_STATS
+				ec->avg_Lu_i_toolow = ec->avg_Lu_i_toolow + ec->Lu_i;  
+				++ec->cntr_coeff_missedupdates;
+#endif
+			}
+	}
+  
+	/* paragraph below eq. (15): if no near-end speech in the sample and 
+	 * the reference signal power estimate > cutoff threshold
+	 * then perform residual error suppression
+	 */
+#ifdef MEC2_STATS_DETAILED
+	if (ec->HCNTR_d == 0)
+		printk( KERN_INFO "possibily correcting frame with ec->Ly_i %9d ec->Lu_i %9d and expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+
+#ifndef NO_ECHO_SUPPRESSOR
+#ifdef AGGRESSIVE_SUPPRESSOR
+	if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
+		for (k=0; k < RESIDUAL_SUPRESSION_PASSES; k++) {
+			u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
+		}
+#ifdef MEC2_STATS_DETAILED
+		printk( KERN_INFO "aggresively correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+#ifdef MEC2_STATS
+		++ec->cntr_residualcorrected_frames;
+#endif
+	}
+#else
+	if (ec->HCNTR_d == 0) { 
+		if ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I) {
+			for (k=0; k < RESIDUAL_SUPRESSION_PASSES; k++) {
+	  			u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
+			}
+#ifdef MEC2_STATS_DETAILED
+			printk( KERN_INFO "correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+#ifdef MEC2_STATS
+		  	++ec->cntr_residualcorrected_frames;
+#endif
+		}
+#ifdef MEC2_STATS
+		else {
+       			++ec->cntr_residualcorrected_framesskipped;
+		}
+#endif
+	}
+#endif	
+#endif  
+
+#if 0
+	/* This will generate a non-linear supression factor, once converted */
+	if ((ec->HCNTR_d == 0) && 
+	   ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
+	    (ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) { 
+	    	suppr_factor = (10 / (float)(SUPPR_FLOOR - SUPPR_CEIL)) * log(ec->Lu_d/ec->Ly_d)
+	    			- SUPPR_CEIL / (float)(SUPPR_FLOOR - SUPPR_CEIL);
+		u_suppr = pow(10.0, (suppr_factor) * RES_SUPR_FACTOR / 10.0) * u_suppr;
+	}
+#endif  
+
+#ifdef MEC2_STATS
+	/* Periodically dump performance stats */
+	if ((ec->i_d % MEC2_STATS) == 0) {
+		/* make sure to avoid div0's! */
+		if (ec->cntr_coeff_missedupdates > 0)
+			ec->avg_Lu_i_toolow = (int)(ec->avg_Lu_i_toolow / ec->cntr_coeff_missedupdates);
+		else
+			ec->avg_Lu_i_toolow = -1;
+
+		if (ec->cntr_coeff_updates > 0)
+			ec->avg_Lu_i_ok = (ec->avg_Lu_i_ok / ec->cntr_coeff_updates);
+		else
+			ec->avg_Lu_i_ok = -1;
+
+		printk( KERN_INFO "%d: Near end speech: %5d Residuals corrected/skipped: %5d/%5d Coefficients updated ok/low sig: %3d/%3d Lu_i avg ok/low sig %6d/%5d\n", 
+			ec->id,
+			ec->cntr_nearend_speech_frames, 
+			ec->cntr_residualcorrected_frames, ec->cntr_residualcorrected_framesskipped, 
+			ec->cntr_coeff_updates, ec->cntr_coeff_missedupdates, 
+			ec->avg_Lu_i_ok, ec->avg_Lu_i_toolow);
+
+		ec->cntr_nearend_speech_frames = 0;
+		ec->cntr_residualcorrected_frames = 0;
+		ec->cntr_residualcorrected_framesskipped = 0;
+		ec->cntr_coeff_updates = 0;
+		ec->cntr_coeff_missedupdates = 0;
+		ec->avg_Lu_i_ok = 0;
+		ec->avg_Lu_i_toolow = 0;
+	}
+#endif
+
+	/* Increment the sample index and return the corrected sample */
+	ec->i_d++;
+	return u;
+}
+
+static inline struct echo_can_state *echo_can_create(int len, int adaption_mode)
+{
+	struct echo_can_state *ec;
+	int maxy;
+	int maxu;
+	maxy = len + DEFAULT_M;
+	maxu = DEFAULT_M;
+	if (maxy < (1 << DEFAULT_ALPHA_YT_I))
+		maxy = (1 << DEFAULT_ALPHA_YT_I);
+	if (maxy < (1 << DEFAULT_SIGMA_LY_I))
+		maxy = (1 << DEFAULT_SIGMA_LY_I);
+	if (maxu < (1 << DEFAULT_SIGMA_LU_I))
+		maxu = (1 << DEFAULT_SIGMA_LU_I);
+	ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) +
+									4 + 						/* align */
+									sizeof(int) * len +			/* a_i */
+									sizeof(short) * len + 		/* a_s */
+									2 * sizeof(short) * (maxy) +	/* y_s */
+									2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
+									2 * sizeof(short) * (maxu) +		/* u_s */
+									2 * sizeof(short) * len);			/* y_tilde_s */
+	if (ec) {
+		memset(ec, 0, sizeof(struct echo_can_state) +
+									4 + 						/* align */
+									sizeof(int) * len +			/* a_i */
+									sizeof(short) * len + 		/* a_s */
+									2 * sizeof(short) * (maxy) +	/* y_s */
+									2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
+									2 * sizeof(short) * (maxu) +		/* u_s */
+									2 * sizeof(short) * len);			/* y_tilde_s */
+	  init_cc(ec, len, maxy, maxu);
+	}
+	return ec;
+}
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+	/* Set the hangover counter to the length of the can to 
+	 * avoid adjustments occuring immediately after initial forced training 
+	 */
+	ec->HCNTR_d = ec->N_d << 1;
+
+	if (pos >= ec->N_d)
+		return 1;
+
+	ec->a_i[pos] = val << 17;
+	ec->a_s[pos] = val << 1;
+
+	if (++pos >= ec->N_d)
+		return 1;
+
+	return 0;
+}
+
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_kb1ec_const.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_kb1ec_const.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_kb1ec_const.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,81 @@
+/* 
+   Important constants for tuning kb1 echo can
+ */
+#ifndef _MEC2_CONST_H
+#define _MEC2_CONST_H
+
+
+/* Convergence (aka. adaptation) speed -- higher means slower */
+#define DEFAULT_BETA1_I 2048
+
+/* Constants for various power computations */
+#define DEFAULT_SIGMA_LY_I 7
+#define DEFAULT_SIGMA_LU_I 7
+#define DEFAULT_ALPHA_ST_I 5 		/* near-end speech detection sensitivity factor */
+#define DEFAULT_ALPHA_YT_I 5
+
+#define DEFAULT_CUTOFF_I 128
+
+/* Define the near-end speech hangover counter: if near-end speech 
+ *  is declared, hcntr is set equal to hangt (see pg. 432)
+ */
+#define DEFAULT_HANGT 600  		/* in samples, so 600 samples = 75ms */
+
+/* define the residual error suppression threshold */
+#define DEFAULT_SUPPR_I 16		/* 16 = -24db */
+
+/* This is the minimum reference signal power estimate level 
+ *  that will result in filter adaptation.
+ * If this is too low then background noise will cause the filter 
+ *  coefficients to constantly be updated.
+ */
+#define MIN_UPDATE_THRESH_I 4096
+
+/* The number of samples used to update coefficients using the
+ *  the block update method (M). It should be related back to the 
+ *  length of the echo can.
+ * ie. it only updates coefficients when (sample number MOD default_m) = 0
+ *
+ *  Getting this wrong may cause an oops. Consider yourself warned!
+ */
+#define DEFAULT_M 16		  	/* every 16th sample */
+
+/* If AGGRESSIVE supression is enabled, then we start cancelling residual 
+ * echos again even while there is potentially the very end of a near-side 
+ *  signal present.
+ * This defines how many samples of DEFAULT_HANGT can remain before we
+ *  kick back in
+ */
+#define AGGRESSIVE_HCNTR 160		/* in samples, so 160 samples = 20ms */
+
+/* This knob controls the number of passes the residual echo supression 
+ * algorithm makes.
+ */
+#ifdef AGGRESSIVE_SUPPRESSOR
+ #define RESIDUAL_SUPRESSION_PASSES 2
+#else
+ #define RESIDUAL_SUPRESSION_PASSES 1
+#endif
+
+
+/***************************************************************/
+/* The following knobs are not implemented in the current code */
+
+/* we need a dynamic level of suppression varying with the ratio of the 
+   power of the echo to the power of the reference signal this is 
+   done so that we have a  smoother background. 		
+   we have a higher suppression when the power ratio is closer to
+   suppr_ceil and reduces logarithmically as we approach suppr_floor.
+ */
+#define SUPPR_FLOOR -64
+#define SUPPR_CEIL -24
+
+/* in a second departure, we calculate the residual error suppression
+ * as a percentage of the reference signal energy level. The threshold
+ * is defined in terms of dB below the reference signal.
+ */
+#define RES_SUPR_FACTOR -20
+
+
+#endif /* _MEC2_CONST_H */
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mec2.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mec2.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mec2.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,424 @@
+/*
+ * Mark's Second Echo Canceller
+ * 
+ * Copyright (C) 2002, Digium, Inc.
+ *
+ * This program is free software and may be used and
+ * distributed according to the terms of the GNU
+ * General Public License, incorporated herein by
+ * reference.
+ *
+ */
+#ifndef _MARK2_ECHO_H
+#define _MARK2_ECHO_H
+
+#define EC_TYPE "MARK2" 
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#define MALLOC(a) kmalloc((a), GFP_ATOMIC)
+#define FREE(a) kfree(a)
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#define MALLOC(a) malloc(a)
+#define FREE(a) free(a)
+#endif
+
+/* Get optimized routines for math */
+#include "dsp_arith.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#include "dsp_mec2_const.h"
+
+/* Circular buffer definition */
+typedef struct {
+  int idx_d;
+  int size_d;
+  short *buf_d;	/* Twice as large as we need */
+} echo_can_cb_s;
+
+// class definition
+//
+struct echo_can_state {
+  /* Echo canceller definition */
+
+  /* absolute time */
+  int i_d;
+  
+  /* pre-computed constants */
+
+  int N_d;
+  int beta2_i;
+
+  // declare accumulators for power computations
+  //
+  int Ly_i;
+  int Lu_i;
+
+  // declare an accumulator for the near-end signal detector
+  //
+  int s_tilde_i;
+  int HCNTR_d;
+
+  // circular buffers and coefficients
+  //
+  int *a_i;
+  short *a_s;
+  echo_can_cb_s y_s;
+  echo_can_cb_s s_s;
+  echo_can_cb_s u_s;
+  echo_can_cb_s y_tilde_s;
+  int y_tilde_i;
+
+  /* Max memory */
+  short max_y_tilde;
+  int max_y_tilde_pos;
+
+};
+
+static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
+{
+	cb->buf_d = (short *)where;
+	cb->idx_d = 0;
+	cb->size_d = len;
+}
+
+static inline void add_cc_s(echo_can_cb_s *cb, short newval)
+{
+    /* Can't use modulus because N+M isn't a power of two (generally) */
+    cb->idx_d--;
+    if (cb->idx_d < (int)0)
+     {cb->idx_d += cb->size_d;}
+	/* Load two copies into memory */
+	cb->buf_d[cb->idx_d] = newval;
+	cb->buf_d[cb->idx_d + cb->size_d] = newval;
+}
+
+static inline short get_cc_s(echo_can_cb_s *cb, int pos)
+{
+	/* Load two copies into memory */
+	return cb->buf_d[cb->idx_d + pos];
+}
+
+static inline void init_cc(struct echo_can_state *ec, int N, int maxy, int maxu) {
+
+  void *ptr = ec;
+  unsigned long tmp;
+  /* double-word align past end of state */
+  ptr += sizeof(struct echo_can_state);
+  tmp = (unsigned long)ptr;
+  tmp += 3;
+  tmp &= ~3L;
+  ptr = (void *)tmp;
+  
+  // reset parameters
+  //
+  ec->N_d = N;
+  ec->beta2_i = DEFAULT_BETA1_I;
+  
+  // allocate coefficient memory
+  //
+  ec->a_i = ptr;
+  ptr += (sizeof(int) * ec->N_d);
+  ec->a_s = ptr;
+  ptr += (sizeof(short) * ec->N_d);
+
+  /* Reset Y circular buffer (short version) */
+  init_cb_s(&ec->y_s, maxy, ptr);
+  ptr += (sizeof(short) * (maxy) * 2);
+  
+  /* Reset Sig circular buffer (short version for FIR filter) */
+  init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
+  ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
+
+  init_cb_s(&ec->u_s, maxu, ptr);
+  ptr += (sizeof(short) * maxu * 2);
+
+  // allocate a buffer for the reference signal power computation
+  //
+  init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
+
+
+  // reset absolute time
+  //
+  ec->i_d = (int)0;
+  
+  // reset the power computations (for y and u)
+  //
+  ec->Ly_i = DEFAULT_CUTOFF_I;
+  ec->Lu_i = DEFAULT_CUTOFF_I;
+
+  // reset the near-end speech detector
+  //
+  ec->s_tilde_i = 0;
+  ec->y_tilde_i = 0;
+  ec->HCNTR_d = (int)0;
+
+  // exit gracefully
+  //
+}
+
+static inline void echo_can_free(struct echo_can_state *ec)
+{
+	FREE(ec);
+}
+
+static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig) {
+
+  /* declare local variables that are used more than once
+  */
+  int k;
+  int rs;
+  short u;
+  int Py_i;
+  int two_beta_i;
+  
+  /***************************************************************************
+  //
+  // flow A on pg. 428
+  //
+   ***************************************************************************/
+
+  /* eq. (16): high-pass filter the input to generate the next value;
+  //           push the current value into the circular buffer
+  //
+  // sdc_im1_d = sdc_d;
+  // sdc_d = sig;
+  //  s_i_d = sdc_d;
+  //  s_d = s_i_d;
+  //  s_i_d = (float)(1.0 - gamma_d) * s_i_d
+     + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); */
+  
+  
+  /* Delete last sample from power estimate */
+  ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
+  /* push the reference data onto the circular buffer */
+  add_cc_s(&ec->y_s, iref);
+ 
+  /* eq. (2): compute r in fixed-point */
+  rs = CONVOLVE2(ec->a_s, ec->y_s.buf_d + ec->y_s.idx_d, ec->N_d);
+  rs >>= 15;
+
+  /* eq. (3): compute the output value (see figure 3) and the error
+  // note: the error is the same as the output signal when near-end
+  // speech is not present
+  */
+  u = isig - rs;  
+  
+  add_cc_s(&ec->u_s, u);
+  
+
+
+  /* Delete oldest part of received s_tilde */
+  ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
+
+  /* push the signal on the circular buffer, too */
+  add_cc_s(&ec->s_s, isig);
+  ec->s_tilde_i += abs(isig);
+  ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_YT_I;
+
+  /* Add to our list of recent y_tilde's */
+  add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);		
+
+  /****************************************************************************
+  //
+  // flow B on pg. 428
+  // 
+   ****************************************************************************/
+  
+  /* compute the new convergence factor
+  */
+  if (!ec->HCNTR_d) {
+  	Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
+  	Py_i >>= 15;
+  } else {
+  	Py_i = (1 << 15);
+  }
+  
+#if 0
+  printf("Py: %e, Py_i: %e\n", Py, Py_i * AMPL_SCALE_1);
+#endif  
+
+  /* Vary rate of adaptation depending on position in the file
+  // Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
+  // has begun of the file to allow the echo cancellor to estimate the
+  // channel accurately
+  */
+#if 0
+  if (ec->start_speech_d != 0 ){
+    if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
+      ec->beta2_d = max_cc_float(MIN_BETA,
+		       DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) -
+						 DEFAULT_T0 -
+						 ec->start_speech_d)));
+    }
+  }
+  else {ec->beta2_d = DEFAULT_BETA1;}
+#endif
+  
+  ec->beta2_i = DEFAULT_BETA1_I;	/* Fixed point, inverted */
+  
+  two_beta_i = (ec->beta2_i * Py_i) >> 15;	/* Fixed point version, inverted */
+  if (!two_beta_i)
+  	two_beta_i++;
+
+  /* Update Lu_i (Suppressed power estimate) */
+  ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
+  ec->Lu_i += abs(u);
+
+  /* eq. (10): update power estimate of the reference
+  */
+  ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
+  ec->Ly_i += abs(iref);
+
+  if (ec->Ly_i < DEFAULT_CUTOFF_I)
+  	ec->Ly_i = DEFAULT_CUTOFF_I;
+
+#if 0
+  printf("Float: %e, Int: %e\n", ec->Ly_d, (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * AMPL_SCALE_1);
+#endif
+  
+  if (ec->y_tilde_i > ec->max_y_tilde) {
+  	/* New highest y_tilde with full life */
+	ec->max_y_tilde = ec->y_tilde_i;
+	ec->max_y_tilde_pos = ec->N_d - 1;
+  } else if (--ec->max_y_tilde_pos < 0) {
+    /* Time to find new max y tilde... */
+	ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos);
+  }
+
+  if ((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde)
+    {
+      ec->HCNTR_d = DEFAULT_HANGT;
+    }
+  else if (ec->HCNTR_d > (int)0)
+    {
+      ec->HCNTR_d--;
+    }
+
+  /* update coefficients if no near-end speech and we have enough signal
+   * to bother trying to update.
+  */
+  if (!ec->HCNTR_d && !(ec->i_d % DEFAULT_M) && 
+      (ec->Lu_i > MIN_UPDATE_THRESH_I)) {
+	    // loop over all filter coefficients
+	    //
+	    for (k=0; k<ec->N_d; k++) {
+	      
+	      // eq. (7): compute an expectation over M_d samples 
+	      //
+		  int grad2;
+	      grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
+		  					ec->y_s.buf_d + ec->y_s.idx_d + k, DEFAULT_M);
+	      // eq. (7): update the coefficient
+	      //
+	      ec->a_i[k] += grad2 / two_beta_i;
+		  ec->a_s[k] = ec->a_i[k] >> 16;
+	    }
+  }
+
+  /* paragraph below eq. (15): if no near-end speech,
+  // check for residual error suppression
+  */
+#ifndef NO_ECHO_SUPPRESSOR
+#ifdef AGGRESSIVE_SUPPRESSOR
+#ifdef AGGRESSIVE_TIMELIMIT /* This allows the aggressive suppressor to turn off after set amount of time */
+  if (ec->i_d > AGGRESSIVE_TIMELIMIT ) {
+  	if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) {
+        	u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
+  	}
+  }
+  else {
+#endif
+  	if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
+ 		u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
+ 		u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
+  	}
+#ifdef AGGRESSIVE_TIMELIMIT  
+  }
+#endif
+#else	
+  if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) {
+  	u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
+  }
+#endif	
+#endif  
+
+#if 0
+  if ((ec->HCNTR_d == 0) && ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
+      (ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) { 
+    suppr_factor = (10/(float)(SUPPR_FLOOR-SUPPR_CEIL))*log(ec->Lu_d/ec->Ly_d)
+      - SUPPR_CEIL/(float)(SUPPR_FLOOR - SUPPR_CEIL);
+
+    u_suppr = pow(10.0,(suppr_factor)*RES_SUPR_FACTOR/10.0)*u_suppr;
+    
+  }
+#endif  
+  ec->i_d++;
+  return u;
+}
+
+static inline struct echo_can_state *echo_can_create(int len, int adaption_mode)
+{
+	struct echo_can_state *ec;
+	int maxy;
+	int maxu;
+	maxy = len + DEFAULT_M;
+	maxu = DEFAULT_M;
+	if (maxy < (1 << DEFAULT_ALPHA_YT_I))
+		maxy = (1 << DEFAULT_ALPHA_YT_I);
+	if (maxy < (1 << DEFAULT_SIGMA_LY_I))
+		maxy = (1 << DEFAULT_SIGMA_LY_I);
+	if (maxu < (1 << DEFAULT_SIGMA_LU_I))
+		maxu = (1 << DEFAULT_SIGMA_LU_I);
+	ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) +
+									4 + 						/* align */
+									sizeof(int) * len +			/* a_i */
+									sizeof(short) * len + 		/* a_s */
+									2 * sizeof(short) * (maxy) +	/* y_s */
+									2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
+									2 * sizeof(short) * (maxu) +		/* u_s */
+									2 * sizeof(short) * len);			/* y_tilde_s */
+	if (ec) {
+		memset(ec, 0, sizeof(struct echo_can_state) +
+									4 + 						/* align */
+									sizeof(int) * len +			/* a_i */
+									sizeof(short) * len + 		/* a_s */
+									2 * sizeof(short) * (maxy) +	/* y_s */
+									2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
+									2 * sizeof(short) * (maxu) +		/* u_s */
+									2 * sizeof(short) * len);			/* y_tilde_s */
+	  init_cc(ec, len, maxy, maxu);
+	}
+	return ec;
+}
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+	/* Reset hang counter to avoid adjustments after
+	   initial forced training */
+	ec->HCNTR_d = ec->N_d << 1;
+	if (pos >= ec->N_d)
+		return 1;
+	ec->a_i[pos] = val << 17;
+	ec->a_s[pos] = val << 1;
+	if (++pos >= ec->N_d)
+		return 1;
+	return 0;
+}
+
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mec2_const.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mec2_const.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mec2_const.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,28 @@
+/* 
+   Important constants for tuning mec2 echo can
+ */
+#ifndef _MEC2_CONST_H
+#define _MEC2_CONST_H
+
+
+/* Convergence speed -- higher means slower */
+#define DEFAULT_BETA1_I 2048
+#define DEFAULT_SIGMA_LY_I 7
+#define DEFAULT_SIGMA_LU_I 7
+#define DEFAULT_ALPHA_ST_I 5
+#define DEFAULT_ALPHA_YT_I 5
+#define DEFAULT_CUTOFF_I 128
+#define DEFAULT_HANGT 600
+#define DEFAULT_SUPPR_I 16
+#define MIN_UPDATE_THRESH_I 4096
+#define DEFAULT_M 16
+#define SUPPR_FLOOR -64
+#define SUPPR_CEIL -24
+#define RES_SUPR_FACTOR -20
+#define AGGRESSIVE_HCNTR 160	/* 20ms */
+
+/* Only use agressive echo cancellation for this amount of time then go back to normal cancelation */
+/* #define AGGRESSIVE_TIMELIMIT 150000 */ /* 8 = 1ms */
+
+#endif /* _MEC2_CONST_H */
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mg2ec.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mg2ec.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mg2ec.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,705 @@
+/*
+ * ECHO_CAN_MG2
+ *
+ * by Michael Gernoth
+ *
+ * Based upon kb1ec.h and mec2.h
+ * 
+ * Copyright (C) 2002, Digium, Inc.
+ *
+ * This program is free software and may be used and
+ * distributed according to the terms of the GNU
+ * General Public License, incorporated herein by
+ * reference.
+ *
+ * Additional background on the techniques used in this code can be found in:
+ *
+ *  Messerschmitt, David; Hedberg, David; Cole, Christopher; Haoui, Amine; 
+ *  Winship, Peter; "Digital Voice Echo Canceller with a TMS32020," 
+ *  in Digital Signal Processing Applications with the TMS320 Family, 
+ *  pp. 415-437, Texas Instruments, Inc., 1986. 
+ *
+ * A pdf of which is available by searching on the document title at http://www.ti.com/
+ *
+ */
+
+#ifndef _MG2_ECHO_H
+#define _MG2_ECHO_H
+
+
+#define EC_TYPE "MG2"
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#define MALLOC(a) kmalloc((a), GFP_ATOMIC)
+#define FREE(a) kfree(a)
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#define MALLOC(a) malloc(a)
+#define FREE(a) free(a)
+#endif
+
+#define ABS(a) abs(a!=-32768?a:-32767)
+
+#define RESTORE_COEFFS {\
+				int x;\
+				memcpy(ec->a_i, ec->c_i, ec->N_d*sizeof(int));\
+				for (x=0;x<ec->N_d;x++) {\
+					ec->a_s[x] = ec->a_i[x] >> 16;\
+				}\
+				ec->backup = BACKUP;\
+			}
+
+/* Uncomment to provide summary statistics for overall echo can performance every 4000 samples */ 
+/* #define MEC2_STATS 4000 */
+
+/* Uncomment to generate per-sample statistics - this will severely degrade system performance and audio quality */
+/* #define MEC2_STATS_DETAILED */
+
+/* Uncomment to generate per-call DC bias offset messages */
+/* #define MEC2_DCBIAS_MESSAGE */
+
+/* Get optimized routines for math */
+#include "dsp_arith.h"
+
+/* Bring in definitions for the various constants and thresholds */
+#include "dsp_mg2ec_const.h"
+
+#define DC_NORMALIZE
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+/* Generic circular buffer definition */
+typedef struct {
+	/* Pointer to the relative 'start' of the buffer */
+	int idx_d;
+	/* The absolute size of the buffer */
+	int size_d;			 
+	/* The actual sample -  twice as large as we need, however we do store values at idx_d and idx_d+size_d */
+	short *buf_d;			
+} echo_can_cb_s;
+
+/* Echo canceller definition */
+struct echo_can_state {
+	/* an arbitrary ID for this echo can - this really should be settable from the calling channel... */
+	int id;
+
+	/* absolute time - aka. sample number index - essentially the number of samples since this can was init'ed */
+	int i_d;
+  
+	/* Pre-computed constants */
+	/* ---------------------- */
+	/* Number of filter coefficents */
+	int N_d;
+	/* Rate of adaptation of filter */
+	int beta2_i;
+
+	/* Accumulators for power computations */
+	/* ----------------------------------- */
+	/* reference signal power estimate - aka. Average absolute value of y(k) */
+	int Ly_i;			
+	/* ... */
+	int Lu_i;
+
+	/* Accumulators for signal detectors */
+	/* --------------------------------- */
+	/* Power estimate of the recent past of the near-end hybrid signal - aka. Short-time average of: 2 x |s(i)| */
+	int s_tilde_i;		
+	/* Power estimate of the recent past of the far-end receive signal - aka. Short-time average of:     |y(i)| */
+	int y_tilde_i;
+
+	/* Near end speech detection counter - stores Hangover counter time remaining, in samples */
+	int HCNTR_d;			
+  
+	/* Circular buffers and coefficients */
+	/* --------------------------------- */
+	/* ... */
+	int *a_i;
+	/* ... */
+	short *a_s;
+	/* Backups */
+	int *b_i;
+	int *c_i;
+	/* Reference samples of far-end receive signal */
+	echo_can_cb_s y_s;
+	/* Reference samples of near-end signal */
+	echo_can_cb_s s_s;
+	/* Reference samples of near-end signal minus echo estimate */
+	echo_can_cb_s u_s;
+	/* Reference samples of far-end receive signal used to calculate short-time average */
+	echo_can_cb_s y_tilde_s;
+
+	/* Peak far-end receive signal */
+	/* --------------------------- */
+	/* Highest y_tilde value in the sample buffer */
+	short max_y_tilde;
+	/* Index of the sample containing the max_y_tilde value */
+	int max_y_tilde_pos;
+
+#ifdef MEC2_STATS
+	/* Storage for performance statistics */
+	int cntr_nearend_speech_frames;
+	int cntr_residualcorrected_frames;
+	int cntr_residualcorrected_framesskipped;
+	int cntr_coeff_updates;
+	int cntr_coeff_missedupdates;
+ 
+	int avg_Lu_i_toolow; 
+	int avg_Lu_i_ok;
+#endif 
+	short lastsig;
+	int lastcount;
+	int backup;
+#ifdef DC_NORMALIZE
+	int dc_estimate;
+#endif
+
+};
+
+static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
+{
+	cb->buf_d = (short *)where;
+	cb->idx_d = 0;
+	cb->size_d = len;
+}
+
+static inline void add_cc_s(echo_can_cb_s *cb, short newval)
+{
+	/* Can't use modulus because N+M isn't a power of two (generally) */
+	cb->idx_d--;
+	if (cb->idx_d < (int)0) 
+		/* Whoops - the pointer to the 'start' wrapped around so reset it to the top of the buffer */
+	 	cb->idx_d += cb->size_d;
+  	
+	/* Load two copies into memory */
+	cb->buf_d[cb->idx_d] = newval;
+	cb->buf_d[cb->idx_d + cb->size_d] = newval;
+}
+
+static inline short get_cc_s(echo_can_cb_s *cb, int pos)
+{
+	/* Load two copies into memory */
+	return cb->buf_d[cb->idx_d + pos];
+}
+
+static inline void init_cc(struct echo_can_state *ec, int N, int maxy, int maxu) 
+{
+
+	void *ptr = ec;
+	unsigned long tmp;
+	/* Double-word align past end of state */
+	ptr += sizeof(struct echo_can_state);
+	tmp = (unsigned long)ptr;
+	tmp += 3;
+	tmp &= ~3L;
+	ptr = (void *)tmp;
+
+	/* Reset parameters */
+	ec->N_d = N;
+	ec->beta2_i = DEFAULT_BETA1_I;
+  
+	/* Allocate coefficient memory */
+	ec->a_i = ptr;
+	ptr += (sizeof(int) * ec->N_d);
+	ec->a_s = ptr;
+	ptr += (sizeof(short) * ec->N_d);
+
+	/* Allocate backup memory */
+	ec->b_i = ptr;
+	ptr += (sizeof(int) * ec->N_d);
+	ec->c_i = ptr;
+	ptr += (sizeof(int) * ec->N_d);
+
+	/* Reset Y circular buffer (short version) */
+	init_cb_s(&ec->y_s, maxy, ptr);
+	ptr += (sizeof(short) * (maxy) * 2);
+  
+	/* Reset Sigma circular buffer (short version for FIR filter) */
+	init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
+	ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
+
+	init_cb_s(&ec->u_s, maxu, ptr);
+	ptr += (sizeof(short) * maxu * 2);
+
+	/* Allocate a buffer for the reference signal power computation */
+	init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
+
+	/* Reset the absolute time index */
+	ec->i_d = (int)0;
+  
+	/* Reset the power computations (for y and u) */
+	ec->Ly_i = DEFAULT_CUTOFF_I;
+	ec->Lu_i = DEFAULT_CUTOFF_I;
+
+#ifdef MEC2_STATS
+	/* set the identity */
+	ec->id = (int)&ptr;
+  
+	/* Reset performance stats */
+	ec->cntr_nearend_speech_frames = (int)0;
+	ec->cntr_residualcorrected_frames = (int)0;
+	ec->cntr_residualcorrected_framesskipped = (int)0;
+	ec->cntr_coeff_updates = (int)0;
+	ec->cntr_coeff_missedupdates = (int)0;
+
+	ec->avg_Lu_i_toolow = (int)0;
+	ec->avg_Lu_i_ok = (int)0;
+#endif
+
+	/* Reset the near-end speech detector */
+	ec->s_tilde_i = (int)0;
+	ec->y_tilde_i = (int)0;
+	ec->HCNTR_d = (int)0;
+
+}
+
+static inline void echo_can_free(struct echo_can_state *ec)
+{
+#if defined(DC_NORMALIZE) && defined(MEC2_DCBIAS_MESSAGE)
+	printk("EC: DC bias calculated: %d V\n", ec->dc_estimate >> 15);
+#endif
+	FREE(ec);
+}
+
+#ifdef DC_NORMALIZE
+static short inline dc_removal(int *dc_estimate, short samp)
+{
+	*dc_estimate += ((((int)samp << 15) - *dc_estimate) >> 9);
+	return samp - (*dc_estimate >> 15);
+}
+#endif
+
+static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig) 
+{
+
+	/* Declare local variables that are used more than once */
+	/* ... */
+	int k;
+	/* ... */
+	int rs;
+	/* ... */
+	short u;
+	/* ... */
+	int Py_i;
+	/* ... */
+	int two_beta_i;
+
+#ifdef DC_NORMALIZE
+	isig = dc_removal(&ec->dc_estimate, isig);
+#endif
+	
+	/* flow A on pg. 428 */
+	/* eq. (16): high-pass filter the input to generate the next value;
+	 *           push the current value into the circular buffer
+	 *
+	 * sdc_im1_d = sdc_d;
+	 *     sdc_d = sig;
+	 *     s_i_d = sdc_d;
+	 *       s_d = s_i_d;
+	 *     s_i_d = (float)(1.0 - gamma_d) * s_i_d
+	 *	+ (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); 
+	 */
+
+	/* Update the Far-end receive signal circular buffers and accumulators */
+	/* ------------------------------------------------------------------- */
+	/* Delete the oldest sample from the power estimate accumulator */
+	ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
+	/* Add the new sample to the power estimate accumulator */
+	ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_ST_I;
+	/* Push a copy of the new sample into its circular buffer */
+	add_cc_s(&ec->y_s, iref);
+ 
+
+	/* eq. (2): compute r in fixed-point */
+	rs = CONVOLVE2(ec->a_s, 
+  			ec->y_s.buf_d + ec->y_s.idx_d, 
+  			ec->N_d);
+	rs >>= 15;
+
+	if (ec->lastsig == isig) {
+		ec->lastcount++;
+	} else {
+		ec->lastcount = 0;
+		ec->lastsig = isig;
+	}
+
+	if (isig == 0) {
+		u = 0;
+	} else if (ec->lastcount > 255) {
+		/* We have seen the same input-signal more than 255 times,
+		 * we should pass it through uncancelled, as we are likely on hold */
+		u = isig;
+	} else {
+		if (rs < -32768) {
+			rs = -32768;
+			ec->HCNTR_d = DEFAULT_HANGT;
+			RESTORE_COEFFS;
+		} else if (rs > 32767) {
+			rs = 32767;
+			ec->HCNTR_d = DEFAULT_HANGT;
+			RESTORE_COEFFS;
+		}
+
+		if (ABS(ABS(rs)-ABS(isig)) > MAX_SIGN_ERROR)
+		{
+			rs = 0;
+			RESTORE_COEFFS;
+		}
+
+		/* eq. (3): compute the output value (see figure 3) and the error
+		 * note: the error is the same as the output signal when near-end
+		 * speech is not present
+		 */
+		u = isig - rs;
+
+		if (u / isig < 0)
+			u = isig - (rs >> 1);
+	}
+
+	/* Push a copy of the output value sample into its circular buffer */
+	add_cc_s(&ec->u_s, u);
+
+	if (!ec->backup) {
+		/* Backup coefficients periodically */
+		ec->backup = BACKUP;
+		memcpy(ec->c_i,ec->b_i,ec->N_d*sizeof(int));
+		memcpy(ec->b_i,ec->a_i,ec->N_d*sizeof(int));
+	} else
+		ec->backup--;
+
+
+	/* Update the Near-end hybrid signal circular buffers and accumulators */
+	/* ------------------------------------------------------------------- */
+	/* Delete the oldest sample from the power estimate accumulator */
+	ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
+	/* Add the new sample to the power estimate accumulator */
+	ec->s_tilde_i += abs(isig);
+	/* Push a copy of the new sample into it's circular buffer */
+	add_cc_s(&ec->s_s, isig);
+
+
+	/* Push a copy of the current short-time average of the far-end receive signal into it's circular buffer */
+	add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);		
+
+	/* flow B on pg. 428 */
+  
+	/* If the hangover timer isn't running then compute the new convergence factor, otherwise set Py_i to 32768 */
+	if (!ec->HCNTR_d) {
+		Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
+		Py_i >>= 15;
+	} else {
+	  	Py_i = (1 << 15);
+	}
+  
+#if 0
+	/* Vary rate of adaptation depending on position in the file
+	 *  Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
+	 *  has begun of the file to allow the echo cancellor to estimate the
+	 *  channel accurately
+	 * Still needs conversion!
+	 */
+
+	if (ec->start_speech_d != 0 ){
+		if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
+			ec->beta2_d = max_cc_float(MIN_BETA, DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) - DEFAULT_T0 - ec->start_speech_d)));
+		}
+	} else {
+		ec->beta2_d = DEFAULT_BETA1;
+	}
+#endif
+  
+	/* Fixed point, inverted */
+	ec->beta2_i = DEFAULT_BETA1_I;	
+  
+	/* Fixed point version, inverted */
+	two_beta_i = (ec->beta2_i * Py_i) >> 15;	
+	if (!two_beta_i)
+		two_beta_i++;
+
+	/* Update the Suppressed signal power estimate accumulator */
+        /* ------------------------------------------------------- */
+        /* Delete the oldest sample from the power estimate accumulator */
+	ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
+        /* Add the new sample to the power estimate accumulator */
+	ec->Lu_i += abs(u);
+
+	/* Update the Far-end reference signal power estimate accumulator */
+        /* -------------------------------------------------------------- */
+	/* eq. (10): update power estimate of the reference */
+        /* Delete the oldest sample from the power estimate accumulator */
+	ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
+        /* Add the new sample to the power estimate accumulator */
+	ec->Ly_i += abs(iref);
+
+	if (ec->Ly_i < DEFAULT_CUTOFF_I)
+		ec->Ly_i = DEFAULT_CUTOFF_I;
+
+
+	/* Update the Peak far-end receive signal detected */
+        /* ----------------------------------------------- */
+	if (ec->y_tilde_i > ec->max_y_tilde) {
+		/* New highest y_tilde with full life */
+		ec->max_y_tilde = ec->y_tilde_i;
+		ec->max_y_tilde_pos = ec->N_d - 1;
+	} else if (--ec->max_y_tilde_pos < 0) {
+		/* Time to find new max y tilde... */
+		ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos);
+	}
+
+	/* Determine if near end speech was detected in this sample */
+	/* -------------------------------------------------------- */
+	if (((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde) 
+	    && (ec->max_y_tilde > 0))  {
+		/* Then start the Hangover counter */
+		ec->HCNTR_d = DEFAULT_HANGT;
+		RESTORE_COEFFS;
+#ifdef MEC2_STATS_DETAILED
+		printk(KERN_INFO "Reset near end speech timer with: s_tilde_i %d, stmnt %d, max_y_tilde %d\n", ec->s_tilde_i, (ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)), ec->max_y_tilde);
+#endif
+#ifdef MEC2_STATS
+		++ec->cntr_nearend_speech_frames;
+#endif
+	} else if (ec->HCNTR_d > (int)0) {
+  		/* otherwise, if it's still non-zero, decrement the Hangover counter by one sample */
+#ifdef MEC2_STATS
+		++ec->cntr_nearend_speech_frames;
+#endif
+		ec->HCNTR_d--;
+	} 
+
+	/* Update coefficients if no near-end speech in this sample (ie. HCNTR_d = 0)
+	 * and we have enough signal to bother trying to update.
+	 * --------------------------------------------------------------------------
+	 */
+	if (!ec->HCNTR_d && 				/* no near-end speech present */
+		!(ec->i_d % DEFAULT_M)) {		/* we only update on every DEFAULM_M'th sample from the stream */
+  			if (ec->Lu_i > MIN_UPDATE_THRESH_I) {	/* there is sufficient energy above the noise floor to contain meaningful data */
+  							/* so loop over all the filter coefficients */
+#ifdef USED_COEFFS
+				int max_coeffs[USED_COEFFS];
+				int *pos;
+
+				if (ec->N_d > USED_COEFFS)
+					memset(max_coeffs, 0, USED_COEFFS*sizeof(int));
+#endif
+#ifdef MEC2_STATS_DETAILED
+				printk( KERN_INFO "updating coefficients with: ec->Lu_i %9d\n", ec->Lu_i);
+#endif
+#ifdef MEC2_STATS
+				ec->avg_Lu_i_ok = ec->avg_Lu_i_ok + ec->Lu_i;  
+				++ec->cntr_coeff_updates;
+#endif
+				for (k=0; k < ec->N_d; k++) {
+					/* eq. (7): compute an expectation over M_d samples */
+					int grad2;
+					grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
+							  ec->y_s.buf_d + ec->y_s.idx_d + k,
+							  DEFAULT_M);
+					/* eq. (7): update the coefficient */
+					ec->a_i[k] += grad2 / two_beta_i;
+					ec->a_s[k] = ec->a_i[k] >> 16;
+
+#ifdef USED_COEFFS
+					if (ec->N_d > USED_COEFFS) {
+						if (abs(ec->a_i[k]) > max_coeffs[USED_COEFFS-1]) {
+							/* More or less insertion-sort... */
+							pos = max_coeffs;
+							while (*pos > abs(ec->a_i[k]))
+								pos++;
+
+							if (*pos > max_coeffs[USED_COEFFS-1])
+								memmove(pos+1, pos, (USED_COEFFS-(pos-max_coeffs)-1)*sizeof(int));
+
+							*pos = abs(ec->a_i[k]);
+						}
+					}
+#endif
+				}
+
+#ifdef USED_COEFFS
+				/* Filter out irrelevant coefficients */
+				if (ec->N_d > USED_COEFFS)
+					for (k=0; k < ec->N_d; k++)
+						if (abs(ec->a_i[k]) < max_coeffs[USED_COEFFS-1])
+							ec->a_i[k] = ec->a_s[k] = 0;
+#endif
+		 	 } else { 
+#ifdef MEC2_STATS_DETAILED
+				printk( KERN_INFO "insufficient signal to update coefficients ec->Lu_i %5d < %5d\n", ec->Lu_i, MIN_UPDATE_THRESH_I);
+#endif
+#ifdef MEC2_STATS
+				ec->avg_Lu_i_toolow = ec->avg_Lu_i_toolow + ec->Lu_i;  
+				++ec->cntr_coeff_missedupdates;
+#endif
+			}
+	}
+  
+	/* paragraph below eq. (15): if no near-end speech in the sample and 
+	 * the reference signal power estimate > cutoff threshold
+	 * then perform residual error suppression
+	 */
+#ifdef MEC2_STATS_DETAILED
+	if (ec->HCNTR_d == 0)
+		printk( KERN_INFO "possibily correcting frame with ec->Ly_i %9d ec->Lu_i %9d and expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+
+#ifndef NO_ECHO_SUPPRESSOR
+#ifdef AGGRESSIVE_SUPPRESSOR
+	if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
+		for (k=0; k < RESIDUAL_SUPRESSION_PASSES; k++) {
+			u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
+		}
+#ifdef MEC2_STATS_DETAILED
+		printk( KERN_INFO "aggresively correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+#ifdef MEC2_STATS
+		++ec->cntr_residualcorrected_frames;
+#endif
+	}
+#else
+	if (ec->HCNTR_d == 0) { 
+		if ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I) {
+			for (k=0; k < RESIDUAL_SUPRESSION_PASSES; k++) {
+	  			u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
+			}
+#ifdef MEC2_STATS_DETAILED
+			printk( KERN_INFO "correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+#ifdef MEC2_STATS
+		  	++ec->cntr_residualcorrected_frames;
+#endif
+		}
+#ifdef MEC2_STATS
+		else {
+       			++ec->cntr_residualcorrected_framesskipped;
+		}
+#endif
+	}
+#endif	
+#endif  
+
+#if 0
+	/* This will generate a non-linear supression factor, once converted */
+	if ((ec->HCNTR_d == 0) && 
+	   ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
+	    (ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) { 
+	    	suppr_factor = (10 / (float)(SUPPR_FLOOR - SUPPR_CEIL)) * log(ec->Lu_d/ec->Ly_d)
+	    			- SUPPR_CEIL / (float)(SUPPR_FLOOR - SUPPR_CEIL);
+		u_suppr = pow(10.0, (suppr_factor) * RES_SUPR_FACTOR / 10.0) * u_suppr;
+	}
+#endif  
+
+#ifdef MEC2_STATS
+	/* Periodically dump performance stats */
+	if ((ec->i_d % MEC2_STATS) == 0) {
+		/* make sure to avoid div0's! */
+		if (ec->cntr_coeff_missedupdates > 0)
+			ec->avg_Lu_i_toolow = (int)(ec->avg_Lu_i_toolow / ec->cntr_coeff_missedupdates);
+		else
+			ec->avg_Lu_i_toolow = -1;
+
+		if (ec->cntr_coeff_updates > 0)
+			ec->avg_Lu_i_ok = (ec->avg_Lu_i_ok / ec->cntr_coeff_updates);
+		else
+			ec->avg_Lu_i_ok = -1;
+
+		printk( KERN_INFO "%d: Near end speech: %5d Residuals corrected/skipped: %5d/%5d Coefficients updated ok/low sig: %3d/%3d Lu_i avg ok/low sig %6d/%5d\n", 
+			ec->id,
+			ec->cntr_nearend_speech_frames, 
+			ec->cntr_residualcorrected_frames, ec->cntr_residualcorrected_framesskipped, 
+			ec->cntr_coeff_updates, ec->cntr_coeff_missedupdates, 
+			ec->avg_Lu_i_ok, ec->avg_Lu_i_toolow);
+
+		ec->cntr_nearend_speech_frames = 0;
+		ec->cntr_residualcorrected_frames = 0;
+		ec->cntr_residualcorrected_framesskipped = 0;
+		ec->cntr_coeff_updates = 0;
+		ec->cntr_coeff_missedupdates = 0;
+		ec->avg_Lu_i_ok = 0;
+		ec->avg_Lu_i_toolow = 0;
+	}
+#endif
+
+	/* Increment the sample index and return the corrected sample */
+	ec->i_d++;
+	return u;
+}
+
+static inline struct echo_can_state *echo_can_create(int len, int adaption_mode)
+{
+	struct echo_can_state *ec;
+	int maxy;
+	int maxu;
+	maxy = len + DEFAULT_M;
+	maxu = DEFAULT_M;
+	if (maxy < (1 << DEFAULT_ALPHA_YT_I))
+		maxy = (1 << DEFAULT_ALPHA_YT_I);
+	if (maxy < (1 << DEFAULT_SIGMA_LY_I))
+		maxy = (1 << DEFAULT_SIGMA_LY_I);
+	if (maxu < (1 << DEFAULT_SIGMA_LU_I))
+		maxu = (1 << DEFAULT_SIGMA_LU_I);
+	ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) +
+									4 + 						/* align */
+									sizeof(int) * len +			/* a_i */
+									sizeof(short) * len + 		/* a_s */
+									sizeof(int) * len +		/* b_i */
+									sizeof(int) * len +		/* c_i */
+									2 * sizeof(short) * (maxy) +	/* y_s */
+									2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
+									2 * sizeof(short) * (maxu) +		/* u_s */
+									2 * sizeof(short) * len);			/* y_tilde_s */
+	if (ec) {
+		memset(ec, 0, sizeof(struct echo_can_state) +
+									4 + 						/* align */
+									sizeof(int) * len +			/* a_i */
+									sizeof(short) * len + 		/* a_s */
+									sizeof(int) * len +		/* b_i */
+									sizeof(int) * len +		/* c_i */
+									2 * sizeof(short) * (maxy) +	/* y_s */
+									2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
+									2 * sizeof(short) * (maxu) +		/* u_s */
+									2 * sizeof(short) * len);			/* y_tilde_s */
+	  init_cc(ec, len, maxy, maxu);
+	}
+	return ec;
+}
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+	/* Set the hangover counter to the length of the can to 
+	 * avoid adjustments occuring immediately after initial forced training 
+	 */
+	ec->HCNTR_d = ec->N_d << 1;
+
+	if (pos >= ec->N_d) {
+		memcpy(ec->b_i,ec->a_i,ec->N_d*sizeof(int));
+		memcpy(ec->c_i,ec->a_i,ec->N_d*sizeof(int));
+		return 1;
+	}
+
+	ec->a_i[pos] = val << 17;
+	ec->a_s[pos] = val << 1;
+
+	if (++pos >= ec->N_d) {
+		memcpy(ec->b_i,ec->a_i,ec->N_d*sizeof(int));
+		memcpy(ec->c_i,ec->a_i,ec->N_d*sizeof(int));
+		return 1;
+	}
+
+	return 0;
+}
+
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mg2ec_const.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mg2ec_const.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_mg2ec_const.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,97 @@
+/* 
+   Important constants for tuning mg2 echo can
+ */
+#ifndef _MG2_CONST_H
+#define _MG2_CONST_H
+
+
+/* Convergence (aka. adaptation) speed -- higher means slower */
+#define DEFAULT_BETA1_I 2048
+
+/* Constants for various power computations */
+#define DEFAULT_SIGMA_LY_I 7
+#define DEFAULT_SIGMA_LU_I 7
+#define DEFAULT_ALPHA_ST_I 5 		/* near-end speech detection sensitivity factor */
+#define DEFAULT_ALPHA_YT_I 5
+
+#define DEFAULT_CUTOFF_I 128
+
+/* Define the near-end speech hangover counter: if near-end speech 
+ *  is declared, hcntr is set equal to hangt (see pg. 432)
+ */
+#define DEFAULT_HANGT 600  		/* in samples, so 600 samples = 75ms */
+
+/* define the residual error suppression threshold */
+#define DEFAULT_SUPPR_I 16		/* 16 = -24db */
+
+/* This is the minimum reference signal power estimate level 
+ *  that will result in filter adaptation.
+ * If this is too low then background noise will cause the filter 
+ *  coefficients to constantly be updated.
+ */
+#define MIN_UPDATE_THRESH_I 4096
+
+/* The number of samples used to update coefficients using the
+ *  the block update method (M). It should be related back to the 
+ *  length of the echo can.
+ * ie. it only updates coefficients when (sample number MOD default_m) = 0
+ *
+ *  Getting this wrong may cause an oops. Consider yourself warned!
+ */
+#define DEFAULT_M 16		  	/* every 16th sample */
+
+/* If AGGRESSIVE supression is enabled, then we start cancelling residual 
+ * echos again even while there is potentially the very end of a near-side 
+ *  signal present.
+ * This defines how many samples of DEFAULT_HANGT can remain before we
+ *  kick back in
+ */
+#define AGGRESSIVE_HCNTR 160		/* in samples, so 160 samples = 20ms */
+
+/* This knob controls the number of passes the residual echo supression 
+ * algorithm makes.
+ */
+#ifdef AGGRESSIVE_SUPPRESSOR
+ #define RESIDUAL_SUPRESSION_PASSES 2
+#else
+ #define RESIDUAL_SUPRESSION_PASSES 1
+#endif
+
+/* Treat sample as error if it has a different sign as the
+ * input signal and is this number larger in ABS() as
+ * the input-signal */
+#define MAX_SIGN_ERROR 3000
+
+/* Number of coefficients really used for calculating the
+ * simulated echo. The value specifies how many of the
+ * biggest coefficients are used for calculating rs.
+ * This helps on long echo-tails by artificially limiting
+ * the number of coefficients for the calculation and
+ * preventing overflows.
+ * Comment this to deactivate the code */
+#define USED_COEFFS 64
+
+/* Backup coefficients every this number of samples */
+#define BACKUP 256
+
+/***************************************************************/
+/* The following knobs are not implemented in the current code */
+
+/* we need a dynamic level of suppression varying with the ratio of the 
+   power of the echo to the power of the reference signal this is 
+   done so that we have a  smoother background. 		
+   we have a higher suppression when the power ratio is closer to
+   suppr_ceil and reduces logarithmically as we approach suppr_floor.
+ */
+#define SUPPR_FLOOR -64
+#define SUPPR_CEIL -24
+
+/* in a second departure, we calculate the residual error suppression
+ * as a percentage of the reference signal energy level. The threshold
+ * is defined in terms of dB below the reference signal.
+ */
+#define RES_SUPR_FACTOR -20
+
+
+#endif /* _MG2_CONST_H */
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_tones.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_tones.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dsp_tones.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,546 @@
+/* $Id: dsp_tones.c,v 1.8 2007/03/27 15:06:29 jolly Exp $ 
+ *
+ * Audio support data for ISDN4Linux.
+ *
+ * Copyright Andreas Eversberg (jolly at eversberg.eu)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+#include "dsp.h"
+
+#define DATA_S sample_silence
+#define SIZE_S &sizeof_silence
+#define DATA_GA sample_german_all
+#define SIZE_GA &sizeof_german_all
+#define DATA_GO sample_german_old
+#define SIZE_GO &sizeof_german_old
+#define DATA_DT sample_american_dialtone
+#define SIZE_DT &sizeof_american_dialtone
+#define DATA_RI sample_american_ringing
+#define SIZE_RI &sizeof_american_ringing
+#define DATA_BU sample_american_busy
+#define SIZE_BU &sizeof_american_busy
+#define DATA_S1 sample_special1
+#define SIZE_S1 &sizeof_special1
+#define DATA_S2 sample_special2
+#define SIZE_S2 &sizeof_special2
+#define DATA_S3 sample_special3
+#define SIZE_S3 &sizeof_special3
+
+/***************/
+/* tones loops */
+/***************/
+
+/* all tones are alaw encoded */
+/* the last sample+1 is in phase with the first sample. the error is low */
+
+static u8 sample_german_all[]= {
+	0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
+	0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
+	0xdc,0xfc,0x6c,
+	0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
+	0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
+	0xdc,0xfc,0x6c,
+	0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
+	0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
+	0xdc,0xfc,0x6c,
+	0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
+	0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
+	0xdc,0xfc,0x6c,
+};
+static u32 sizeof_german_all = sizeof(sample_german_all);
+
+static u8 sample_german_old[]= {
+	0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
+	0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
+	0x8c,
+	0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
+	0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
+	0x8c,
+	0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
+	0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
+	0x8c,
+	0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
+	0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
+	0x8c,
+};
+static u32 sizeof_german_old = sizeof(sample_german_old);
+
+static u8 sample_american_dialtone[]= {
+	0x2a,0x18,0x90,0x6c,0x4c,0xbc,0x4c,0x6c,
+	0x10,0x58,0x32,0xb9,0x31,0x2d,0x8d,0x0d,
+	0x8d,0x2d,0x31,0x99,0x0f,0x28,0x60,0xf0,
+	0xd0,0x50,0xd0,0x30,0x60,0x08,0x8e,0x67,
+	0x09,0x19,0x21,0xe1,0xd9,0xb9,0x29,0x67,
+	0x83,0x02,0xce,0xbe,0xee,0x1a,0x1b,0xef,
+	0xbf,0xcf,0x03,0x82,0x66,0x28,0xb8,0xd8,
+	0xe0,0x20,0x18,0x08,0x66,0x8f,0x09,0x61,
+	0x31,0xd1,0x51,0xd1,0xf1,0x61,0x29,0x0e,
+	0x98,0x30,0x2c,0x8c,0x0c,0x8c,0x2c,0x30,
+	0xb8,0x33,0x59,0x11,0x6d,0x4d,0xbd,0x4d,
+	0x6d,0x91,0x19,
+};
+static u32 sizeof_american_dialtone = sizeof(sample_american_dialtone);
+
+static u8 sample_american_ringing[]= {
+	0x2a,0xe0,0xac,0x0c,0xbc,0x4c,0x8c,0x90,
+	0x48,0xc7,0xc1,0xed,0xcd,0x4d,0xcd,0xed,
+	0xc1,0xb7,0x08,0x30,0xec,0xcc,0xcc,0x8c,
+	0x10,0x58,0x1a,0x99,0x71,0xed,0x8d,0x8d,
+	0x2d,0x41,0x89,0x9e,0x20,0x70,0x2c,0xec,
+	0x2c,0x70,0x20,0x86,0x77,0xe1,0x31,0x11,
+	0xd1,0xf1,0x81,0x09,0xa3,0x56,0x58,0x00,
+	0x40,0xc0,0x60,0x38,0x46,0x43,0x57,0x39,
+	0xd9,0x59,0x99,0xc9,0x77,0x2f,0x2e,0xc6,
+	0xd6,0x28,0xd6,0x36,0x26,0x2e,0x8a,0xa3,
+	0x43,0x63,0x4b,0x4a,0x62,0x42,0xa2,0x8b,
+	0x2f,0x27,0x37,0xd7,0x29,0xd7,0xc7,0x2f,
+	0x2e,0x76,0xc8,0x98,0x58,0xd8,0x38,0x56,
+	0x42,0x47,0x39,0x61,0xc1,0x41,0x01,0x59,
+	0x57,0xa2,0x08,0x80,0xf0,0xd0,0x10,0x30,
+	0xe0,0x76,0x87,0x21,0x71,0x2d,0xed,0x2d,
+	0x71,0x21,0x9f,0x88,0x40,0x2c,0x8c,0x8c,
+	0xec,0x70,0x98,0x1b,0x59,0x11,0x8d,0xcd,
+	0xcd,0xed,0x31,0x09,0xb6,0xc0,0xec,0xcc,
+	0x4c,0xcc,0xec,0xc0,0xc6,0x49,0x91,0x8d,
+	0x4d,0xbd,0x0d,0xad,0xe1,
+};
+static u32 sizeof_american_ringing = sizeof(sample_american_ringing);
+
+static u8 sample_american_busy[]= {
+	0x2a,0x00,0x6c,0x4c,0x4c,0x6c,0xb0,0x66,
+	0x99,0x11,0x6d,0x8d,0x2d,0x41,0xd7,0x96,
+	0x60,0xf0,0x70,0x40,0x58,0xf6,0x53,0x57,
+	0x09,0x89,0xd7,0x5f,0xe3,0x2a,0xe3,0x5f,
+	0xd7,0x89,0x09,0x57,0x53,0xf6,0x58,0x40,
+	0x70,0xf0,0x60,0x96,0xd7,0x41,0x2d,0x8d,
+	0x6d,0x11,0x99,0x66,0xb0,0x6c,0x4c,0x4c,
+	0x6c,0x00,0x2a,0x01,0x6d,0x4d,0x4d,0x6d,
+	0xb1,0x67,0x98,0x10,0x6c,0x8c,0x2c,0x40,
+	0xd6,0x97,0x61,0xf1,0x71,0x41,0x59,0xf7,
+	0x52,0x56,0x08,0x88,0xd6,0x5e,0xe2,0x2a,
+	0xe2,0x5e,0xd6,0x88,0x08,0x56,0x52,0xf7,
+	0x59,0x41,0x71,0xf1,0x61,0x97,0xd6,0x40,
+	0x2c,0x8c,0x6c,0x10,0x98,0x67,0xb1,0x6d,
+	0x4d,0x4d,0x6d,0x01,
+};
+static u32 sizeof_american_busy = sizeof(sample_american_busy);
+
+static u8 sample_special1[]= {
+	0x2a,0x2c,0xbc,0x6c,0xd6,0x71,0xbd,0x0d,
+	0xd9,0x80,0xcc,0x4c,0x40,0x39,0x0d,0xbd,
+	0x11,0x86,0xec,0xbc,0xec,0x0e,0x51,0xbd,
+	0x8d,0x89,0x30,0x4c,0xcc,0xe0,0xe1,0xcd,
+	0x4d,0x31,0x88,0x8c,0xbc,0x50,0x0f,0xed,
+	0xbd,0xed,0x87,0x10,0xbc,0x0c,0x38,0x41,
+	0x4d,0xcd,0x81,0xd8,0x0c,0xbc,0x70,0xd7,
+	0x6d,0xbd,0x2d,
+};
+static u32 sizeof_special1 = sizeof(sample_special1);
+
+static u8 sample_special2[]= {
+	0x2a,0xcc,0x8c,0xd7,0x4d,0x2d,0x18,0xbc,
+	0x10,0xc1,0xbd,0xc1,0x10,0xbc,0x18,0x2d,
+	0x4d,0xd7,0x8c,0xcc,0x2a,0xcd,0x8d,0xd6,
+	0x4c,0x2c,0x19,0xbd,0x11,0xc0,0xbc,0xc0,
+	0x11,0xbd,0x19,0x2c,0x4c,0xd6,0x8d,0xcd,
+	0x2a,0xcc,0x8c,0xd7,0x4d,0x2d,0x18,0xbc,
+	0x10,0xc1,0xbd,0xc1,0x10,0xbc,0x18,0x2d,
+	0x4d,0xd7,0x8c,0xcc,0x2a,0xcd,0x8d,0xd6,
+	0x4c,0x2c,0x19,0xbd,0x11,0xc0,0xbc,0xc0,
+	0x11,0xbd,0x19,0x2c,0x4c,0xd6,0x8d,0xcd,
+};
+static u32 sizeof_special2 = sizeof(sample_special2);
+
+static u8 sample_special3[]= {
+	0x2a,0xbc,0x18,0xcd,0x11,0x2c,0x8c,0xc1,
+	0x4d,0xd6,0xbc,0xd6,0x4d,0xc1,0x8c,0x2c,
+	0x11,0xcd,0x18,0xbc,0x2a,0xbd,0x19,0xcc,
+	0x10,0x2d,0x8d,0xc0,0x4c,0xd7,0xbd,0xd7,
+	0x4c,0xc0,0x8d,0x2d,0x10,0xcc,0x19,0xbd,
+	0x2a,0xbc,0x18,0xcd,0x11,0x2c,0x8c,0xc1,
+	0x4d,0xd6,0xbc,0xd6,0x4d,0xc1,0x8c,0x2c,
+	0x11,0xcd,0x18,0xbc,0x2a,0xbd,0x19,0xcc,
+	0x10,0x2d,0x8d,0xc0,0x4c,0xd7,0xbd,0xd7,
+	0x4c,0xc0,0x8d,0x2d,0x10,0xcc,0x19,0xbd,
+};
+static u32 sizeof_special3 = sizeof(sample_special3);
+
+static u8 sample_silence[]= {
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+	0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+};
+static u32 sizeof_silence = sizeof(sample_silence);
+
+struct tones_samples {
+	u32 *len;
+	u8 *data;
+};
+static struct 
+tones_samples samples[] = {
+	{&sizeof_german_all, sample_german_all},
+	{&sizeof_german_old, sample_german_old},
+	{&sizeof_american_dialtone, sample_american_dialtone},
+	{&sizeof_american_ringing, sample_american_ringing},
+	{&sizeof_american_busy, sample_american_busy},
+	{&sizeof_special1, sample_special1},
+	{&sizeof_special2, sample_special2},
+	{&sizeof_special3, sample_special3},
+	{NULL, NULL},
+};
+
+/***********************************
+ * generate ulaw from alaw samples *
+ ***********************************/
+
+void 
+dsp_audio_generate_ulaw_samples(void)
+{
+	int i,j;
+
+	i = 0;
+	while(samples[i].len) {
+		j = 0;
+		while(j < (*samples[i].len)) {
+			samples[i].data[j] = 
+				dsp_audio_alaw_to_ulaw[samples[i].data[j]];
+			j++;
+		}
+		i++;
+	}
+}
+
+
+/****************************
+ * tone sequence definition *
+ ****************************/
+
+struct pattern {
+	int tone;
+	u8 *data[10];
+	u32 *siz[10];
+	u32 seq[10];
+} pattern[] = {
+	{TONE_GERMAN_DIALTONE,
+	{DATA_GA,0,0,0,0,0,0,0,0,0},
+	{SIZE_GA,0,0,0,0,0,0,0,0,0},
+	{1900,0,0,0,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_OLDDIALTONE,
+	{DATA_GO,0,0,0,0,0,0,0,0,0},
+	{SIZE_GO,0,0,0,0,0,0,0,0,0},
+	{1998,0,0,0,0,0,0,0,0,0}},
+
+	{TONE_AMERICAN_DIALTONE,
+	{DATA_DT,0,0,0,0,0,0,0,0,0},
+	{SIZE_DT,0,0,0,0,0,0,0,0,0},
+	{8000,0,0,0,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_DIALPBX,
+	{DATA_GA,DATA_S,DATA_GA,DATA_S,DATA_GA,DATA_S,0,0,0,0},
+	{SIZE_GA,SIZE_S,SIZE_GA,SIZE_S,SIZE_GA,SIZE_S,0,0,0,0},
+	{2000,2000,2000,2000,2000,12000,0,0,0,0}},
+
+	{TONE_GERMAN_OLDDIALPBX,
+	{DATA_GO,DATA_S,DATA_GO,DATA_S,DATA_GO,DATA_S,0,0,0,0},
+	{SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,0,0,0,0},
+	{2000,2000,2000,2000,2000,12000,0,0,0,0}},
+
+	{TONE_AMERICAN_DIALPBX,
+	{DATA_DT,DATA_S,DATA_DT,DATA_S,DATA_DT,DATA_S,0,0,0,0},
+	{SIZE_DT,SIZE_S,SIZE_DT,SIZE_S,SIZE_DT,SIZE_S,0,0,0,0},
+	{2000,2000,2000,2000,2000,12000,0,0,0,0}},
+
+	{TONE_GERMAN_RINGING,
+	{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
+	{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
+	{8000,32000,0,0,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_OLDRINGING,
+	{DATA_GO,DATA_S,0,0,0,0,0,0,0,0},
+	{SIZE_GO,SIZE_S,0,0,0,0,0,0,0,0},
+	{8000,40000,0,0,0,0,0,0,0,0}},
+
+	{TONE_AMERICAN_RINGING,
+	{DATA_RI,DATA_S,0,0,0,0,0,0,0,0},
+	{SIZE_RI,SIZE_S,0,0,0,0,0,0,0,0},
+	{8000,32000,0,0,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_RINGPBX,
+	{DATA_GA,DATA_S,DATA_GA,DATA_S,0,0,0,0,0,0},
+	{SIZE_GA,SIZE_S,SIZE_GA,SIZE_S,0,0,0,0,0,0},
+	{4000,4000,4000,28000,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_OLDRINGPBX,
+	{DATA_GO,DATA_S,DATA_GO,DATA_S,0,0,0,0,0,0},
+	{SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,0,0,0,0,0,0},
+	{4000,4000,4000,28000,0,0,0,0,0,0}},
+
+	{TONE_AMERICAN_RINGPBX,
+	{DATA_RI,DATA_S,DATA_RI,DATA_S,0,0,0,0,0,0},
+	{SIZE_RI,SIZE_S,SIZE_RI,SIZE_S,0,0,0,0,0,0},
+	{4000,4000,4000,28000,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_BUSY,
+	{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
+	{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
+	{4000,4000,0,0,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_OLDBUSY,
+	{DATA_GO,DATA_S,0,0,0,0,0,0,0,0},
+	{SIZE_GO,SIZE_S,0,0,0,0,0,0,0,0},
+	{1000,5000,0,0,0,0,0,0,0,0}},
+
+	{TONE_AMERICAN_BUSY,
+	{DATA_BU,DATA_S,0,0,0,0,0,0,0,0},
+	{SIZE_BU,SIZE_S,0,0,0,0,0,0,0,0},
+	{4000,4000,0,0,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_HANGUP,
+	{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
+	{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
+	{4000,4000,0,0,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_OLDHANGUP,
+	{DATA_GO,DATA_S,0,0,0,0,0,0,0,0},
+	{SIZE_GO,SIZE_S,0,0,0,0,0,0,0,0},
+	{1000,5000,0,0,0,0,0,0,0,0}},
+
+	{TONE_AMERICAN_HANGUP,
+	{DATA_DT,0,0,0,0,0,0,0,0,0},
+	{SIZE_DT,0,0,0,0,0,0,0,0,0},
+	{8000,0,0,0,0,0,0,0,0,0}},
+
+	{TONE_SPECIAL_INFO,
+	{DATA_S1,DATA_S2,DATA_S3,DATA_S,0,0,0,0,0,0},
+	{SIZE_S1,SIZE_S2,SIZE_S3,SIZE_S,0,0,0,0,0,0},
+	{2666,2666,2666,8002,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_GASSENBESETZT,
+	{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
+	{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
+	{2000,2000,0,0,0,0,0,0,0,0}},
+
+	{TONE_GERMAN_AUFSCHALTTON,
+	{DATA_GO,DATA_S,DATA_GO,DATA_S,0,0,0,0,0,0},
+	{SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,0,0,0,0,0,0},
+	{1000,5000,1000,17000,0,0,0,0,0,0}},
+
+	{0,
+	{0,0,0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0,0,0}},
+};
+
+/******************
+ * copy tone data *
+ ******************/
+
+/* an sk_buff is generated from the number of samples needed.
+ * the count will be changed and may begin from 0 each pattern period.
+ * the clue is to precalculate the pointers and legths to use only one
+ * memcpy per function call, or two memcpy if the tone sequence changes.
+ *
+ * pattern - the type of the pattern
+ * count - the sample from the beginning of the pattern (phase)
+ * len - the number of bytes
+ *
+ * return - the sk_buff with the sample
+ *
+ * if tones has finished (e.g. knocking tone), dsp->tones is turned off
+ */
+void dsp_tone_copy(dsp_t *dsp, u8 *data, int len)
+{
+	int index, count, start, num;
+	struct pattern *pat;
+	tone_t *tone = &dsp->tone;
+ 
+	/* if we have no tone, we copy silence */
+	if (!tone->tone) {
+		memset(data, dsp_silence, len);
+		return;
+	}
+
+	/* process pattern */
+	pat = (struct pattern *)tone->pattern; /* points to the current pattern */
+	index = tone->index; /* gives current sequence index */
+	count = tone->count; /* gives current sample */
+
+	/* copy sample */
+	while(len) {
+		/* find sample to start with */
+		while(42) {
+			/* warp arround */
+			if (!pat->seq[index]) {
+				count = 0;
+				index = 0;
+			}
+			/* check if we are currently playing this tone */
+			if (count < pat->seq[index]) {
+				break;
+			}
+			if (dsp_debug & DEBUG_DSP_TONE)
+				printk(KERN_DEBUG "%s: reaching next sequence (index=%d)\n", __FUNCTION__, index);
+			count -= pat->seq[index];
+			index++;
+		}
+		/* calculate start and number of samples */
+		start = count % (*(pat->siz[index]));
+		num = len;
+		if (num+count > pat->seq[index])
+			num = pat->seq[index] - count;
+		if (num+start > (*(pat->siz[index])))
+			num = (*(pat->siz[index])) - start;
+		/* copy memory */
+		memcpy(data, pat->data[index]+start, num);
+		/* reduce length */
+		data += num;
+		count += num;
+		len -= num;
+	}
+	tone->index = index;
+	tone->count = count;
+
+	/* return sk_buff */
+	return;
+}
+
+
+/*******************************
+ * send HW message to hfc card *
+ *******************************/
+
+static void
+dsp_tone_hw_message(dsp_t *dsp, u8 *sample, int len)
+{
+	struct sk_buff *nskb;
+
+	nskb = create_link_skb(PH_CONTROL | REQUEST, (len)?HW_SPL_LOOP_ON:HW_SPL_LOOP_OFF, len, sample, 0);
+	if (!nskb) {
+		printk(KERN_ERR "%s: No mem for skb.\n", __FUNCTION__);
+		return;
+	}
+	/* unlocking is not required, because we don't expect a response */
+	if (mISDN_queue_down(&dsp->inst, 0, nskb))
+		dev_kfree_skb(nskb);
+}
+
+
+/*****************
+ * timer expires *
+ *****************/
+void
+dsp_tone_timeout(void *arg)
+{
+	dsp_t *dsp = arg;
+	tone_t *tone = &dsp->tone;
+	struct pattern *pat = (struct pattern *)tone->pattern;
+	int index = tone->index;
+
+	if (!tone->tone)
+		return;
+
+	index++;
+	if (!pat->seq[index])
+		index = 0;
+	tone->index = index;
+	
+	/* set next tone */
+	if (pat->data[index] == DATA_S)
+		dsp_tone_hw_message(dsp, 0, 0);
+	else
+		dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index]));
+	/* set timer */
+	init_timer(&tone->tl);
+	tone->tl.expires = jiffies + (pat->seq[index] * HZ) / 8000;
+	add_timer(&tone->tl);
+}
+
+
+/********************
+ * set/release tone *
+ ********************/
+
+/*
+ * tones are relaized by streaming or by special loop commands if supported
+ * by hardware. when hardware is used, the patterns will be controlled by
+ * timers.
+ */
+int
+dsp_tone(dsp_t *dsp, int tone)
+{
+	struct pattern *pat;
+	int i;
+	tone_t *tonet = &dsp->tone;
+
+	tonet->software = 0;
+	tonet->hardware = 0;
+
+	/* we turn off the tone */
+	if (!tone) {
+		if (dsp->features.hfc_loops)
+		if (timer_pending(&tonet->tl))
+			del_timer(&tonet->tl);
+		if (dsp->features.hfc_loops)
+			dsp_tone_hw_message(dsp, NULL, 0);
+		tonet->tone = 0;
+		return(0);
+	}
+
+	pat = NULL;
+	i = 0;
+	while(pattern[i].tone) {
+		if (pattern[i].tone == tone) {
+			pat = &pattern[i];
+			break;
+		} 
+		i++;
+	}
+	if (!pat) {
+		printk(KERN_WARNING "dsp: given tone 0x%x is invalid\n", tone);
+		return(-EINVAL);
+	}
+	if (dsp_debug & DEBUG_DSP_TONE)
+		printk(KERN_DEBUG "%s: now starting tone %d (index=%d)\n", __FUNCTION__, tone, 0);
+	tonet->tone = tone;
+	tonet->pattern = pat;
+	tonet->index = 0;
+	tonet->count = 0;
+
+	if (dsp->features.hfc_loops) {
+		tonet->hardware = 1;
+		/* set first tone */
+		dsp_tone_hw_message(dsp, pat->data[0], *(pat->siz[0]));
+		/* set timer */
+		if (timer_pending(&tonet->tl))
+			del_timer(&tonet->tl);
+		init_timer(&tonet->tl);
+		tonet->tl.expires = jiffies + (pat->seq[0] * HZ) / 8000;
+		add_timer(&tonet->tl);
+	} else {
+		tonet->software = 1;
+	}
+
+	return(0);
+}
+
+
+
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dss1.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dss1.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dss1.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,183 @@
+/* $Id: dss1.h,v 1.5 2006/12/27 18:50:50 jolly Exp $
+ *
+ *  DSS1 (Euro) D-channel protocol defines
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#ifndef l3dss1_process
+
+#define T302	15000
+#define T303	4000
+#define T304	30000
+#define T305	30000
+#define T308	4000
+/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
+/* This makes some tests easier and quicker */
+#define T309	40000
+/* T310 can be between 30-120 Seconds. We use 120 Seconds so the user can hear
+   the inband messages */
+#define T310	120000
+#define T313	4000
+#define T318	4000
+#define T319	4000
+#define N303	1
+#define T_CTRL	180000
+
+#define THOLD		4000
+#define TRETRIEVE	4000
+
+/* private TIMER events */
+#define CC_T302		0x030201
+#define CC_T303		0x030301
+#define CC_T304		0x030401
+#define CC_T305		0x030501
+#define CC_T308_1	0x030801
+#define CC_T308_2	0x030802
+#define CC_T309         0x030901
+#define CC_T310		0x031001
+#define CC_T313		0x031301
+#define CC_T318		0x031801
+#define CC_T319		0x031901
+#define CC_TCTRL	0x031f01
+#define CC_THOLD	0x03a001
+#define CC_TRETRIEVE	0x03a101
+/*
+ * Message-Types
+ */
+
+#define MT_ALERTING		0x01
+#define MT_CALL_PROCEEDING	0x02
+#define MT_CONNECT		0x07
+#define MT_CONNECT_ACKNOWLEDGE	0x0f
+#define MT_PROGRESS		0x03
+#define MT_SETUP		0x05
+#define MT_SETUP_ACKNOWLEDGE	0x0d
+#define MT_HOLD			0x24
+#define MT_HOLD_ACKNOWLEDGE	0x28
+#define MT_HOLD_REJECT		0x30
+#define MT_RETRIEVE		0x31
+#define MT_RETRIEVE_ACKNOWLEDGE	0x33
+#define MT_RETRIEVE_REJECT	0x37
+#define MT_RESUME		0x26
+#define MT_RESUME_ACKNOWLEDGE	0x2e
+#define MT_RESUME_REJECT	0x22
+#define MT_SUSPEND		0x25
+#define MT_SUSPEND_ACKNOWLEDGE	0x2d
+#define MT_SUSPEND_REJECT	0x21
+#define MT_USER_INFORMATION	0x20
+#define MT_DISCONNECT		0x45
+#define MT_RELEASE		0x4d
+#define MT_RELEASE_COMPLETE	0x5a
+#define MT_RESTART		0x46
+#define MT_RESTART_ACKNOWLEDGE	0x4e
+#define MT_SEGMENT		0x60
+#define MT_CONGESTION_CONTROL	0x79
+#define MT_INFORMATION		0x7b
+#define MT_FACILITY		0x62
+#define MT_NOTIFY		0x6e
+#define MT_STATUS		0x7d
+#define MT_STATUS_ENQUIRY	0x75
+
+#define IE_SEGMENT	0x00
+#define IE_BEARER	0x04
+#define IE_CAUSE	0x08
+#define IE_CALL_ID	0x10
+#define IE_CALL_STATE	0x14
+#define IE_CHANNEL_ID	0x18
+#define IE_FACILITY	0x1c
+#define IE_PROGRESS	0x1e
+#define IE_NET_FAC	0x20
+#define IE_NOTIFY	0x27
+#define IE_DISPLAY	0x28
+#define IE_DATE		0x29
+#define IE_KEYPAD	0x2c
+#define IE_SIGNAL	0x34
+#define IE_INFORATE	0x40
+#define IE_E2E_TDELAY	0x42
+#define IE_TDELAY_SEL	0x43
+#define IE_PACK_BINPARA	0x44
+#define IE_PACK_WINSIZE	0x45
+#define IE_PACK_SIZE	0x46
+#define IE_CUG		0x47
+#define	IE_REV_CHARGE	0x4a
+#define IE_CONNECT_PN	0x4c
+#define IE_CONNECT_SUB	0x4d
+#define IE_CALLING_PN	0x6c
+#define IE_CALLING_SUB	0x6d
+#define IE_CALLED_PN	0x70
+#define IE_CALLED_SUB	0x71
+#define IE_REDIR_NR	0x74
+#define IE_REDIR_DN	0x76
+#define IE_TRANS_SEL	0x78
+#define IE_RESTART_IND	0x79
+#define IE_LLC		0x7c
+#define IE_HLC		0x7d
+#define IE_USER_USER	0x7e
+#define IE_ESCAPE	0x7f
+#define IE_SHIFT	0x90
+#define IE_MORE_DATA	0xa0
+#define IE_COMPLETE	0xa1
+#define IE_CONGESTION	0xb0
+#define IE_COMPR_REQ	0x01
+#define IE_REPEAT	0xd0
+
+#define IE_MANDATORY	0x0100
+/* mandatory not in every case */
+#define IE_MANDATORY_1	0x0200
+
+#define ERR_IE_COMPREHENSION	 1
+#define ERR_IE_UNRECOGNIZED	-1
+#define ERR_IE_LENGTH		-2
+#define ERR_IE_SEQUENCE		-3
+
+#define CAUSE_LOC_USER		0
+
+#define CAUSE_NORMAL_CLEARING	16
+#define CAUSE_CALL_REJECTED	21
+#define CAUSE_INVALID_NUMBER	28
+#define CAUSE_STATUS_RESPONSE	30
+#define CAUSE_NORMALUNSPECIFIED	31
+#define CAUSE_TEMPORARY_FAILURE	41
+#define CAUSE_RESOURCES_UNAVAIL 47
+#define CAUSE_INVALID_CALLREF	81
+#define CAUSE_MANDATORY_IE_MISS	96
+#define CAUSE_MT_NOTIMPLEMENTED	97
+#define CAUSE_IE_NOTIMPLEMENTED	99
+#define CAUSE_INVALID_CONTENTS	100
+#define CAUSE_NOTCOMPAT_STATE	101
+#define CAUSE_TIMER_EXPIRED	102
+#define CAUSE_PROTOCOL_ERROR	111
+
+#define NO_CAUSE		254
+
+#define AUX_IDLE		0
+#define AUX_HOLD_REQ		1
+#define AUX_CALL_HELD		2
+#define AUX_RETRIEVE_REQ	3
+#define AUX_HOLD_IND		4
+#define AUX_RETRIEVE_IND	5
+
+#define VALID_HOLD_STATES_PTMP	(SBIT(3) | SBIT(4) | SBIT(10))
+#define VALID_HOLD_STATES_PTP	(SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10))
+
+#else /* only l3dss1_process */
+
+/* l3dss1 specific data in l3 process */
+typedef struct
+  { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
+    ulong ll_id; /* remebered ll id */
+    u_char remote_operation; /* handled remote operation, 0 = not active */ 
+    int proc; /* rememered procedure */  
+    ulong remote_result; /* result of remote operation for statcallb */
+    char uus1_data[35]; /* data send during alerting or disconnect */
+  } dss1_proc_priv;
+
+/* l3dss1 specific data in protocol stack */
+typedef struct
+  { unsigned char last_invoke_id; /* last used value for invoking */
+    unsigned char invoke_used[32]; /* 256 bits for 256 values */
+  } dss1_stk_priv;        
+
+#endif /* only l3dss1_process */

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dtmf.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dtmf.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/dtmf.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,667 @@
+/* $Id: dtmf.c,v 1.18 2007/02/13 10:43:45 crich Exp $
+ *
+ * Linux ISDN subsystem, DTMF tone module
+ *
+ * Author	Karsten Keil (kkeil at suse.de)
+ *
+ * based on I4L isdn_audio code
+ * Copyright 2003 by Karsten Keil (kkeil at suse.de)
+ * Copyright 1994-1999 by Fritz Elfert (fritz at isdn4linux.de)
+ * DTMF code (c) 1996 by Christian Mock (cm at kukuruz.ping.at)
+ * Silence detection (c) 1998 by Armin Schindler (mac at gismo.telekom.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include <linux/module.h>
+#include "core.h"
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+
+#define DTMF_NPOINTS 205        /* Number of samples for DTMF recognition */
+
+typedef struct _dtmf {
+	struct list_head	list;
+	u_long 			Flags;
+	int			debug;
+	char			last;
+	int			idx;
+	int			buf[DTMF_NPOINTS];
+	mISDNinstance_t		inst;
+} dtmf_t;
+
+#define	FLG_DTMF_ULAW	1
+#define FLG_DTMF_ACTIV	2
+
+static u_int debug = 0;
+
+#define DEBUG_DTMF_MGR		0x001
+#define DEBUG_DTMF_TONE		0x010
+#define DEBUG_DTMF_CTRL		0x020
+#define DEBUG_DTMF_DETECT	0x100
+#define DEBUG_DTMF_KOEFF	0x200
+
+static mISDNobject_t dtmf_obj;
+
+static char *mISDN_dtmf_revision = "$Revision: 1.18 $";
+
+/*
+ * Misc. lookup-tables.
+ */
+
+/* ulaw -> signed 16-bit */
+static short isdn_audio_ulaw_to_s16[] =
+{
+	0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
+	0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
+	0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
+	0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
+	0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
+	0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
+	0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
+	0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
+	0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
+	0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
+	0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
+	0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
+	0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
+	0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
+	0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
+	0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
+	0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
+	0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
+	0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
+	0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
+	0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
+	0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
+	0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
+	0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
+	0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
+	0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
+	0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
+	0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
+	0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
+	0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
+	0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
+	0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
+};
+
+/* alaw -> signed 16-bit */
+static short isdn_audio_alaw_to_s16[] =
+{
+	0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
+	0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
+	0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
+	0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
+	0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
+	0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
+	0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
+	0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
+	0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
+	0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
+	0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
+	0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
+	0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
+	0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
+	0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
+	0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
+	0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
+	0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
+	0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
+	0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
+	0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
+	0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
+	0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
+	0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
+	0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
+	0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
+	0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
+	0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
+	0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
+	0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
+	0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
+	0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
+};
+
+/* alaw -> ulaw */
+static char isdn_audio_alaw_to_ulaw[] =
+{
+	0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
+	0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
+	0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
+	0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
+	0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
+	0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
+	0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
+	0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
+	0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
+	0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
+	0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
+	0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
+	0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
+	0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
+	0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
+	0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
+	0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
+	0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
+	0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
+	0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
+	0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
+	0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
+	0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
+	0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
+	0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
+	0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
+	0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
+	0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
+	0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
+	0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
+	0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
+	0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
+};
+
+/* ulaw -> alaw */
+static char isdn_audio_ulaw_to_alaw[] =
+{
+	0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
+	0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
+	0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
+	0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
+	0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
+	0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
+	0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
+	0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
+	0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
+	0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
+	0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
+	0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
+	0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
+	0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
+	0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
+	0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
+	0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
+	0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
+	0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
+	0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
+	0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
+	0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
+	0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
+	0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
+	0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
+	0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
+	0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
+	0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
+	0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
+	0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
+	0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
+	0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
+};
+
+#define NCOEFF            8     /* number of frequencies to be analyzed       */
+#define DTMF_TRESH     4000     /* above this is dtmf                         */
+#define SILENCE_TRESH   200     /* below this is silence                      */
+#define AMP_BITS          9     /* bits per sample, reduced to avoid overflow */
+#define LOGRP             0
+#define HIGRP             1
+
+/* For DTMF recognition:
+ * 2 * cos(2 * PI * k / N) precalculated for all k
+ */
+static int cos2pik[NCOEFF] =
+{
+	55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
+};
+
+static char dtmf_matrix[4][4] =
+{
+	{'1', '2', '3', 'A'},
+	{'4', '5', '6', 'B'},
+	{'7', '8', '9', 'C'},
+	{'*', '0', '#', 'D'}
+};
+
+static inline void
+isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n)
+{
+#ifdef __i386__
+	unsigned long d0, d1, d2, d3;
+	__asm__ __volatile__(
+		"cld\n"
+		"1:\tlodsb\n\t"
+		"xlatb\n\t"
+		"stosb\n\t"
+		"loop 1b\n\t"
+	:	"=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
+	:	"0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
+	:	"memory", "ax");
+#else
+	while (n--)
+		*buff = table[*(unsigned char *)buff], buff++;
+#endif
+}
+
+void
+isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
+{
+	isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
+}
+
+void
+isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
+{
+	isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
+}
+
+/*
+ * Goertzel algorithm.
+ * See http://ptolemy.eecs.berkeley.edu/~pino/Ptolemy/papers/96/dtmf_ict/
+ * for more info.
+ */
+
+static void
+isdn_audio_goertzel(dtmf_t *dtmf)
+{
+	int		sk[NCOEFF], sk1[NCOEFF], sk2[NCOEFF];
+	register int	sample;	
+	int		k, n;
+	int		thresh, silence;
+	int		lgrp,hgrp;
+	char		what;
+
+	memset(sk, 0, NCOEFF*sizeof(int));
+	memset(sk1, 0, NCOEFF*sizeof(int));
+	memset(sk2, 0, NCOEFF*sizeof(int));
+	for (n = 0; n < DTMF_NPOINTS; n++) {
+		sample = dtmf->buf[n];
+		for (k = 0; k < NCOEFF; k++)
+			sk[k] = sample + ((cos2pik[k] * sk1[k]) >> 15) - sk2[k];
+		memcpy(sk2, sk1, NCOEFF*sizeof(int));
+		memcpy(sk1, sk, NCOEFF*sizeof(int));
+	}	
+	thresh = silence = 0;
+	lgrp = hgrp = -1;
+	for (k = 0; k < NCOEFF; k++) {
+		sk[k] >>= 1;
+		sk2[k] >>= 1;
+		/* compute |X(k)|**2 */
+		/* report overflows. This should not happen. */
+		/* Comment this out if desired */
+		if (sk[k] < -32768 || sk[k] > 32767)
+			printk(KERN_DEBUG
+				"dtmf goertzel overflow, sk[%d]=%d\n", k, sk[k]);
+		if (sk2[k] < -32768 || sk2[k] > 32767)
+			printk(KERN_DEBUG
+				"isdn_audio: dtmf goertzel overflow, sk2[%d]=%d\n", k, sk2[k]);
+		sk1[k] = ((sk[k] * sk[k]) >> AMP_BITS) -
+			((((cos2pik[k] * sk[k]) >> 15) * sk2[k]) >> AMP_BITS) +
+			((sk2[k] * sk2[k]) >> AMP_BITS);
+		if (sk1[k] > DTMF_TRESH) {
+			if (sk1[k] > thresh)
+				thresh = sk1[k];
+		} else if (sk1[k] < SILENCE_TRESH)
+			silence++;
+	}
+	if (dtmf->debug & DEBUG_DTMF_KOEFF)
+		printk(KERN_DEBUG "DTMF koeff(%d,%d,%d,%d,%d,%d,%d,%d) range(%d-%d)\n",
+			sk1[0], sk1[1], sk1[2], sk1[3], sk1[4], sk1[5],
+			sk1[6], sk1[7], SILENCE_TRESH, DTMF_TRESH);
+	if (silence == NCOEFF)
+		what = ' ';
+	else {
+		if (thresh > 0)	{
+			thresh = thresh >> 4;  /* touchtones must match within 12 dB */
+			for (k = 0; k < NCOEFF; k++) {
+				if (sk1[k] < thresh)
+					continue;  /* ignore */
+				/* good level found. This is allowed only one time per group */
+				if (k < NCOEFF / 2) {
+					/* lowgroup*/
+					if (lgrp >= 0) {
+						// Bad. Another tone found. */
+						lgrp = -1;
+						break;
+					} else
+						lgrp = k;
+				} else { /* higroup */
+					if (hgrp >= 0) {
+						// Bad. Another tone found. */
+						hgrp = -1;
+						break;
+					} else
+						hgrp = k - NCOEFF/2;
+				}
+			}
+			if ((lgrp >= 0) && (hgrp >= 0)) {
+				what = dtmf_matrix[lgrp][hgrp];
+				if (dtmf->last != ' ' && dtmf->last != '.')
+					dtmf->last = what;	/* min. 1 non-DTMF between DTMF */
+			} else
+					what = '.';
+		} else
+			what = '.';
+	}
+	if (dtmf->debug & DEBUG_DTMF_DETECT)
+		printk(KERN_DEBUG "DTMF: last(%c) what(%c)\n",
+			dtmf->last, what);
+	if ((what != dtmf->last) && (what != ' ') && (what != '.')) {
+		if (dtmf->debug & DEBUG_DTMF_TONE)
+			printk(KERN_DEBUG "DTMF: tone='%c'\n", what);
+		k = what | DTMF_TONE_VAL;
+		mISDN_queue_data(&dtmf->inst, FLG_MSG_UP, PH_CONTROL | INDICATION,
+			0, sizeof(int), &k, 0);
+	}
+	dtmf->last = what;
+}
+
+/*
+ * Decode audio stream into signed u16 
+ * start detection if enough data was sampled
+ */
+static void
+isdn_audio_calc_dtmf(dtmf_t *dtmf, struct sk_buff *skb)
+{
+	int len = skb->len;
+	u_char	*p = skb->data;
+	int i;
+	int c;
+
+	while (len) {
+		c = DTMF_NPOINTS - dtmf->idx;
+		if (c > len)
+			c = len;
+		if (c <= 0)
+			break;
+		for (i = 0; i < c; i++) {
+			if (test_bit(FLG_DTMF_ULAW, &dtmf->Flags))
+				dtmf->buf[dtmf->idx++] =
+					isdn_audio_ulaw_to_s16[*p++] >> (15 - AMP_BITS);
+			else
+				dtmf->buf[dtmf->idx++] =
+					isdn_audio_alaw_to_s16[*p++] >> (15 - AMP_BITS);
+		}
+		if (dtmf->idx == DTMF_NPOINTS) {
+			isdn_audio_goertzel(dtmf);
+			dtmf->idx = 0;
+		}
+		len -= c;
+	}
+}
+
+static void
+dtmf_reset(dtmf_t *dtmf)
+{
+	dtmf->last = ' ';
+	dtmf->idx = 0;
+}
+
+#ifdef OBSOLETE
+static int
+dtmf_from_up(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	dtmf_t		*dtmf;
+	mISDN_head_t	*hh;
+	int		*data;
+	int		err = 0;
+
+	dtmf = inst->privat;
+	hh = mISDN_HEAD_P(skb);
+	switch(hh->prim) {
+		case (PH_CONTROL | REQUEST):
+			if ((hh->dinfo == 0) && (skb->len >= sizeof(int))) {
+				data = (int *)skb->data;
+				if (dtmf->debug & DEBUG_DTMF_CTRL)
+					printk(KERN_DEBUG "DTMF: PH_CONTROL REQ data %04x\n",
+						*data);
+				if (*data == DTMF_TONE_START) {
+					test_and_set_bit(FLG_DTMF_ACTIV, &dtmf->Flags);
+					dtmf_reset(dtmf);
+					break;
+				} else if (*data == DTMF_TONE_STOP) {
+					test_and_clear_bit(FLG_DTMF_ACTIV, &dtmf->Flags);
+					dtmf_reset(dtmf);
+					break;
+				}
+			}
+			/* Fall trough in case of not handled function */
+		default:
+			return(mISDN_queue_down(inst, 0, skb));
+	}
+	if (!err)
+		dev_kfree_skb(skb);
+	return(err);
+}
+#endif
+
+static int
+dtmf_function(mISDNinstance_t *inst,  struct sk_buff *skb)
+{
+	dtmf_t		*dtmf;
+	mISDN_head_t	*hh;
+
+	dtmf = inst->privat;
+	hh = mISDN_HEAD_P(skb);
+	switch(hh->prim) {
+		case (PH_DATA | CONFIRM):
+			hh->prim = DL_DATA | CONFIRM;
+			break;
+		case (DL_DATA_IND):
+		case (PH_DATA_IND):
+			if (test_bit(FLG_DTMF_ACTIV, &dtmf->Flags))
+				isdn_audio_calc_dtmf(dtmf, skb);
+			hh->prim = DL_DATA_IND;
+			break;
+		case (PH_CONTROL | REQUEST):
+			if ((hh->dinfo == 0) && (skb->len >= sizeof(int))) {
+				int *data = (int *)skb->data;
+				if (dtmf->debug & DEBUG_DTMF_CTRL)
+					printk(KERN_DEBUG "DTMF: PH_CONTROL REQ data %04x\n",
+						*data);
+				if (*data == DTMF_TONE_START) {
+					test_and_set_bit(FLG_DTMF_ACTIV, &dtmf->Flags);
+					dtmf_reset(dtmf);
+					dev_kfree_skb(skb);
+					return(0);
+				} else if (*data == DTMF_TONE_STOP) {
+					test_and_clear_bit(FLG_DTMF_ACTIV, &dtmf->Flags);
+					dtmf_reset(dtmf);
+					dev_kfree_skb(skb);
+					return(0);
+				}
+			}
+			break;
+		case (PH_ACTIVATE | CONFIRM):
+			hh->prim = DL_ESTABLISH | CONFIRM;
+			break;
+		case (PH_ACTIVATE | INDICATION):
+			hh->prim = DL_ESTABLISH | INDICATION;
+			break;
+		case (PH_DEACTIVATE | CONFIRM):
+			hh->prim = DL_RELEASE | CONFIRM;
+			break;
+		case (PH_DEACTIVATE | INDICATION):
+			hh->prim = DL_RELEASE | INDICATION;
+			break;
+	}
+	return(mISDN_queue_message(inst, hh->addr & MSG_DIR_MASK, skb));
+}
+
+static void
+release_dtmf(dtmf_t *dtmf) {
+	mISDNinstance_t	*inst = &dtmf->inst;
+	u_long		flags;
+
+	spin_lock_irqsave(&dtmf_obj.lock, flags);
+	list_del(&dtmf->list);
+	spin_unlock_irqrestore(&dtmf_obj.lock, flags);
+	mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+	kfree(dtmf);
+}
+
+static int
+new_dtmf(mISDNstack_t *st, mISDN_pid_t *pid) {
+	dtmf_t	*n_dtmf;
+	int	err;
+	u_long	flags;
+
+	if (!st || !pid)
+		return(-EINVAL);
+	if (!(n_dtmf = kmalloc(sizeof(dtmf_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc dtmf_t failed\n");
+		return(-ENOMEM);
+	}
+	memset(n_dtmf, 0, sizeof(dtmf_t));
+	memcpy(&n_dtmf->inst.pid, pid, sizeof(mISDN_pid_t));
+	mISDN_init_instance(&n_dtmf->inst, &dtmf_obj, n_dtmf, dtmf_function);
+	if (!mISDN_SetHandledPID(&dtmf_obj, &n_dtmf->inst.pid)) {
+		int_error();
+		kfree(n_dtmf);
+		return(-ENOPROTOOPT);
+	}
+	n_dtmf->debug = debug;
+	spin_lock_irqsave(&dtmf_obj.lock, flags);
+	list_add_tail(&n_dtmf->list, &dtmf_obj.ilist);
+	spin_unlock_irqrestore(&dtmf_obj.lock, flags);
+	err = mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &n_dtmf->inst);
+	if (err) {
+		list_del(&n_dtmf->list);
+		kfree(n_dtmf);
+	}
+	return(err);
+}
+
+#if 0
+static int
+dtmf_status(dtmf_t *dtmf, status_info_dtmf_t *si)
+{
+
+	if (!si)
+		return(-EINVAL);
+	memset(si, 0, sizeof(status_info_dtmf_t));
+	si->len = sizeof(status_info_dtmf_t) - 2*sizeof(int);
+	si->typ = STATUS_INFO_L1;
+	si->protocol = dtmf->inst.pid.protocol[1];
+	if (test_bit(FLG_L1_ACTIVATED, &dtmf->Flags))
+		si->status = 1;
+	si->state = dtmf->dtmfm.state;
+	si->Flags = dtmf->Flags;
+	si->T3 = TIMER3_VALUE;
+	si->debug = dtmf->delay;
+	si->debug = dtmf->debug;
+	return(0);
+}
+
+#endif
+
+static char MName[] = "DTMF";
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#else
+module_param (debug, uint, S_IRUGO | S_IWUSR);
+#endif
+MODULE_PARM_DESC (debug, "dtmf debug mask");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#endif
+
+static int
+dtmf_manager(void *data, u_int prim, void *arg) {
+	mISDNinstance_t	*inst = data;
+	dtmf_t		*dtmf_l;
+	int		ret = -EINVAL;
+	u_long		flags;
+
+	if (debug & DEBUG_DTMF_MGR)
+		printk(KERN_DEBUG "dtmf_manager data:%p prim:%x arg:%p\n", data, prim, arg);
+	if (!data)
+		return(ret);
+	spin_lock_irqsave(&dtmf_obj.lock, flags);
+	list_for_each_entry(dtmf_l, &dtmf_obj.ilist, list) {
+		if (&dtmf_l->inst == inst) {
+			ret = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&dtmf_obj.lock, flags);
+	if (prim == (MGR_NEWLAYER | REQUEST))
+		return(new_dtmf(data, arg));
+	if (ret) {
+		printk(KERN_WARNING "dtmf_manager prim(%x) no instance\n", prim);
+		return(ret);
+	}
+	switch(prim) {
+	    case MGR_CLRSTPARA | INDICATION:
+		break;
+#ifdef OBSOLETE
+	    case MGR_CLONELAYER | REQUEST:
+		break;
+	    case MGR_CONNECT | REQUEST:
+		return(mISDN_ConnectIF(inst, arg));
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+		return(mISDN_SetIF(inst, arg, prim, dtmf_from_up, dtmf_from_down, dtmf_l));
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		return(mISDN_DisConnectIF(inst, arg));
+#endif
+	    case MGR_UNREGLAYER | REQUEST:
+	    case MGR_RELEASE | INDICATION:
+		if (debug & DEBUG_DTMF_MGR)
+			printk(KERN_DEBUG "release_dtmf id %x\n", dtmf_l->inst.st->id);
+		release_dtmf(dtmf_l);
+		break;
+//	    case MGR_STATUS | REQUEST:
+//		return(dtmf_status(dtmf_l, arg));
+	    default:
+		if (debug & DEBUG_DTMF_MGR)
+			printk(KERN_WARNING "dtmf_manager prim %x not handled\n", prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+static int dtmf_init(void)
+{
+	int err;
+
+	printk(KERN_INFO "DTMF modul version %s\n", mISDN_getrev(mISDN_dtmf_revision));
+#ifdef MODULE
+	dtmf_obj.owner = THIS_MODULE;
+#endif
+	dtmf_obj.name = MName;
+	dtmf_obj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANSDTMF;
+	dtmf_obj.own_ctrl = dtmf_manager;
+	spin_lock_init(&dtmf_obj.lock);
+	INIT_LIST_HEAD(&dtmf_obj.ilist);
+	if ((err = mISDN_register(&dtmf_obj))) {
+		printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
+	} else
+		mISDN_module_register(THIS_MODULE);
+	return(err);
+}
+
+static void dtmf_cleanup(void)
+{
+	int	err;
+	dtmf_t	*dtmf, *nd;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if ((err = mISDN_unregister(&dtmf_obj))) {
+		printk(KERN_ERR "Can't unregister DTMF error(%d)\n", err);
+	}
+	if (!list_empty(&dtmf_obj.ilist)) {
+		printk(KERN_WARNING "dtmf inst list not empty\n");
+		list_for_each_entry_safe(dtmf, nd, &dtmf_obj.ilist, list)
+			release_dtmf(dtmf);
+	}
+}
+
+module_init(dtmf_init);
+module_exit(dtmf_cleanup);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/faxl3.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/faxl3.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/faxl3.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,2182 @@
+/* $Id: faxl3.c,v 1.8 2007/02/13 10:43:45 crich Exp $
+ *
+ * Linux ISDN subsystem, Fax Layer 3
+ *
+ * Author	Karsten Keil (kkeil at suse.de)
+ *
+ * Copyright 2003 by Karsten Keil (kkeil at suse.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include <linux/module.h>
+#include "layer1.h"
+#include "m_capi.h"
+#include "helper.h"
+#include "debug.h"
+
+static int ttt=180;
+
+typedef struct _faxl3 {
+	struct list_head	list;
+	spinlock_t		lock;
+	u_long 			state;
+	int			debug;
+	mISDNinstance_t		inst;
+	u16			options;
+	u16			format;
+	u8			stationID[24];
+	u8			headline[64];
+	u8			DIS[12];
+	u8			CIS[24];  // only max 20 are used
+	u8			NSF[12];
+	u8			DTC[12];
+	u8			DCS[12];
+	u8			CIG[24];
+	u8			NSC[12];
+	u_int			peer_rate_mask;
+	u_int			own_rate_mask;
+	int			current_rate_idx;
+	int			current_mod;
+	int			current_rate;
+	int			pending_mod;
+	int			pending_rate;
+	int			result;
+	struct FsmInst		main;
+	struct FsmTimer 	deltimer;
+	struct FsmTimer 	timer1;
+	struct FsmInst		mod;
+	struct FsmTimer 	modtimer;
+	struct sk_buff_head	downq;
+	struct sk_buff_head	dataq;
+	struct sk_buff_head	pageq;
+	struct sk_buff_head	saveq;
+	struct sk_buff		*data_skb;
+	struct sk_buff		*page_skb;
+	int			entity;
+	int			next_id;
+	int			maxdatalen;
+	int			up_headerlen;
+	int			down_headerlen;
+	u32			ncci;
+	// SFFHEADER
+	int			pages;
+	u32			offset_lpage;
+	u32			offset_dend;
+	int			current_page;
+	// SFF page header
+	u8			page_vres;
+	u8			page_hres;
+	u8			page_code;
+	u8			page_rsv1;
+	u16			page_llen;
+	u16			page_plen;
+	u32			page_oprv;
+	u32			page_onxt;
+	u8			lasttyp;
+	int			lastlen;
+	int			line_cnt;
+	int			page_retry;
+} faxl3_t;
+
+#define	FAXL3_STATE_OUTGOING	1
+#define FAXL3_STATE_SENT_TIS	2
+#define FAXL3_STATE_CAPICONNECT	3
+#define FAXL3_STATE_GOT_DIS	8
+#define FAXL3_STATE_GOT_CIS	9
+#define FAXL3_STATE_GOT_NSF	10
+#define FAXL3_STATE_SFFHEADER	16
+#define FAXL3_STATE_PAGEHEADER	17
+#define FAXL3_STATE_NEWPAGE	18
+#define FAXL3_STATE_LASTPAGE	19
+#define FAXL3_STATE_CONTINUE	20
+#define FAXL3_STATE_HAVEDATA	21
+#define FAXL3_STATE_DATABUSY	24
+#define FAXL3_STATE_DATALAST	25
+#define FAXL3_STATE_DATAREADY	26
+
+#define FAXL3_RESULT_NONE	0
+#define FAXL3_RESULT_CFR	1
+#define FAXL3_RESULT_FTT	2
+#define FAXL3_RESULT_MCF	3
+#define FAXL3_RESULT_RTP	4
+#define FAXL3_RESULT_RTN	5
+
+static char logbuf[2000];
+static int debug = 0;
+#define DEBUG_FAXL3_FUNC	0x0001
+#define DEBUG_FAXL3_MGR		0x0010
+#define DEBUG_FAXL3_CFG		0x0020
+#define DEBUG_FAXL3_MSG		0x0100
+#define DEBUG_FAXL3_SIG         0x0200
+#define DEBUG_FAXL3_PAGEPREPARE	0x1000
+
+static mISDNobject_t faxl3_obj;
+
+static char *mISDN_faxl3_revision = "$Revision: 1.8 $";
+
+static u_char FaxModulation[] = {24,48,72,74,96,98,122,146};
+static u_char FaxModulationTrain[] = {24,48,72,73,96,97,121,145};
+static int FaxModulationBaud[] = {2400,4800,7200,7200,9600,9600,12000,14400};
+
+#define MAX_FAXMODULATION_INDEX	7
+#define FAXMODULATION_MASK	0xff
+
+#define FAXMODM_UNDEF		0x00
+#define FAXMODM_V27		0x03
+#define FAXMODM_V27_V29		0x17
+#define FAXMODM_V27_V29_V33	0x17 //We don't have V.33 definition yet
+#define FAXMODM_V27_V29_V33_V17	0xff
+
+static u_int FaxModulationRates[16] = {
+	FAXMODM_UNDEF,
+	FAXMODM_UNDEF,
+	FAXMODM_V27,
+	FAXMODM_V27_V29,
+	FAXMODM_UNDEF,
+	FAXMODM_UNDEF,
+	FAXMODM_UNDEF,
+	FAXMODM_V27_V29_V33,
+	FAXMODM_UNDEF,
+	FAXMODM_UNDEF,
+	FAXMODM_UNDEF,
+	FAXMODM_V27_V29_V33_V17,
+	FAXMODM_UNDEF,
+	FAXMODM_UNDEF,
+	FAXMODM_UNDEF,
+	FAXMODM_UNDEF
+};
+
+static u8 FaxModulationRates_DCS[8] = {
+	0x0,
+	0x2,
+	0x3,
+	0xb,
+	0x1,
+	0x9,
+	0xa,
+	0x8
+};
+
+#define Dxx_TYPE_DIS	0
+#define Dxx_TYPE_DTC	1
+#define Dxx_TYPE_DCS	2
+
+static void	l3m_debug(struct FsmInst *fi, char *fmt, ...);
+static int	send_hdlc_data(faxl3_t *fl3, u8 adr, u8 hcf, u8 fcf, u8 *para, int len);
+static int	sendL4frame(faxl3_t *fl3, int prim, int di, int len, void *arg, struct sk_buff *skb);
+static int	send_capi_msg_ncpi(faxl3_t *fl3, int prim, u16 Info);
+static int	prepare_page_data(faxl3_t *fl3);
+static int	copy_page_data4retry(faxl3_t *fl3);
+
+static
+struct Fsm faxl3fsm = {NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_L3_IDLE,
+	ST_L3_WAIT_RECVDIS,
+	ST_L3_RECV_DIS,
+	ST_L3_WAIT_SENDDCS,
+	ST_L3_SEND_DCS,
+	ST_L3_WAIT_SENDTRAIN, 
+	ST_L3_SEND_TRAIN,
+	ST_L3_WAIT_TRAINSTATE,
+	ST_L3_RECV_TRAINSTATE,
+	ST_L3_WAIT_SENDPAGE,
+	ST_L3_SEND_PAGE,
+	ST_L3_WAIT_PAGESTATE,
+	ST_L3_RECV_PAGESTATE,
+	ST_L3_WAIT_SENDEOP,
+	ST_L3_SEND_EOP,
+	ST_L3_WAIT_RECVMCF,
+	ST_L3_RECV_MCF,
+	ST_L3_WAIT_SENDDCN,
+	ST_L3_SEND_DCN,
+	ST_L3_CLEARING,
+};
+
+#define FAXL3_STATE_COUNT (ST_L3_CLEARING+1)
+
+static char *strfaxl3State[] =
+{
+	"ST_L3_IDLE",
+	"ST_L3_WAIT_RECVDIS",
+	"ST_L3_RECV_DIS",
+	"ST_L3_WAIT_SENDDCS",
+	"ST_L3_SEND_DCS",
+	"ST_L3_WAIT_SENDTRAIN", 
+	"ST_L3_SEND_TRAIN",
+	"ST_L3_WAIT_TRAINSTATE",
+	"ST_L3_RECV_TRAINSTATE",
+	"ST_L3_WAIT_SENDPAGE",
+	"ST_L3_SEND_PAGE",
+	"ST_L3_WAIT_PAGESTATE",
+	"ST_L3_RECV_PAGESTATE",
+	"ST_L3_WAIT_SENDEOP",
+	"ST_L3_SEND_EOP",
+	"ST_L3_WAIT_RECVMCF",
+	"ST_L3_RECV_MCF",
+	"ST_L3_WAIT_SENDDCN",
+	"ST_L3_SEND_DCN",
+	"ST_L3_CLEARING",
+};
+
+enum {
+	EV_CALL_OUT,
+	EV_MODEM_ACTIV,
+	EV_MODEM_IDLE,
+	EV_MODEM_ERROR,
+	EV_DATA,
+	EV_NEXT_DATA,
+	EV_DELAYTIMER,
+	EV_CLEARING,
+};
+
+#define FAXL3_EVENT_COUNT (EV_CLEARING + 1)
+
+static char *strfaxl3Event[] =
+{
+	"EV_CALL_OUT",
+	"EV_MODEM_ACTIV",
+	"EV_MODEM_IDLE",
+	"EV_MODEM_ERROR",
+	"EV_DATA",
+	"EV_NEXT_DATA",
+	"EV_DELAYTIMER",
+	"EV_CLEARING",
+};
+
+static
+struct Fsm modfsm = {NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_MOD_NULL,
+	ST_MOD_IDLE,
+	ST_MOD_WAITCONNECT,
+	ST_MOD_CONNECTED,
+	ST_MOD_WAITDISCONNECT,
+};
+
+#define MOD_STATE_COUNT (ST_MOD_WAITDISCONNECT + 1)
+
+static char *strmodState[] =
+{
+	"ST_MOD_NULL",
+	"ST_MOD_IDLE",
+	"ST_MOD_WAITCONNECT",
+	"ST_MOD_CONNECTED",
+	"ST_MOD_WAITDISCONNECT",
+};
+
+enum {
+	EV_MOD_READY,
+	EV_MOD_NEW,
+	EV_MOD_CONNECT,
+	EV_MOD_DISCONNECT,
+	EV_MOD_NOCARRIER,
+	EV_MOD_ERROR,
+	EV_MOD_TIMEOUT,
+};
+
+#define MOD_EVENT_COUNT (EV_MOD_TIMEOUT + 1)
+
+static char *strmodEvent[] =
+{
+	"EV_MOD_READY",
+	"EV_MOD_NEW",
+	"EV_MOD_CONNECT",
+	"EV_MOD_DISCONNECT",
+	"EV_MOD_NOCARRIER",
+	"EV_MOD_ERROR",
+	"EV_MOD_TIMEOUT",
+};
+
+static int
+data_next_id(faxl3_t *fl3)
+{
+	u_long	flags;
+	int	id;
+
+	spin_lock_irqsave(&fl3->lock, flags);
+	id = fl3->next_id++;
+	if (id == 0x0fff)
+		fl3->next_id = 1;
+	spin_unlock_irqrestore(&fl3->lock, flags);
+	id |= (fl3->entity << 16);
+	return(id);
+}
+
+static void
+print_hexdata(faxl3_t *fl3, char *head, int len, char *data)
+{
+	char	*t = logbuf;
+
+	t += sprintf(logbuf, "%s", head);
+	if (len > 650)
+		len = 650;
+	mISDN_QuickHex(t, data, len);
+	printk(KERN_DEBUG "%s\n", logbuf);
+}
+
+static char *rate_1[16] = {
+	"undef",
+	"undef",
+	"2400,4800 V.27ter",
+	"9600,7200,4800,2400 V.27ter/V.29",
+	"undef",
+	"undef",
+	"undef",
+	"14400,12000,9600,7200,4800,2400 V.27ter/V.29/V.33",
+	"undef",
+	"undef",
+	"undef",
+	"14400,12000,9600,7200,4800,2400 V.27ter/V.29/V.33/V.17",
+	"undef",
+	"undef",
+	"undef",
+	"undef"
+};
+
+static char *rate_2[16] = {
+	"2400(V.27ter)",
+	"9600(V.29)",
+	"4800(V.27ter)",
+	"7200(V.29)",
+	"14400(V.33)",
+	"undef",
+	"12000(V.33)",
+	"undef",
+	"14400(V.17)",
+	"9600(V.17)",
+	"12000(V.17)",
+	"7200(V.17)",
+	"undef",
+	"undef",
+	"undef",
+	"undef"
+};
+
+static char *pwidth_1[4] = {
+	"1728/A4",
+	"1728/A4 2048/B4",
+	"1728/A4 2048/B4 2432/A3",
+	"undef"
+};
+
+static char *pwidth_2[4] = {
+	"1728 A4",
+	"2048 B4",
+	"2432 A3",
+	"undef"
+};
+
+static char *plength[4] = {
+	"297/A4",
+	"364/B4",
+	"unlimited",
+	"undef"
+};
+
+static char *minrowtime_1[8] = {
+	"20ms",
+	"5ms",
+	"10ms",
+	"20ms*",
+	"40ms",
+	"40ms*",
+	"10ms*",
+	"0ms"
+};
+
+static char *minrowtime_2[8] = {
+	"20ms",
+	"5ms",
+	"10ms",
+	" ",
+	"40ms",
+	" ",
+	" ",
+	"0ms"
+};
+
+static void
+print_Dxx(faxl3_t *fl3, int typ)
+{
+	char	*ts;
+	u8	*p, v1,v2,v3;
+
+	switch (typ) {
+		case Dxx_TYPE_DIS:
+			ts = "DIS";
+			p = fl3->DIS;
+			break;
+		case Dxx_TYPE_DTC:
+			ts = "DTC";
+			p = fl3->DTC;
+			break;
+		case Dxx_TYPE_DCS:
+			ts = "DCS";
+			p = fl3->DCS;
+			break;
+		default:
+			int_error();
+			return;
+	}
+	/* OK byte one is only for group 1/2 compatibility */
+	printk(KERN_DEBUG "%s: byte1 %02X\n", ts, *p);
+	v1 = (p[1] >> 2) & 0xf;
+	printk(KERN_DEBUG "%s:%s%s %s%s%s\n", ts,
+		(test_bit(8, (u_long *)p) && (typ != Dxx_TYPE_DCS)) ? " SendG3" : "",
+		(test_bit(9, (u_long *)p)) ? " RecvG3" : "",
+		(typ == Dxx_TYPE_DCS) ? rate_2[v1] : rate_1[v1],
+		(test_bit(14, (u_long *)p)) ? " 7,7Row/mm" : "",
+		(test_bit(15, (u_long *)p)) ? " 2-Dim" : "");
+
+	v1 = p[2] & 3;
+	v2 = (p[2] >> 2) & 3;
+	v3 = (p[2] >> 4) & 7;
+	printk(KERN_DEBUG "%s: width(%s) plength(%s) MinRow(%s)\n", ts,
+		(typ == Dxx_TYPE_DCS) ? pwidth_2[v1] : pwidth_1[v1],
+		plength[v2],
+		(typ == Dxx_TYPE_DCS) ? minrowtime_2[v3] : minrowtime_1[v3]);
+
+	if (!test_bit(23, (u_long *)p))
+		return;
+
+	if (typ == Dxx_TYPE_DCS)
+		printk(KERN_DEBUG "%s:%s%s%s BS(%s)%s\n", ts,
+			(test_bit(24, (u_long *)p)) ? " 2400" : "",
+			(test_bit(25, (u_long *)p)) ? " uncompressed" : "",
+			(test_bit(26, (u_long *)p)) ? " ECM" : "",
+			(test_bit(27, (u_long *)p)) ? "64" : "256",
+			(test_bit(30, (u_long *)p)) ? " MMR" : "");
+	else
+		printk(KERN_DEBUG "%s:%s%s%s%s\n", ts,
+			(test_bit(24, (u_long *)p)) ? " 2400" : "",
+			(test_bit(25, (u_long *)p)) ? " uncompressed" : "",
+			(test_bit(26, (u_long *)p)) ? " ECM" : "",
+			(test_bit(30, (u_long *)p)) ? " MMR" : "");
+	if (!test_bit(31, (u_long *)p))
+		return;
+	/* byte is reseved */
+	if (!test_bit(39, (u_long *)p))
+		return;
+// TODO
+	if (!test_bit(47, (u_long *)p))
+		return;
+// TODO
+	if (!test_bit(55, (u_long *)p))
+		return;
+// TODO
+	if (!test_bit(63, (u_long *)p))
+		return;
+// TODO
+}
+
+static u8
+calc_dtcrate(faxl3_t *fl3)
+{
+	if ((FAXMODM_V27_V29_V33_V17 & fl3->own_rate_mask) == FAXMODM_V27_V29_V33_V17)
+		return(11);
+	if ((FAXMODM_V27_V29_V33 & fl3->own_rate_mask) == FAXMODM_V27_V29_V33)
+		return(7);
+	if ((FAXMODM_V27_V29 & fl3->own_rate_mask) == FAXMODM_V27_V29)
+		return(3);
+	if ((FAXMODM_V27& fl3->own_rate_mask) == FAXMODM_V27)
+		return(2);
+	return(0);
+}
+
+static u8
+calc_dcsrate(faxl3_t *fl3)
+{
+	if ((fl3->current_rate_idx > MAX_FAXMODULATION_INDEX) ||
+		(fl3->current_rate_idx < 0)) {
+		int_errtxt("current_rate_idx(%d)", fl3->current_rate_idx);
+		return(0xf);
+	} 
+	return(FaxModulationRates_DCS[fl3->current_rate_idx]);
+}
+
+static void
+fill_Dxx(faxl3_t *fl3, int typ)
+{
+	u8	*p, v1,v2,v3;
+
+	switch (typ) {
+		case Dxx_TYPE_DIS:
+			p = fl3->DIS;
+			break;
+		case Dxx_TYPE_DTC:
+			p = fl3->DTC;
+			break;
+		case Dxx_TYPE_DCS:
+			p = fl3->DCS;
+			break;
+		default:
+			int_error();
+			return;
+	}
+	memset(p, 0, 12); // clear all bits
+	/* OK byte one is only for group 1/2 compatibility, skipped */
+	if (typ == Dxx_TYPE_DCS)
+		v1 = calc_dcsrate(fl3);
+	else
+		v1 = calc_dtcrate(fl3);
+	p[1] = v1 << 2;
+	if (typ == Dxx_TYPE_DCS)
+		test_and_set_bit(9, (u_long *)p);
+	else
+		test_and_set_bit(8, (u_long *)p);
+	if (fl3->options & 1)
+		test_and_set_bit(14, (u_long *)p);
+// TODO: calc
+	test_and_set_bit(14, (u_long *)p);
+	v1 = 0; // A4, TODO: calc 
+	v2 = 2; // unlimited, TODO: calc
+	v3 = 7; // 0 ms, TODO: calc
+	p[2] = v1 | (v2 << 2) | (v3 << 4);
+	test_and_set_bit(23, (u_long *)p); // next byte exist
+	p[3] = 0; // TODO: calc
+}
+
+static int
+send_Dxx(faxl3_t *fl3, int typ, int last)
+{
+	u8	*p, fcf, hdlc_cf = last ? 0x13 : 3;
+	int 	len;
+
+	switch (typ) {
+		case Dxx_TYPE_DIS:
+			p = fl3->DIS;
+			fcf = 80;
+			break;
+		case Dxx_TYPE_DTC:
+			p = fl3->DTC;
+			fcf = 0x81;
+			break;
+		case Dxx_TYPE_DCS:
+			p = fl3->DCS;
+			fcf = 0x83;
+			break;
+		default:
+			int_error();
+			return(-EINVAL);
+	}
+	if (!test_bit(23, (u_long *)p))
+		len = 3;
+	else if (!test_bit(31, (u_long *)p))
+		len = 4;
+	else if (!test_bit(39, (u_long *)p))
+		len = 5;
+	else if (!test_bit(47, (u_long *)p))
+		len = 6;
+	else if (!test_bit(55, (u_long *)p))
+		len = 7;
+	else if (!test_bit(63, (u_long *)p))
+		len = 8;
+	else
+		len = 9;
+	return(send_hdlc_data(fl3, 0xff, hdlc_cf, fcf, p, len));
+}
+
+static int
+send_char20(faxl3_t *fl3, u8 *p, int fcf, int last)
+{
+	u8	buf[20], *s, hdlc_cf = last ? 0x13 : 3;
+	int	len, i;
+
+	memset(buf, ' ', 20);
+	len = strlen(p);
+	if (len > 20)
+		len = 20;
+	s = buf;
+	for (i=len; i>0; i--)
+		*s++ = p[i-1];
+	return(send_hdlc_data(fl3, 0xff, hdlc_cf, fcf, buf, 20));
+}
+
+static int
+is_valid_rate_idx(faxl3_t *fl3, int ridx)
+{
+	if ((ridx > MAX_FAXMODULATION_INDEX) || (ridx < 0))
+		return(0);
+	if (((1<<ridx) & fl3->own_rate_mask & fl3->peer_rate_mask) == 0)
+		return(0);
+	else
+		return(1);
+}
+
+static int
+fallback_rate(faxl3_t *fl3)
+{
+	fl3->current_rate_idx--;
+	while ((fl3->current_rate_idx >= 0) &&
+		!is_valid_rate_idx(fl3, fl3->current_rate_idx)) {
+		fl3->current_rate_idx--;
+	}
+	return(is_valid_rate_idx(fl3, fl3->current_rate_idx));
+}
+
+static int
+calc_max_rate(faxl3_t *fl3)
+{
+	int i;
+
+	for (i = MAX_FAXMODULATION_INDEX; i >= 0; i--) {
+		if (is_valid_rate_idx(fl3, i))
+			return(i);
+	}
+	return(-1);
+}
+
+static int
+send_data_down(faxl3_t *fl3, struct sk_buff *skb) {
+	int		ret = 0;
+	mISDNif_t	*down = &fl3->inst.down;
+
+	if (test_and_set_bit(FAXL3_STATE_DATABUSY, &fl3->state)) {
+		skb_queue_tail(&fl3->downq, skb);
+	} else {
+		mISDN_sethead(PH_DATA_REQ, data_next_id(fl3), skb);
+		ret = down->func(down, skb);
+		if (ret) {
+			int_errtxt("down: error(%d)", ret);
+		}
+	}
+	return(ret);
+}
+
+static int
+send_hdlc_data(faxl3_t *fl3, u8 adr, u8 hcf, u8 fcf, u8 *para, int len)
+{
+	struct sk_buff	*skb;
+	u_char		*p;
+	int		ret;
+
+	if (!(skb = alloc_stack_skb(3 + len, 1)))
+		return(-ENOMEM);
+	p = skb_put(skb, 3);
+	*p++ = adr;
+	*p++ = hcf;
+	*p++ = fcf;
+	if (len)
+		memcpy(skb_put(skb, len), para, len);
+	ret = send_data_down(fl3, skb);
+	if (ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+static void
+mod_init(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+	int err;
+
+	err = if_link(&fl3->inst.down, PH_ACTIVATE | REQUEST, 0, 0, NULL, 0);
+	if (err) {
+		int_error();
+		return;
+	}
+}
+
+static void
+set_new_modulation(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+	int err;
+
+	if ((fl3->pending_mod < 0) || (fl3->pending_rate <0)) {
+		if (event == EV_MOD_READY)
+			mISDN_FsmChangeState(fi, ST_MOD_IDLE);
+		else
+			int_error();
+		return;
+	}
+	mISDN_FsmChangeState(fi, ST_MOD_WAITCONNECT);
+	err = if_link(&fl3->inst.down, PH_CONTROL | REQUEST, fl3->pending_mod, sizeof(int), &fl3->pending_rate, 0);
+	if (err) {
+		int_error();
+		return;
+	}
+}
+
+static void
+mod_activ(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_MOD_CONNECTED);
+	fl3->current_mod = fl3->pending_mod;
+	fl3->pending_mod = -1;
+	fl3->current_rate = fl3->pending_rate;
+	fl3->pending_rate = -1;
+	mISDN_FsmEvent(&fl3->main, EV_MODEM_ACTIV, NULL);	
+}
+
+static void
+mod_disconnect(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_MOD_WAITDISCONNECT);
+}
+
+static void
+mod_error(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_MOD_IDLE);
+	mISDN_FsmEvent(&fl3->main, EV_MODEM_ERROR, NULL);	
+}
+
+static void
+mod_nocarrier(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_MOD_IDLE);
+	mISDN_FsmEvent(&fl3->main, EV_MODEM_IDLE, NULL);	
+}
+
+static struct FsmNode ModFnList[] =
+{
+	{ST_MOD_NULL,		EV_MOD_NEW,		mod_init},
+	{ST_MOD_NULL,		EV_MOD_READY,		set_new_modulation},
+	{ST_MOD_IDLE,		EV_MOD_READY,		set_new_modulation},
+	{ST_MOD_IDLE,		EV_MOD_NEW,		set_new_modulation},
+	{ST_MOD_WAITCONNECT,	EV_MOD_CONNECT,		mod_activ},
+	{ST_MOD_WAITCONNECT,	EV_MOD_ERROR,		mod_error},
+	{ST_MOD_CONNECTED,	EV_MOD_NOCARRIER,	mod_nocarrier},
+	{ST_MOD_CONNECTED,	EV_MOD_DISCONNECT,	mod_disconnect},
+	{ST_MOD_WAITDISCONNECT,	EV_MOD_NOCARRIER,	mod_nocarrier},
+};
+
+#define MOD_FN_COUNT (sizeof(ModFnList)/sizeof(struct FsmNode))
+
+
+static void
+l3m_callout(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_L3_WAIT_RECVDIS);
+}
+
+static void
+l3m_activ_dis(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_L3_RECV_DIS);
+}
+
+static int
+get_Dxx(u8 *dst, u8 *src, int len) {
+	if (len < 3) {
+		int_errtxt("Dxx too short %d", len);
+		return(-1);
+	}
+	if (len > 12)
+		len = 12; // normally max 9 bytes
+	memcpy(dst, src, len);
+	return(0);
+}
+
+static int
+get_CHAR20(u8 *dst, u8 *src, int len) {
+	int i;
+
+	if (len <= 0) {
+		int_errtxt("string too short %d", len);
+		return(-1);
+	}
+	if (len > 20) {
+		int_errtxt("string too big (%d) rest ignored", len);
+		len = 20;
+	}
+	for (i = 20; i > len; i--)
+		dst[20-i] = ' ';
+	for (; i > 0; i--)
+		dst[20-i] = src[i-1];
+	dst[20] = 0;
+	return(0);
+}
+
+static int
+get_Nxx(u8 *dst, u8 *src, int len) {
+	if (len < 2) {
+		int_errtxt("Nxx too short %d", len);
+		return(-1);
+	}
+	if (len > 12) {
+		int_errtxt("Nxx too big (%d) ignored", len);
+		return(-2);
+	}
+	memcpy(dst, src, len);
+	return(0);
+}
+
+static void
+init_newpage(faxl3_t *fl3)
+{
+	fl3->page_retry = 0;
+	fl3->line_cnt = 0;
+	fl3->result = 0;
+	discard_queue(&fl3->pageq);
+	discard_queue(&fl3->saveq);
+	test_and_clear_bit(FAXL3_STATE_NEWPAGE, &fl3->state);
+}
+
+static void
+l3m_receive_dis(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t		*fl3 = fi->userdata;
+	struct sk_buff	*skb = arg;
+	u8		end, *p = skb->data;
+
+	if (skb->len < 3) {
+		int_errtxt("HDLC too short %d", skb->len);
+		return;
+	}
+	if (*p != 0xff) {
+		int_errtxt("HDLC addr not FF (%02X)", *p);
+	}
+	p++;
+	if (*p == 0x03) {
+		end = 0;
+	} else if (*p == 0x13) {
+		end = 1;
+	} else {
+		int_errtxt("wrong HDLC CTRL (%02X)", *p);
+	}
+	p++;
+	skb_pull(skb, 3);
+	switch(*p) {
+		case 0x80: // DIS
+			if (0 == get_Dxx(fl3->DIS, p+1, skb->len))
+				test_and_set_bit(FAXL3_STATE_GOT_DIS, &fl3->state);
+			break;
+		case 0x40: // CIS
+			if (0 == get_CHAR20(fl3->CIS, p+1, skb->len))
+				test_and_set_bit(FAXL3_STATE_GOT_CIS, &fl3->state);
+			break;
+		case 0x20: // NSF
+			if (0 == get_Nxx(fl3->NSF, p+1, skb->len))
+				test_and_set_bit(FAXL3_STATE_GOT_NSF, &fl3->state);
+			break;
+		default:
+			int_errtxt("unhandled FCF (%02X) len %d", *p, skb->len);
+			break;
+	}
+}
+
+static void
+l3m_finish_dis(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	if (fl3->debug & DEBUG_FAXL3_SIG) {
+		if (test_bit(FAXL3_STATE_GOT_DIS, &fl3->state))
+			print_Dxx(fl3, Dxx_TYPE_DIS);
+		if (test_bit(FAXL3_STATE_GOT_CIS, &fl3->state))
+			printk(KERN_DEBUG "CIS: %s\n", fl3->CIS);
+		if (test_bit(FAXL3_STATE_GOT_NSF, &fl3->state))
+			print_hexdata(fl3, "NSF: ", 12, fl3->NSF);
+	}
+	fl3->peer_rate_mask = FaxModulationRates[(fl3->DIS[1]>>2) &0xf];
+	fl3->current_rate_idx = calc_max_rate(fl3);
+	if (fl3->current_rate_idx > 0) {
+		fill_Dxx(fl3, Dxx_TYPE_DCS);
+		if (fl3->debug & DEBUG_FAXL3_SIG)
+			print_Dxx(fl3, Dxx_TYPE_DCS);
+		fl3->pending_mod = HW_MOD_FTH;
+		fl3->pending_rate = 3;
+		mISDN_FsmChangeState(fi, ST_L3_WAIT_SENDDCS);
+		mISDN_FsmEvent(&fl3->mod, EV_MOD_NEW, NULL);
+	} else // ABORT
+		mISDN_FsmChangeState(fi, ST_L3_IDLE);
+}
+
+static void
+l3m_send_dcs(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L3_SEND_DCS);
+	if (!test_and_set_bit(FAXL3_STATE_SENT_TIS, &fl3->state))
+		send_char20(fl3, &fl3->stationID[1], 0x43, 0);
+	send_Dxx(fl3, Dxx_TYPE_DCS, 1);
+}
+
+static void
+l3m_send_lastdata(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t	*fl3 = fi->userdata;
+	int	err;
+
+	if (test_and_clear_bit(FAXL3_STATE_DATALAST, &fl3->state)) {
+		err = 0;
+		err = if_link(&fl3->inst.down, PH_CONTROL | REQUEST, HW_MOD_LASTDATA, sizeof(int), &err, 0);
+		if (err) {
+			int_error();
+			return;
+		}
+	}
+}
+
+static void
+l3m_finish_dcs(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L3_WAIT_SENDTRAIN);
+	/* wait 75 ms */
+	mISDN_FsmRestartTimer(&fl3->deltimer, 75, EV_DELAYTIMER, NULL, 2);
+}
+
+static void
+l3m_setup_train(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	if (is_valid_rate_idx(fl3, fl3->current_rate_idx)) {
+		fl3->pending_mod = HW_MOD_FTM;
+		fl3->pending_rate = FaxModulationTrain[fl3->current_rate_idx];
+		mISDN_FsmEvent(&fl3->mod, EV_MOD_NEW, NULL);
+	} else // ABORT
+		mISDN_FsmChangeState(fi, ST_L3_IDLE);
+}
+
+static void
+l3m_send_train(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t		*fl3 = fi->userdata;
+	struct sk_buff	*skb;
+	int		len, ret;
+
+	mISDN_FsmChangeState(fi, ST_L3_SEND_TRAIN);
+	len = 3*(FaxModulationBaud[fl3->current_rate_idx]/16); // 1,5 sec
+	if (!(skb = alloc_stack_skb(len, 1)))
+		return;
+	memset(skb_put(skb, len), 0, len);
+	test_and_set_bit(FAXL3_STATE_DATALAST, &fl3->state);
+	ret = send_data_down(fl3, skb);
+	if (ret) {
+		dev_kfree_skb(skb);
+	}
+}
+
+static void
+l3m_finish_train(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	fl3->pending_mod = HW_MOD_FRH;
+	fl3->pending_rate = 3;
+	mISDN_FsmChangeState(fi, ST_L3_WAIT_TRAINSTATE);
+	mISDN_FsmEvent(&fl3->mod, EV_MOD_NEW, NULL);
+}
+
+static void
+l3m_activ_trainstate(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_L3_RECV_TRAINSTATE);
+}
+
+static void
+l3m_receive_trainstate(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t		*fl3 = fi->userdata;
+	struct sk_buff	*skb = arg;
+	u8		end, *p = skb->data;
+
+	if (skb->len < 3) {
+		int_errtxt("HDLC too short %d", skb->len);
+		return;
+	}
+	if (*p != 0xff) {
+		int_errtxt("HDLC addr not FF (%02X)", *p);
+	}
+	p++;
+	if (*p == 0x03) {
+		end = 0;
+	} else if (*p == 0x13) {
+		end = 1;
+	} else {
+		int_errtxt("wrong HDLC CTRL (%02X)", *p);
+	}
+	p++;
+	skb_pull(skb, 3);
+	switch(*p) {
+		case 0x84: // CFR
+			fl3->result = FAXL3_RESULT_CFR;
+			printk(KERN_DEBUG "training successfull\n");
+			if (!test_and_set_bit(FAXL3_STATE_CAPICONNECT, &fl3->state))
+				send_capi_msg_ncpi(fl3, CAPI_CONNECT_B3_ACTIVE_IND, 0);
+			break;
+		case 0x44: // FTT
+			fl3->result = FAXL3_RESULT_FTT;
+			printk(KERN_DEBUG "training failed\n");
+			break;
+		default:
+			fl3->result = FAXL3_RESULT_NONE;
+			int_errtxt("unhandled FCF (%02X) len %d", *p, skb->len);
+			break;
+	}
+}
+
+static void
+l3m_finish_trainstate(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	if (fl3->result == FAXL3_RESULT_FTT) {
+		fl3->pending_mod = HW_MOD_FTH;
+		fl3->pending_rate = 3;
+		if (fallback_rate(fl3)) {
+			fill_Dxx(fl3, Dxx_TYPE_DCS);
+			mISDN_FsmChangeState(fi, ST_L3_WAIT_SENDDCS);
+		} else {
+			mISDN_FsmChangeState(fi, ST_L3_WAIT_SENDDCN);
+		}
+	} else {
+		mISDN_FsmChangeState(fi, ST_L3_WAIT_SENDPAGE);
+		mISDN_FsmRestartTimer(&fl3->deltimer, 75, EV_DELAYTIMER, NULL, 2);
+	}
+}
+
+static void
+l3m_setup_sendpage(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	if (is_valid_rate_idx(fl3, fl3->current_rate_idx)) {
+		fl3->pending_mod = HW_MOD_FTM;
+		fl3->pending_rate = FaxModulation[fl3->current_rate_idx];
+		mISDN_FsmEvent(&fl3->mod, EV_MOD_NEW, NULL);
+	} else // ABORT
+		mISDN_FsmChangeState(fi, ST_L3_IDLE);
+}
+
+static void
+l3m_ready_sendpage(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t	*fl3 = fi->userdata;
+	struct sk_buff	*skb;
+	int		ret;
+
+	mISDN_FsmChangeState(fi, ST_L3_SEND_PAGE);
+	if (!(skb = alloc_stack_skb(4000, 1)))
+		return;
+//	memset(skb_put(skb, 1000), 0xff, 1000);
+//	memset(skb_put(skb, 1000), 0, 1000);
+//	memset(skb_put(skb, 100), 0xff, 100);
+	memset(skb_put(skb, ttt), 0, ttt);
+	test_and_set_bit(FAXL3_STATE_DATAREADY, &fl3->state);
+	ret = send_data_down(fl3, skb);
+	if (ret) {
+		dev_kfree_skb(skb);
+	}
+}
+
+static void
+l3m_send_next_pagedata(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t		*fl3 = fi->userdata;
+	struct sk_buff	*skb;
+	int		err;
+
+start:
+	if (test_bit(FAXL3_STATE_DATALAST, &fl3->state)) {
+		if (skb_queue_empty(&fl3->pageq)) {
+			err = 0;
+			err = if_link(&fl3->inst.down, PH_CONTROL | REQUEST, HW_MOD_LASTDATA, sizeof(int), &err, 0);
+			if (err) {
+				int_error();
+				return;
+			}
+			test_and_clear_bit(FAXL3_STATE_DATALAST, &fl3->state);
+		} else {
+			while((skb = skb_dequeue(&fl3->pageq)))
+				send_data_down(fl3, skb);
+		}
+	} else {
+		if (!fl3->page_retry) {
+			prepare_page_data(fl3);
+		} else if (skb_queue_empty(&fl3->pageq)) {
+			test_and_set_bit(FAXL3_STATE_DATALAST, &fl3->state);
+			goto start;
+		}
+		if ((skb = skb_dequeue(&fl3->pageq)))
+			send_data_down(fl3, skb);
+	}
+}
+
+static void
+l3m_finish_page(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	test_and_clear_bit(FAXL3_STATE_DATAREADY, &fl3->state);
+	fl3->pending_mod = HW_MOD_FTH;
+	fl3->pending_rate = 3;
+	mISDN_FsmChangeState(fi, ST_L3_WAIT_SENDEOP);
+	mISDN_FsmEvent(&fl3->mod, EV_MOD_NEW, NULL);
+}
+
+static void
+l3m_send_endofpage(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+	u8	fcf;
+
+	mISDN_FsmChangeState(fi, ST_L3_SEND_EOP);
+	if (test_bit(FAXL3_STATE_LASTPAGE, &fl3->state))
+		fcf = 0x2f; // EOP
+	else
+		fcf = 0x4f; // MPS
+	send_hdlc_data(fl3, 0xff, 0x13, fcf, NULL, 0);
+}
+
+static void
+l3m_finish_eop(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	fl3->pending_mod = HW_MOD_FRH;
+	fl3->pending_rate = 3;
+	mISDN_FsmChangeState(fi, ST_L3_WAIT_RECVMCF);
+	mISDN_FsmEvent(&fl3->mod, EV_MOD_NEW, NULL);
+}
+
+static void
+l3m_activ_mcf(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_L3_RECV_MCF);
+}
+
+static void
+l3m_receive_mcf(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t		*fl3 = fi->userdata;
+	struct sk_buff	*skb = arg;
+	u8		end, *p = skb->data;
+
+	if (skb->len < 3) {
+		int_errtxt("HDLC too short %d", skb->len);
+		return;
+	}
+	if (*p != 0xff) {
+		int_errtxt("HDLC addr not FF (%02X)", *p);
+	}
+	p++;
+	if (*p == 0x03) {
+		end = 0;
+	} else if (*p == 0x13) {
+		end = 1;
+	} else {
+		int_errtxt("wrong HDLC CTRL (%02X)", *p);
+	}
+	p++;
+	skb_pull(skb, 3);
+	switch(*p) {
+		case 0x8C: // MCF
+			fl3->result = FAXL3_RESULT_MCF;
+			printk(KERN_DEBUG "got MCF\n");
+			break;
+		case 0xCC: // RTP
+			fl3->result = FAXL3_RESULT_RTP;
+			printk(KERN_DEBUG "got RTP\n");
+			break;
+		case 0x4C: // RTN
+			fl3->result = FAXL3_RESULT_RTN;
+			printk(KERN_DEBUG "got RTN\n");
+			break;
+		default:
+			fl3->result = FAXL3_RESULT_NONE;
+			int_errtxt("unhandled FCF (%02X) len %d", *p, skb->len);
+			break;
+	}
+}
+
+static void
+l3m_finish_mcf(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+	int	newstate = ST_L3_WAIT_SENDDCN;
+
+	if (fl3->result == FAXL3_RESULT_RTN) {
+		fl3->page_retry++;
+		if ((fl3->page_retry < 5) && fallback_rate(fl3)) {
+			newstate = ST_L3_WAIT_SENDDCS;
+			fill_Dxx(fl3, Dxx_TYPE_DCS);
+			copy_page_data4retry(fl3);
+		}
+	} else if (fl3->result == FAXL3_RESULT_MCF) {
+		if (!test_bit(FAXL3_STATE_LASTPAGE, &fl3->state)) {
+			init_newpage(fl3);
+			prepare_page_data(fl3);
+			mISDN_FsmChangeState(fi, ST_L3_WAIT_SENDPAGE);
+			mISDN_FsmRestartTimer(&fl3->deltimer, 75, EV_DELAYTIMER, NULL, 2);
+			return;
+		}
+	} else if (fl3->result == FAXL3_RESULT_RTP) {
+		if (!test_bit(FAXL3_STATE_LASTPAGE, &fl3->state)) {
+			init_newpage(fl3);
+			prepare_page_data(fl3);
+			newstate = ST_L3_WAIT_SENDDCS;
+			fill_Dxx(fl3, Dxx_TYPE_DCS);
+		}
+	} else {
+		int_errtxt("unhandled result %d abort", fl3->result);
+	}
+	fl3->pending_mod = HW_MOD_FTH;
+	fl3->pending_rate = 3;
+	mISDN_FsmChangeState(fi, newstate);
+	mISDN_FsmEvent(&fl3->mod, EV_MOD_NEW, NULL);
+}
+
+static void
+
+l3m_send_dcn(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	send_hdlc_data(fl3, 0xff, 0x13, 0xfb, NULL, 0);
+}
+
+static void
+l3m_finish_dcn(struct FsmInst *fi, int event, void *arg)
+{
+	faxl3_t *fl3 = fi->userdata;
+
+	
+	send_capi_msg_ncpi(fl3, CAPI_DISCONNECT_B3_IND, 0);
+	mISDN_FsmChangeState(fi, ST_L3_CLEARING);
+}
+
+static struct FsmNode FaxL3FnList[] =
+{
+	{ST_L3_IDLE,		EV_CALL_OUT,		l3m_callout},
+	{ST_L3_WAIT_RECVDIS,	EV_MODEM_ACTIV,		l3m_activ_dis},
+	{ST_L3_RECV_DIS,	EV_DATA,		l3m_receive_dis},
+	{ST_L3_RECV_DIS,	EV_MODEM_IDLE,		l3m_finish_dis},
+	{ST_L3_WAIT_SENDDCS,	EV_MODEM_ACTIV,		l3m_send_dcs},
+	{ST_L3_SEND_DCS,	EV_NEXT_DATA,		l3m_send_lastdata},
+	{ST_L3_SEND_DCS,        EV_MODEM_IDLE,		l3m_finish_dcs},
+	{ST_L3_WAIT_SENDTRAIN,	EV_DELAYTIMER,		l3m_setup_train},
+	{ST_L3_WAIT_SENDTRAIN,	EV_MODEM_ACTIV,		l3m_send_train},
+	{ST_L3_SEND_TRAIN,	EV_MODEM_IDLE,		l3m_finish_train},
+	{ST_L3_SEND_TRAIN,	EV_NEXT_DATA,		l3m_send_lastdata},
+	{ST_L3_WAIT_TRAINSTATE,	EV_MODEM_ACTIV,		l3m_activ_trainstate},
+	{ST_L3_RECV_TRAINSTATE,	EV_DATA,		l3m_receive_trainstate},
+	{ST_L3_RECV_TRAINSTATE,	EV_MODEM_IDLE,		l3m_finish_trainstate},
+	{ST_L3_WAIT_SENDPAGE,   EV_DELAYTIMER,		l3m_setup_sendpage},
+	{ST_L3_WAIT_SENDPAGE,	EV_MODEM_ACTIV,		l3m_ready_sendpage},
+	{ST_L3_SEND_PAGE,	EV_NEXT_DATA,		l3m_send_next_pagedata},
+	{ST_L3_SEND_PAGE,	EV_MODEM_IDLE,		l3m_finish_page},
+	{ST_L3_WAIT_SENDEOP,	EV_MODEM_ACTIV,		l3m_send_endofpage},
+	{ST_L3_SEND_EOP,	EV_NEXT_DATA,		l3m_send_lastdata},
+	{ST_L3_SEND_EOP,	EV_MODEM_IDLE,		l3m_finish_eop},
+	{ST_L3_WAIT_RECVMCF,	EV_MODEM_ACTIV,		l3m_activ_mcf},
+	{ST_L3_RECV_MCF,	EV_DATA,		l3m_receive_mcf},
+	{ST_L3_RECV_MCF,	EV_MODEM_IDLE,		l3m_finish_mcf},
+	{ST_L3_WAIT_SENDDCN,	EV_MODEM_ACTIV,		l3m_send_dcn},
+	{ST_L3_SEND_DCN,	EV_NEXT_DATA,		l3m_send_lastdata},
+	{ST_L3_SEND_DCN,	EV_MODEM_IDLE,		l3m_finish_dcn},
+};
+
+#define FAXL3_FN_COUNT (sizeof(FaxL3FnList)/sizeof(struct FsmNode))
+
+static int
+data_b3_conf(faxl3_t *fl3, struct sk_buff *skb)
+{
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u8		buf[4];
+
+	hh++;
+	capimsg_setu16(buf, 0, hh->prim); // datahandle	
+	hh--;
+	capimsg_setu16(buf, 2, 0); // Info
+	sendL4frame(fl3, CAPI_DATA_B3_CONF, hh->dinfo, 4, buf, NULL);
+	dev_kfree_skb(skb);
+	return(0);
+}
+
+static int
+copy_page_data4retry(faxl3_t *fl3) {
+	struct sk_buff_head	tmpq;
+	struct sk_buff		*skb, *nskb;
+	int			err = 0;
+
+	skb_queue_head_init(&tmpq);
+	discard_queue(&fl3->pageq);
+	while((skb = skb_dequeue(&fl3->saveq))) {
+		nskb = skb_clone(skb, GFP_ATOMIC);
+		skb_queue_tail(&fl3->pageq, skb);
+		if (!nskb) {
+			int_error();
+			err = -ENOMEM;
+		} else
+			skb_queue_tail(&tmpq, nskb);
+		
+	}
+	if (err) {
+		discard_queue(&tmpq);
+	} else {
+		while((skb = skb_dequeue(&tmpq)))
+			skb_queue_tail(&fl3->saveq, skb);
+	}
+	return(err);
+}
+
+#define	PAGE_SKB_LEN	1024
+
+static int
+collect_page_data(faxl3_t *fl3, int len, u8 *buf, int flush)
+{
+	int		l = len;
+	struct sk_buff	*skb;
+
+	if (!fl3->page_skb) {
+		fl3->page_skb = alloc_stack_skb(PAGE_SKB_LEN, 1);
+		if (!fl3->page_skb)
+			return(-ENOMEM);
+	}
+	if ((fl3->page_skb->len + len) >= PAGE_SKB_LEN) {
+		l = PAGE_SKB_LEN - fl3->page_skb->len;
+		memcpy(skb_put(fl3->page_skb, l), buf, l);
+		buf += l;
+		skb = skb_clone(fl3->page_skb, GFP_ATOMIC);
+		if (!skb) {
+			int_error();
+		} else {
+			// for resend pages
+			skb_queue_tail(&fl3->saveq, skb);
+		}
+		skb_queue_tail(&fl3->pageq, fl3->page_skb);
+		fl3->page_skb = alloc_stack_skb(PAGE_SKB_LEN, 1);
+		if (!fl3->page_skb) {
+			int_error();
+			return(-ENOMEM);
+		}
+		l = len - l;
+	}
+	if (l) {
+		memcpy(skb_put(fl3->page_skb, l), buf, l);
+	}
+	if (flush) {
+		skb = skb_clone(fl3->page_skb, GFP_ATOMIC);
+		if (!skb) {
+			int_error();
+		} else {
+			// for resend pages
+			skb_queue_tail(&fl3->saveq, skb);
+		}
+		skb_queue_tail(&fl3->pageq, fl3->page_skb);
+		fl3->page_skb = NULL;
+	}
+	return(0);
+}
+
+static int
+fill_empty_lines(faxl3_t *fl3, int cnt) {
+	u8		buf[4], *p;
+	int		l,ret = 0;
+
+	if (fl3->debug & DEBUG_FAXL3_PAGEPREPARE)
+		printk(KERN_DEBUG "%s %d\n", __FUNCTION__, cnt);
+	p = buf;
+	if (fl3->page_llen == 1728) {
+		*p++ = 0x00;
+		*p++ = 0x40;
+		*p++ = 0xd9;
+		*p++ = 0xa4;
+		l = 4;
+	} else {
+		int_error();
+		return(-EINVAL);
+	}
+	while(cnt) {
+		ret = collect_page_data(fl3, l, buf, 0);
+		fl3->line_cnt++;
+		cnt--;
+	}
+	return(ret);	
+}
+
+static int
+fill_rtc(faxl3_t *fl3) {
+	u8		buf[8] = {0, 0x08, 0x80,};
+	int		cnt = 3, ret = 0;
+
+	if (fl3->debug & DEBUG_FAXL3_PAGEPREPARE)
+		printk(KERN_DEBUG "%s\n", __FUNCTION__);
+	while(cnt) {
+		ret = collect_page_data(fl3, 3, buf, 0);
+		cnt--;
+	}
+	memset(buf, 0 ,8);
+	ret = collect_page_data(fl3, 8, buf, 1);
+	return(ret);	
+}
+
+static int
+fill_line(faxl3_t *fl3, int cnt1, u8 *data1, int cnt2, u8 *data2) {
+	u8		eol[2] = {0x00, 0x80};
+	int		ret = 0;
+
+	if (fl3->debug & DEBUG_FAXL3_PAGEPREPARE)
+		printk(KERN_DEBUG "%s: %d/%d\n", __FUNCTION__, cnt1, cnt2);
+	ret = collect_page_data(fl3, 2, eol, 0);
+	if (cnt1)
+		ret = collect_page_data(fl3, cnt1, data1, 0);
+	if (cnt2)
+		ret = collect_page_data(fl3, cnt2, data2, 0);
+	fl3->line_cnt++;
+	return(ret);	
+}
+
+static int
+next_data_skb(faxl3_t *fl3) {
+	struct sk_buff	*skb;
+	int		cnt = 3, ret = 0;
+
+	skb = skb_dequeue(&fl3->dataq);
+	if (fl3->debug & DEBUG_FAXL3_PAGEPREPARE)
+		printk(KERN_DEBUG "%s: %p/%p %d %d %lx\n", __FUNCTION__, fl3->data_skb, skb,
+			fl3->lasttyp, fl3->lastlen, fl3->state);
+	if (!skb) {
+		if (fl3->data_skb && (fl3->data_skb->len == 0)) {
+			data_b3_conf(fl3, fl3->data_skb);
+			fl3->data_skb = NULL;
+			test_and_clear_bit(FAXL3_STATE_HAVEDATA, &fl3->state);
+		}
+		return(-EAGAIN);
+	}
+	if (fl3->data_skb) {
+		if (fl3->debug & DEBUG_FAXL3_PAGEPREPARE)
+			printk(KERN_DEBUG "%s: len(%d) hl(%d)\n", __FUNCTION__, 
+				fl3->data_skb->len, skb_headroom(skb));
+		if (fl3->data_skb->len) {
+			if (fl3->data_skb->len <= skb_headroom(skb)) {
+				memcpy(skb_push(skb, fl3->data_skb->len), fl3->data_skb->data, fl3->data_skb->len);
+				skb_pull(fl3->data_skb, fl3->data_skb->len);
+			}
+			if (test_and_clear_bit(FAXL3_STATE_CONTINUE, &fl3->state)) {
+				cnt = fl3->lastlen - fl3->data_skb->len;
+				fill_line(fl3, fl3->data_skb->len, fl3->data_skb->data, cnt, skb->data);
+				skb_pull(fl3->data_skb, fl3->data_skb->len);
+				skb_pull(skb, cnt);
+			}
+			if (fl3->data_skb->len) {
+				int_error();
+				return(-EINVAL);
+			}
+		}
+		data_b3_conf(fl3, fl3->data_skb);
+	}
+	fl3->data_skb = skb;
+	return(ret);	
+}
+
+static int
+prepare_page_data(faxl3_t *fl3)
+{
+	u32	tmp32;
+	u16	tmp16;
+	u8	ver, len8;
+
+	if (!fl3->data_skb) {
+		fl3->data_skb = skb_dequeue(&fl3->dataq);
+		if (!fl3->data_skb)
+			return(-EAGAIN);
+	}
+	if (test_bit(FAXL3_STATE_CONTINUE, &fl3->state)) {
+		if (next_data_skb(fl3))
+			return(-EAGAIN);
+	}
+	if (!test_and_set_bit(FAXL3_STATE_SFFHEADER, &fl3->state)) {
+		if (fl3->data_skb->len < 0x14) {
+			int_error();
+			return(-EINVAL);
+		}
+		tmp32 = CAPIMSG_U32(fl3->data_skb->data, 0);
+		ver = CAPIMSG_U8(fl3->data_skb->data, 4);
+		len8 = CAPIMSG_U8(fl3->data_skb->data, 5);
+		tmp16 = CAPIMSG_U16(fl3->data_skb->data, 6);
+		printk(KERN_DEBUG "SFFHEADER(%x,%x,%x,%x)\n", tmp32, ver, len8, tmp16);
+		if (tmp32 != 0x66666653) { // SFFF
+			int_error();
+			return(-EINVAL);
+		}
+		if (ver != 1) { // only ver 1 supported
+			int_error();
+			return(-EINVAL);
+		}
+		fl3->pages = CAPIMSG_U16(fl3->data_skb->data, 8);
+		tmp16 = CAPIMSG_U16(fl3->data_skb->data, 10);
+		fl3->offset_lpage = CAPIMSG_U32(fl3->data_skb->data, 12);
+		fl3->offset_dend = CAPIMSG_U32(fl3->data_skb->data, 16);
+		printk(KERN_DEBUG "SFFHEADER pages %d ofP(%x) o_lpage(%x) o_dend(%x)\n",
+			fl3->pages, tmp16, fl3->offset_lpage, fl3->offset_dend);
+		if (tmp16 != 0x14) {
+			int_error();
+			return(-EINVAL);
+		}
+		skb_pull(fl3->data_skb, 0x14);
+	}
+	if (fl3->data_skb->len < 2) {
+		if (next_data_skb(fl3))
+			return(-EAGAIN);
+	}
+	while (fl3->data_skb->len > 1) {
+		fl3->lasttyp = CAPIMSG_U8(fl3->data_skb->data, 0);
+		fl3->lastlen = 0;
+		if (fl3->lasttyp == 255) {
+			int_error();
+			return(-EINVAL);
+		} else if (fl3->lasttyp == 254) {
+			// page header
+			len8 = CAPIMSG_U8(fl3->data_skb->data, 1);
+			printk(KERN_DEBUG "current page end: %d lines\n", fl3->line_cnt); 
+			if (len8 == 0) {
+				// doc end
+				printk(KERN_DEBUG "SFF doc end found\n");
+				test_and_set_bit(FAXL3_STATE_LASTPAGE, &fl3->state);
+				test_and_set_bit(FAXL3_STATE_DATALAST, &fl3->state);
+				skb_pull(fl3->data_skb, 2);
+				fill_rtc(fl3);
+				// TODO clean up skb
+				return(0);
+			}
+			if (test_and_set_bit(FAXL3_STATE_NEWPAGE, &fl3->state)) {
+				// next page
+				fill_rtc(fl3);
+				test_and_set_bit(FAXL3_STATE_DATALAST, &fl3->state);
+				return(0);
+			}
+			if (fl3->data_skb->len < (2 + len8)) {
+				if (next_data_skb(fl3))
+					return(-EAGAIN);
+			}
+			printk(KERN_DEBUG "SFF page header len %d\n", len8);
+			if (len8 < 10) {
+				int_error();
+				return(-EINVAL);
+			}
+			fl3->page_vres = CAPIMSG_U8(fl3->data_skb->data, 2);
+			fl3->page_hres = CAPIMSG_U8(fl3->data_skb->data, 3);
+			fl3->page_code = CAPIMSG_U8(fl3->data_skb->data, 4);
+			fl3->page_rsv1 = CAPIMSG_U8(fl3->data_skb->data, 5);
+			fl3->page_llen = CAPIMSG_U16(fl3->data_skb->data, 6);
+			fl3->page_plen = CAPIMSG_U16(fl3->data_skb->data, 8);
+			fl3->page_oprv = CAPIMSG_U32(fl3->data_skb->data, 10);
+			fl3->page_onxt = CAPIMSG_U32(fl3->data_skb->data, 14);
+			skb_pull(fl3->data_skb, len8 +2);
+			printk(KERN_DEBUG "SFF page header: vres(%x) hres(%x) code(%x) resrv(%x)\n",
+				fl3->page_vres, fl3->page_hres, fl3->page_code, fl3->page_rsv1);
+			printk(KERN_DEBUG "SFF page header: llen(%d) plen(%d) op(%x) on(%x)\n",
+				fl3->page_llen, fl3->page_plen, fl3->page_oprv, fl3->page_onxt);
+			continue;
+		} else if (fl3->lasttyp == 0) {
+			if (fl3->data_skb->len < 3) {
+				if (next_data_skb(fl3))
+					return(-EAGAIN);
+			}
+			fl3->lastlen = CAPIMSG_U16(fl3->data_skb->data, 1);
+			skb_pull(fl3->data_skb, 3);
+		} else if (fl3->lasttyp < 216) {
+			fl3->lastlen = fl3->lasttyp;
+			skb_pull(fl3->data_skb, 1);
+		} else if (fl3->lasttyp < 253) {
+			// white lines
+			skb_pull(fl3->data_skb, 1);
+			fill_empty_lines(fl3, fl3->lasttyp - 216);
+			continue;
+		}
+		if (fl3->data_skb->len < fl3->lastlen) {
+			test_and_set_bit(FAXL3_STATE_CONTINUE, &fl3->state);
+			break;
+		}
+		fill_line(fl3, fl3->lastlen, fl3->data_skb->data, 0, NULL);
+		skb_pull(fl3->data_skb, fl3->lastlen);
+	}
+	return(0);
+}
+
+static u16
+data_b3_req(faxl3_t *fl3, struct sk_buff *skb)
+{
+	__u16		size;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+
+	if (skb->len < 10) {
+		int_errtxt("skb too short");
+		return(0x2007);
+	}
+
+	size =  CAPIMSG_U16(skb->data, 4);
+
+	/* we save DataHandle and Flags in a area after normal mISDN_HEAD */ 
+	hh++;
+	hh->prim = CAPIMSG_U16(skb->data, 6);
+	hh->dinfo = CAPIMSG_U16(skb->data, 8);
+	/* the data begins behind the header, we don't use Data32/Data64 here */
+	if ((skb->len - size) == 18)
+		skb_pull(skb, 18);
+	else if ((skb->len - size) == 10) // old format
+		skb_pull(skb, 10);
+	else {
+		int_errtxt("skb data_b3 header len mismatch len %d", skb->len - size);
+		return(0x2007);
+	}
+	if (test_and_set_bit(FAXL3_STATE_HAVEDATA, &fl3->state)) {
+		skb_queue_tail(&fl3->dataq, skb);
+	} else {
+		fl3->data_skb = skb;
+		prepare_page_data(fl3);
+	}
+	return(0);
+}
+
+static int
+data_b3_resp(faxl3_t *faxl3, u_int di, struct sk_buff *skb)
+{
+	dev_kfree_skb(skb);
+	return(0);
+}
+
+static int
+connect_b3_req(faxl3_t *fl3, u_int di, u32 addr, struct sk_buff *skb)
+{
+	u16	info = 0;
+
+	print_hexdata(fl3, "NCPI: ", skb->len, skb->data);
+	fl3->pending_mod = HW_MOD_FRH;
+	fl3->pending_rate = 3;
+	mISDN_FsmEvent(&fl3->mod, EV_MOD_NEW, NULL);
+	mISDN_FsmEvent(&fl3->main, EV_CALL_OUT, NULL);
+	fl3->ncci = 0x10000 | addr;
+	skb_push(skb, 4);
+	sendL4frame(fl3, CAPI_CONNECT_B3_CONF, di, 2, &info, skb);
+	return(0);
+}
+
+static int
+sendL4frame(faxl3_t *fl3, int prim, int di, int len, void *arg, struct sk_buff *skb)
+{
+	u_char		*p;
+	int		ret;
+
+	if (!skb) {
+		skb = alloc_stack_skb(len +  20, fl3->up_headerlen);
+		if (!skb)
+			return(-ENOMEM);
+	} else {
+		skb_trim(skb, 0);
+	}
+	capimsg_setu32(skb_put(skb, 4), 0, fl3->ncci);
+	switch(prim) {
+		case CAPI_CONNECT_B3_CONF:
+			capimsg_setu16(skb_put(skb, 2), 0, *((u16 *)arg));
+			break;
+		case CAPI_DISCONNECT_B3_IND:
+//			capimsg_setu16(skb_put(skb, 2), 0, flags & 0xffff);
+		case CAPI_CONNECT_B3_IND:
+		case CAPI_RESET_B3_IND:
+		case CAPI_CONNECT_B3_ACTIVE_IND:
+		case CAPI_DATA_B3_CONF:
+			if (len) {
+				p = skb_put(skb, len);
+				memcpy(p, arg, len);
+			} else {
+				p = skb_put(skb, 1);
+				*p = 0;
+			}
+			break;
+		default:
+			int_error();
+			dev_kfree_skb(skb);
+			return(-EINVAL);
+	}
+	ret = if_newhead(&fl3->inst.up, prim, di, skb);
+	if (ret) {
+		printk(KERN_WARNING "%s: up error %d\n", __FUNCTION__, ret);
+		dev_kfree_skb(skb);
+	}
+	return(ret);
+}
+
+static int
+send_capi_msg_ncpi(faxl3_t *fl3, int prim, u16 Info)
+{
+	u8	ncpi[36], *p, off=0, len = 0;
+	u16	lastmod = 0;
+
+	memset(ncpi, 0, 36);
+	switch(prim) {
+		case CAPI_CONNECT_B3_ACTIVE_IND:
+			if (is_valid_rate_idx(fl3, fl3->current_rate_idx))
+				lastmod = FaxModulationBaud[fl3->current_rate_idx];
+			p = fl3->CIS;
+			break;
+		case CAPI_DISCONNECT_B3_IND:
+			if (is_valid_rate_idx(fl3, fl3->current_rate_idx))
+				lastmod = FaxModulationBaud[fl3->current_rate_idx];
+			p = fl3->CIS;
+			capimsg_setu16(ncpi, 0, Info);
+			off = 2;
+			break;
+		default:
+			int_error();
+			return(-EINVAL);
+	}
+	capimsg_setu16(ncpi, off+1, lastmod);
+	capimsg_setu16(ncpi, off+3, 0x8000); // FIXME no ECM
+	capimsg_setu16(ncpi, off+5, 0);
+	capimsg_setu16(ncpi, off+7, 0);
+	len = strlen(p);
+	if (len > 20)
+		len = 20;
+	capimsg_setu8(ncpi, off+9, len);
+	if (len)
+		memcpy(&ncpi[off+10], p, len);
+	len += 9; // 8*u16 + lenfield
+	capimsg_setu8(ncpi, off, len);
+	return(sendL4frame(fl3, prim, 0, len + off, ncpi, NULL));
+}
+
+static int
+faxl3_from_up(mISDNif_t *hif, struct sk_buff *skb)
+{
+	faxl3_t		*faxl3;
+	mISDN_head_t	*hh;
+	__u32		addr;
+	__u16		info = 0;
+	int		err = 0;
+
+	if (!hif || !hif->fdata || !skb)
+		return(-EINVAL);
+	faxl3 = hif->fdata;
+	if (!faxl3->inst.down.func) {
+		return(-ENXIO);
+	}
+	hh = mISDN_HEAD_P(skb);
+	if (faxl3->debug & DEBUG_FAXL3_FUNC)
+		printk(KERN_DEBUG "%s: prim(%x) dinfo(%x) len(%d)\n", __FUNCTION__, hh->prim, hh->dinfo, skb->len);
+	if (skb->len < 4) {
+		printk(KERN_WARNING "%s: skb too short (%d)\n", __FUNCTION__, skb->len);
+		return(-EINVAL);
+	} else {
+		addr = CAPIMSG_U32(skb->data, 0);
+		skb_pull(skb, 4);
+	}
+	if (faxl3->debug & DEBUG_FAXL3_FUNC)
+		printk(KERN_DEBUG "%s: addr(%x)\n", __FUNCTION__, addr);
+	switch(hh->prim) {
+		case CAPI_DATA_B3_REQ:
+			info = data_b3_req(faxl3, skb);
+			if (info) {
+			} else
+				err = 0;
+			break;
+		case CAPI_DATA_B3_RESP:
+			return(data_b3_resp(faxl3, hh->dinfo, skb));
+		case CAPI_CONNECT_B3_REQ:
+			return(connect_b3_req(faxl3, hh->dinfo, addr, skb));
+		case CAPI_RESET_B3_REQ:
+			break;
+		case CAPI_DISCONNECT_B3_REQ:
+			break;
+		case CAPI_CONNECT_B3_RESP:
+			if (skb->len <= 2) {
+				printk(KERN_WARNING "%s: CAPI_CONNECT_B3_RESP skb too short (%d)\n",
+					__FUNCTION__, skb->len);
+				skb_push(skb, 4);
+				return(-EINVAL);
+			}
+			info = CAPIMSG_U16(skb->data, 0);
+			skb_pull(skb, 2);
+			if (info == 0)
+				;
+			if (skb->len <= 4) { // default NCPI
+			} else {
+			}
+			dev_kfree_skb(skb);
+			err = 0;
+			break;
+		case CAPI_CONNECT_B3_ACTIVE_RESP:
+			// nothing to do
+			dev_kfree_skb(skb);
+			err = 0;
+			break;
+		case CAPI_RESET_B3_RESP:
+			dev_kfree_skb(skb);
+			err = 0;
+			break;
+		case CAPI_DISCONNECT_B3_RESP:
+			dev_kfree_skb(skb);
+			err = 0;
+			break;
+		default:
+			printk(KERN_WARNING "%s: unknown prim %x dinfo %x\n",
+				__FUNCTION__, hh->prim, hh->dinfo);
+			err = -EINVAL;
+	}
+	return(err);
+}
+
+static void
+ph_status_ind(faxl3_t *fl3, int status)
+{
+	switch(status) {
+		case HW_MOD_READY:
+			mISDN_FsmEvent(&fl3->mod, EV_MOD_READY, NULL);
+			break;
+		case HW_MOD_CONNECT:
+			mISDN_FsmEvent(&fl3->mod, EV_MOD_CONNECT, NULL);
+			break;
+		case HW_MOD_OK:
+		case HW_MOD_NOCARR:
+			mISDN_FsmEvent(&fl3->mod, EV_MOD_NOCARRIER, NULL);
+			break;
+		default:
+			int_errtxt("unhandled status(%x)", status);
+			break;
+	}
+}
+
+static void
+ph_data_cnf(faxl3_t *fl3, int status)
+{
+	struct sk_buff	*skb ;
+	mISDNif_t	*down = &fl3->inst.down;
+	int		ret;
+
+	if (!test_bit(FAXL3_STATE_DATABUSY, &fl3->state)) {
+		int_errtxt("PH_DATA | CONFIRM without DATABUSY");
+		return;
+	}
+	skb = skb_dequeue(&fl3->downq);
+	if ((skb == NULL) && test_bit(FAXL3_STATE_DATAREADY, &fl3->state)) {
+		skb = skb_dequeue(&fl3->pageq);
+	}
+	if (skb)  {
+		mISDN_sethead(PH_DATA_REQ, data_next_id(fl3), skb);
+		ret = down->func(down, skb);
+		if (ret) {
+			dev_kfree_skb(skb);
+			int_errtxt("down: error(%d)", ret);
+			return;
+		}
+	} else {
+		test_and_clear_bit(FAXL3_STATE_DATABUSY, &fl3->state);
+		mISDN_FsmEvent(&fl3->main, EV_NEXT_DATA, NULL);
+	}
+}
+
+static int
+faxl3_from_down(mISDNif_t *hif,  struct sk_buff *skb)
+{
+	faxl3_t		*faxl3;
+	mISDN_head_t	*hh;
+	int		err = 0;
+
+	if (!hif || !hif->fdata || !skb)
+		return(-EINVAL);
+	faxl3 = hif->fdata;
+	if (!faxl3->inst.up.func) {
+		return(-ENXIO);
+	}
+	hh = mISDN_HEAD_P(skb);
+	if (faxl3->debug & DEBUG_FAXL3_FUNC)
+		printk(KERN_DEBUG "%s: prim(%x) dinfo(%x) len(%d)\n", __FUNCTION__, hh->prim, hh->dinfo, skb->len);
+	switch(hh->prim) {
+		case PH_ACTIVATE | INDICATION:
+		case PH_ACTIVATE | CONFIRM:
+			break;
+		case PH_STATUS | INDICATION:
+			ph_status_ind(faxl3, hh->dinfo);
+			break;
+		case PH_DATA | INDICATION:
+			mISDN_FsmEvent(&faxl3->main, EV_DATA, skb);
+			break;
+		case PH_DATA | CONFIRM:
+			ph_data_cnf(faxl3, hh->dinfo);
+			break;
+		default:
+			printk(KERN_WARNING "%s: unknown prim %x dinfo %x\n",
+				__FUNCTION__, hh->prim, hh->dinfo);
+			err = -EINVAL;
+			break;
+	}
+	if (!err)
+		dev_kfree_skb(skb);
+	return(err);
+}
+
+static char MName[] = "FAXL3";
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+module_param(ttt, uint, S_IRUGO | S_IWUSR);
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#endif
+
+static void
+l3m_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	faxl3_t *fl3 = fi->userdata;
+	logdata_t log;
+
+	va_start(log.args, fmt);
+	log.fmt = fmt;
+	log.head = fl3->inst.name;
+	mISDN_ctrl(&fl3->inst, MGR_DEBUGDATA | REQUEST, &log);
+	va_end(log.args);
+}
+
+static void
+release_faxl3(faxl3_t *faxl3) {
+	mISDNinstance_t	*inst = &faxl3->inst;
+
+	if (inst->up.peer) {
+		mISDN_ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up);
+	}
+	if (inst->down.peer) {
+		mISDN_ctrl(inst->down.peer, MGR_DISCONNECT | REQUEST, &inst->down);
+	}
+	list_del(&faxl3->list);
+	discard_queue(&faxl3->downq);
+	discard_queue(&faxl3->dataq);
+	discard_queue(&faxl3->pageq);
+	discard_queue(&faxl3->saveq);
+	mISDN_FsmDelTimer(&faxl3->deltimer, 99);
+	mISDN_FsmDelTimer(&faxl3->timer1, 99);
+	mISDN_FsmDelTimer(&faxl3->modtimer, 99);
+	if (faxl3->entity != MISDN_ENTITY_NONE)
+		mISDN_ctrl(inst, MGR_DELENTITY | REQUEST, (void *)faxl3->entity);
+	mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+	kfree(faxl3);
+}
+
+static int
+new_faxl3(mISDNstack_t *st, mISDN_pid_t *pid) {
+	faxl3_t *n_faxl3;
+	u8	*p;
+	int	err;
+
+	if (!st || !pid)
+		return(-EINVAL);
+	if (!(n_faxl3 = kmalloc(sizeof(faxl3_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc faxl3_t failed\n");
+		return(-ENOMEM);
+	}
+	memset(n_faxl3, 0, sizeof(faxl3_t));
+	n_faxl3->entity = MISDN_ENTITY_NONE;
+	n_faxl3->next_id = 1;
+	spin_lock_init(&n_faxl3->lock);
+	memcpy(&n_faxl3->inst.pid, pid, sizeof(mISDN_pid_t));
+	if (n_faxl3->inst.pid.global == 1)
+		test_and_set_bit(FAXL3_STATE_OUTGOING, &n_faxl3->state);
+	p = n_faxl3->inst.pid.param[3];
+	if (p) {
+		if (*p < 6) {
+			int_errtxt("B3cfg too shoort(%d)", *p);
+		} else {
+			n_faxl3->options = CAPIMSG_U16(p, 1);
+			n_faxl3->format = CAPIMSG_U16(p, 3);
+			p += 5;
+			if (*p && (*p <= 20))
+				memcpy(n_faxl3->stationID, p, *p + 1);
+			p += (*p +1);
+			if (*p && (*p <= 62))
+				memcpy(n_faxl3->headline, p, *p + 1);
+		}
+	}
+	if (debug & DEBUG_FAXL3_CFG) {
+		printk(KERN_DEBUG "%s opt(%x) fmt(%x) id=%s head=%s\n",
+			test_bit(FAXL3_STATE_OUTGOING, &n_faxl3->state) ? "out" : "in",
+			n_faxl3->options,
+			n_faxl3->format,
+			&n_faxl3->stationID[1],
+			&n_faxl3->headline[1]);
+		if (n_faxl3->inst.pid.param[1]) {
+			p = n_faxl3->inst.pid.param[1];
+			printk(KERN_DEBUG "B1 param len %d rate %d\n", *p,
+				(*p > 1) ? *((u16 *)(p+1)) : -1);
+		}
+	}
+	mISDN_init_instance(&n_faxl3->inst, &faxl3_obj, n_faxl3);
+	if (!mISDN_SetHandledPID(&faxl3_obj, &n_faxl3->inst.pid)) {
+		int_error();
+		kfree(n_faxl3);
+		return(-ENOPROTOOPT);
+	}
+	n_faxl3->own_rate_mask = FAXMODM_V27_V29_V33_V17; 
+	n_faxl3->current_rate_idx = -1;
+	n_faxl3->current_mod = -1;
+	n_faxl3->current_rate = -1;
+	n_faxl3->pending_mod = -1;
+	n_faxl3->pending_rate = -1;
+	n_faxl3->debug = debug;
+	n_faxl3->main.fsm = &faxl3fsm;
+	n_faxl3->main.state = ST_L3_IDLE;
+	n_faxl3->main.debug = debug;
+	n_faxl3->main.userdata = n_faxl3;
+	n_faxl3->main.userint = 0;
+	n_faxl3->main.printdebug = l3m_debug;
+	mISDN_FsmInitTimer(&n_faxl3->main, &n_faxl3->deltimer);
+	mISDN_FsmInitTimer(&n_faxl3->main, &n_faxl3->timer1);
+
+	n_faxl3->mod.fsm = &modfsm;
+	n_faxl3->mod.state = ST_MOD_NULL;
+	n_faxl3->mod.debug = debug;
+	n_faxl3->mod.userdata = n_faxl3;
+	n_faxl3->mod.userint = 0;
+	n_faxl3->mod.printdebug = l3m_debug;
+	mISDN_FsmInitTimer(&n_faxl3->mod, &n_faxl3->modtimer);
+	skb_queue_head_init(&n_faxl3->downq);
+	skb_queue_head_init(&n_faxl3->dataq);
+	skb_queue_head_init(&n_faxl3->pageq);
+	skb_queue_head_init(&n_faxl3->saveq);
+
+	list_add_tail(&n_faxl3->list, &faxl3_obj.ilist);
+	n_faxl3->entity = MISDN_ENTITY_NONE;
+	err = mISDN_ctrl(&n_faxl3->inst, MGR_NEWENTITY | REQUEST, NULL);
+	if (err) {
+		printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%d)\n",
+			__FUNCTION__, err);
+	}
+	err = mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &n_faxl3->inst);
+	if (err) {
+		list_del(&n_faxl3->list);
+		kfree(n_faxl3);
+	} else {
+		if (st->para.maxdatalen)
+			n_faxl3->maxdatalen = st->para.maxdatalen;
+		if (st->para.up_headerlen)
+			n_faxl3->up_headerlen = st->para.up_headerlen;
+		if (st->para.down_headerlen)
+			n_faxl3->down_headerlen = st->para.down_headerlen;
+		if (debug)
+			printk(KERN_DEBUG "%s:mlen(%d) hup(%d) hdown(%d)\n", __FUNCTION__,
+				n_faxl3->maxdatalen, n_faxl3->up_headerlen, n_faxl3->down_headerlen);
+	}
+	return(err);
+}
+
+static int
+faxl3_manager(void *data, u_int prim, void *arg) {
+	mISDNinstance_t	*inst = data;
+	faxl3_t		*faxl3_l;
+	int		err = -EINVAL;
+
+	if (debug & DEBUG_FAXL3_MGR)
+		printk(KERN_DEBUG "faxl3_manager data:%p prim:%x arg:%p\n", data, prim, arg);
+	if (!data)
+		return(err);
+	list_for_each_entry(faxl3_l, &faxl3_obj.ilist, list) {
+		if (&faxl3_l->inst == inst) {
+			err = 0;
+			break;
+		}
+	}
+	if (prim == (MGR_NEWLAYER | REQUEST))
+		return(new_faxl3(data, arg));
+	if (err) {
+		printk(KERN_WARNING "faxl3_manager prim(%x) no instance\n", prim);
+		return(err);
+	}
+	switch(prim) {
+	    case MGR_CLRSTPARA | INDICATION:
+	    case MGR_CLONELAYER | REQUEST:
+		break;
+	    case MGR_ADDSTPARA | INDICATION:
+		{
+			mISDN_stPara_t *stp = arg;
+
+			if (stp->down_headerlen)
+				faxl3_l->down_headerlen = stp->down_headerlen;
+			if (stp->up_headerlen)
+				faxl3_l->up_headerlen = stp->up_headerlen;
+			printk(KERN_DEBUG "MGR_ADDSTPARA: (%d/%d/%d)\n",
+				stp->maxdatalen, stp->down_headerlen, stp->up_headerlen);
+	    	}
+	    	break;
+	    case MGR_CONNECT | REQUEST:
+		return(mISDN_ConnectIF(inst, arg));
+	    case MGR_NEWENTITY | CONFIRM:
+		faxl3_l->entity = (int)arg;
+		break;
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+		return(mISDN_SetIF(inst, arg, prim, faxl3_from_up, faxl3_from_down, faxl3_l));
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		return(mISDN_DisConnectIF(inst, arg));
+	    case MGR_UNREGLAYER | REQUEST:
+	    case MGR_RELEASE | INDICATION:
+		if (debug & DEBUG_FAXL3_MGR)
+			printk(KERN_DEBUG "release_faxl3 id %x\n", faxl3_l->inst.st->id);
+		release_faxl3(faxl3_l);
+		break;
+	    default:
+		if (debug & DEBUG_FAXL3_MGR)
+			printk(KERN_WARNING "faxl3_manager prim %x not handled\n", prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+static int faxl3_init(void)
+{
+	int err;
+
+	printk(KERN_INFO "%s modul version %s\n", MName, mISDN_getrev(mISDN_faxl3_revision));
+#ifdef MODULE
+	faxl3_obj.owner = THIS_MODULE;
+#endif
+	faxl3_obj.name = MName;
+	faxl3_obj.BPROTO.protocol[3] = ISDN_PID_L3_B_T30;
+	faxl3_obj.own_ctrl = faxl3_manager;
+	INIT_LIST_HEAD(&faxl3_obj.ilist);
+	if ((err = mISDN_register(&faxl3_obj))) {
+		printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
+		return(err);
+	}
+	faxl3fsm.state_count = FAXL3_STATE_COUNT;
+	faxl3fsm.event_count = FAXL3_EVENT_COUNT;
+	faxl3fsm.strEvent = strfaxl3Event;
+	faxl3fsm.strState = strfaxl3State;
+	mISDN_FsmNew(&faxl3fsm, FaxL3FnList, FAXL3_FN_COUNT);
+	modfsm.state_count = MOD_STATE_COUNT;
+	modfsm.event_count = MOD_EVENT_COUNT;
+	modfsm.strEvent = strmodEvent;
+	modfsm.strState = strmodState;
+	mISDN_FsmNew(&modfsm, ModFnList, MOD_FN_COUNT);
+	return(err);
+}
+
+static void faxl3_cleanup(void)
+{
+	faxl3_t	*l3, *nl3;
+	int	err;
+
+	if ((err = mISDN_unregister(&faxl3_obj))) {
+		printk(KERN_ERR "Can't unregister DTMF error(%d)\n", err);
+	}
+	if(!list_empty(&faxl3_obj.ilist)) {
+		printk(KERN_WARNING "faxl3 inst list not empty\n");
+		list_for_each_entry_safe(l3, nl3, &faxl3_obj.ilist, list)
+			release_faxl3(l3);
+	}
+	mISDN_FsmFree(&faxl3fsm);
+	mISDN_FsmFree(&modfsm);
+}
+
+module_init(faxl3_init);
+module_exit(faxl3_cleanup);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/fsm.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/fsm.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/fsm.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,171 @@
+/* $Id: fsm.c,v 1.5 2007/03/21 13:26:56 crich Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/isdn_compat.h>
+#ifdef NEED_JIFFIES_INCLUDE
+#include <linux/jiffies.h>
+#endif
+#include <linux/string.h>
+#include "fsm.h"
+
+#define FSM_TIMER_DEBUG 0
+
+void
+mISDN_FsmNew(struct Fsm *fsm,
+       struct FsmNode *fnlist, int fncount)
+{
+	int i;
+
+	fsm->jumpmatrix = (FSMFNPTR *)
+		kmalloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL);
+	memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
+
+	for (i = 0; i < fncount; i++) 
+		if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) {
+			printk(KERN_ERR "mISDN_FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
+				i,(long)fnlist[i].state,(long)fsm->state_count,
+				(long)fnlist[i].event,(long)fsm->event_count);
+		} else		
+			fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
+				fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
+}
+
+void
+mISDN_FsmFree(struct Fsm *fsm)
+{
+	kfree((void *) fsm->jumpmatrix);
+}
+
+int
+mISDN_FsmEvent(struct FsmInst *fi, int event, void *arg)
+{
+	FSMFNPTR r;
+
+	if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
+		printk(KERN_ERR "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
+			(long)fi->state,(long)fi->fsm->state_count,event,(long)fi->fsm->event_count);
+		return(1);
+	}
+	r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
+	if (r) {
+		if (fi->debug)
+			fi->printdebug(fi, "State %s Event %s",
+				fi->fsm->strState[fi->state],
+				fi->fsm->strEvent[event]);
+		r(fi, event, arg);
+		return (0);
+	} else {
+		if (fi->debug)
+			fi->printdebug(fi, "State %s Event %s no action",
+				fi->fsm->strState[fi->state],
+				fi->fsm->strEvent[event]);
+		return (!0);
+	}
+}
+
+void
+mISDN_FsmChangeState(struct FsmInst *fi, int newstate)
+{
+	fi->state = newstate;
+	if (fi->debug)
+		fi->printdebug(fi, "ChangeState %s",
+			fi->fsm->strState[newstate]);
+}
+
+static void
+FsmExpireTimer(struct FsmTimer *ft)
+{
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug)
+		ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
+#endif
+	mISDN_FsmEvent(ft->fi, ft->event, ft->arg);
+}
+
+void
+mISDN_FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
+{
+	ft->fi = fi;
+	ft->tl.function = (void *) FsmExpireTimer;
+	ft->tl.data = (long) ft;
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug)
+		ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft);
+#endif
+	init_timer(&ft->tl);
+}
+
+void
+mISDN_FsmDelTimer(struct FsmTimer *ft, int where)
+{
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug)
+		ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d", (long) ft, where);
+#endif
+	del_timer(&ft->tl);
+}
+
+int
+mISDN_FsmAddTimer(struct FsmTimer *ft,
+	    int millisec, int event, void *arg, int where)
+{
+
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug)
+		ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d",
+			(long) ft, millisec, where);
+#endif
+
+	if (timer_pending(&ft->tl)) {
+		if (ft->fi->debug) {
+			printk(KERN_WARNING "mISDN_FsmAddTimer: timer already active!\n");
+			ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer already active!");
+		}
+		return -1;
+	}
+	init_timer(&ft->tl);
+	ft->event = event;
+	ft->arg = arg;
+	ft->tl.expires = jiffies + (millisec * HZ) / 1000;
+	add_timer(&ft->tl);
+	return 0;
+}
+
+void
+mISDN_FsmRestartTimer(struct FsmTimer *ft,
+	    int millisec, int event, void *arg, int where)
+{
+
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug)
+		ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d",
+			(long) ft, millisec, where);
+#endif
+
+	if (timer_pending(&ft->tl))
+		del_timer(&ft->tl);
+	init_timer(&ft->tl);
+	ft->event = event;
+	ft->arg = arg;
+	ft->tl.expires = jiffies + (millisec * HZ) / 1000;
+	add_timer(&ft->tl);
+}
+
+EXPORT_SYMBOL(mISDN_FsmNew);
+EXPORT_SYMBOL(mISDN_FsmFree);
+EXPORT_SYMBOL(mISDN_FsmEvent);
+EXPORT_SYMBOL(mISDN_FsmChangeState);
+EXPORT_SYMBOL(mISDN_FsmInitTimer);
+EXPORT_SYMBOL(mISDN_FsmAddTimer);
+EXPORT_SYMBOL(mISDN_FsmRestartTimer);
+EXPORT_SYMBOL(mISDN_FsmDelTimer);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/fsm.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/fsm.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/fsm.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,54 @@
+/* $Id: fsm.h,v 1.2 2004/01/30 23:46:37 keil Exp $
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#ifndef _MISDN_FSM_H
+#define _MISDN_FSM_H
+
+#include <linux/timer.h>
+
+/* Statemachine */
+
+struct FsmInst;
+
+typedef void (* FSMFNPTR)(struct FsmInst *, int, void *);
+
+struct Fsm {
+	FSMFNPTR *jumpmatrix;
+	int state_count, event_count;
+	char **strEvent, **strState;
+};
+
+struct FsmInst {
+	struct Fsm *fsm;
+	int state;
+	int debug;
+	void *userdata;
+	int userint;
+	void (*printdebug) (struct FsmInst *, char *, ...);
+};
+
+struct FsmNode {
+	int state, event;
+	void (*routine) (struct FsmInst *, int, void *);
+};
+
+struct FsmTimer {
+	struct FsmInst *fi;
+	struct timer_list tl;
+	int event;
+	void *arg;
+};
+
+extern void mISDN_FsmNew(struct Fsm *, struct FsmNode *, int);
+extern void mISDN_FsmFree(struct Fsm *);
+extern int mISDN_FsmEvent(struct FsmInst *, int , void *);
+extern void mISDN_FsmChangeState(struct FsmInst *, int);
+extern void mISDN_FsmInitTimer(struct FsmInst *, struct FsmTimer *);
+extern int mISDN_FsmAddTimer(struct FsmTimer *, int, int, void *, int);
+extern void mISDN_FsmRestartTimer(struct FsmTimer *, int, int, void *, int);
+extern void mISDN_FsmDelTimer(struct FsmTimer *, int);
+
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/helper.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/helper.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/helper.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,413 @@
+/* $Id: helper.c,v 1.16 2006/08/07 23:35:59 keil Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mISDNif.h>
+#include "helper.h"
+
+#undef	DEBUG_LM
+#undef	DEBUG_IF
+
+void
+mISDN_set_dchannel_pid(mISDN_pid_t *pid, int protocol, int layermask)
+{
+	if (!layermask)
+		layermask = ISDN_LAYER(0)| ISDN_LAYER(1) | ISDN_LAYER(2) |
+			ISDN_LAYER(3) | ISDN_LAYER(4);
+	
+	memset(pid, 0, sizeof(mISDN_pid_t));
+	pid->layermask = layermask;
+	pid->modparm_protocol = protocol;
+	if (layermask & ISDN_LAYER(0))
+		pid->protocol[0] = ISDN_PID_L0_TE_S0;
+	if (layermask & ISDN_LAYER(1))
+		pid->protocol[1] = ISDN_PID_L1_TE_S0;
+	if (layermask & ISDN_LAYER(2)) {
+		pid->protocol[2] = ISDN_PID_L2_LAPD;
+		if (protocol & 0x20)
+			pid->protocol[2] |= ISDN_PID_L2_DF_PTP;
+	}
+	if (layermask & ISDN_LAYER(3)) {
+		if ((protocol & 0xf) == 2)
+			pid->protocol[3] = ISDN_PID_L3_DSS1USER;
+		if (protocol & 0x20)
+			pid->protocol[3] |= ISDN_PID_L3_DF_PTP;
+	}
+	if (layermask & ISDN_LAYER(4))
+		pid->protocol[4] = ISDN_PID_L4_CAPI20;
+}
+
+
+int
+mISDN_add_pid_parameter(mISDN_pid_t *pid, int layer, u_char *para)
+{
+	u16	l;
+
+	if (para == NULL || *para == 0) {
+		pid->param[layer] = 0;
+		return 0;
+	}
+	l = 1 + *para;	/* including length itself */
+	if (!pid->pbuf) {
+		pid->maxplen = l + 1; /* pbuf[0] is never used */
+		if (l < 63)
+			pid->maxplen = 64;
+		pid->pbuf = kzalloc(pid->maxplen, GFP_ATOMIC);
+		pid->pidx = 1;
+		if (!pid->pbuf) {
+			pid->maxplen = 0;
+			return -ENOMEM;
+		}
+	} else if ((pid->pidx + l) > pid->maxplen) {
+		u_char *tbuf;
+		
+		tbuf = kmalloc(pid->pidx + l, GFP_ATOMIC);
+		if (!tbuf)
+			return -ENOMEM;
+		memcpy(tbuf, pid->pbuf, pid->pidx);
+		kfree(pid->pbuf);
+		pid->pbuf = tbuf;
+		pid->maxplen = pid->pidx + l;
+	}
+	pid->param[layer] = pid->pidx;
+	memcpy(&pid->pbuf[pid->pidx], para, l);
+	pid->pidx += l;
+	return 0;
+}
+
+int
+mISDN_bprotocol2pid(void *bp, mISDN_pid_t *pid)
+{
+	u8	*p = bp;
+	u16	*w = bp;
+	int	i, ret;
+	
+
+	p += 6;
+	for (i=1; i<=3; i++) {
+		if (*w > 23) {
+			int_errtxt("L%d pid %x\n",i,*w);
+			return -EINVAL;
+		}
+		pid->protocol[i] = (1 <<*w) | ISDN_PID_LAYER(i) |
+			ISDN_PID_BCHANNEL_BIT;
+		ret = mISDN_add_pid_parameter(pid, i, p);
+		if (ret)
+			return ret;
+		w++;
+		p += *p;
+		p++;
+	}
+	pid->global = 0;
+	if (*p == 2) { // len of 1 word
+		p++;
+		w = (u16 *)p;
+		pid->global = *w;
+	}
+	return 0;
+}
+
+int
+mISDN_HasProtocol(mISDNobject_t *obj, u_int protocol)
+{
+	int layer;
+	u_int pmask;
+
+	if (!obj) {
+		int_error();
+		return(-EINVAL);
+	}
+	layer = (protocol & ISDN_PID_LAYER_MASK)>>24;
+	if (layer > MAX_LAYER_NR) {
+		int_errtxt("layer %d", layer);
+		return(-EINVAL);
+	}
+	if (protocol & ISDN_PID_BCHANNEL_BIT)
+		pmask = obj->BPROTO.protocol[layer];
+	else
+		pmask = obj->DPROTO.protocol[layer];
+	if (pmask == ISDN_PID_ANY)
+		return(-EPROTO);
+	if (protocol == (protocol & pmask))
+		return(0);
+	else
+		return(-ENOPROTOOPT); 
+}
+
+int
+mISDN_SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
+{
+	int layer;
+	int ret = 0;
+	mISDN_pid_t sav;
+
+	if (!obj || !pid) {
+		int_error();
+		return(0);
+	}
+#ifdef DEBUG_LM
+	printk(KERN_DEBUG "%s: %s LM(%x)\n", __FUNCTION__, obj->name, pid->layermask);
+#endif
+	memcpy(&sav, pid, sizeof(mISDN_pid_t));
+	memset(pid, 0, sizeof(mISDN_pid_t));
+	pid->pbuf = sav.pbuf;
+	pid->maxplen = sav.maxplen;
+	pid->pidx = sav.pidx;
+	pid->global = sav.global;
+	if (!sav.layermask) {
+		printk(KERN_WARNING "%s: no layermask in pid\n", __FUNCTION__);
+		return(0);
+	}
+	for (layer=0; layer<=MAX_LAYER_NR; layer++) {
+		if (!(ISDN_LAYER(layer) & sav.layermask)) {
+			if (ret)
+				break;
+			else
+				continue;
+		}
+		if (0 == mISDN_HasProtocol(obj, sav.protocol[layer])) {
+			ret++;
+			pid->protocol[layer] = sav.protocol[layer];
+			pid->param[layer] = sav.param[layer];
+			pid->layermask |= ISDN_LAYER(layer);
+		} else
+			break;
+	}
+	return(ret);
+}
+
+void
+mISDN_RemoveUsedPID(mISDN_pid_t *pid, mISDN_pid_t *used)
+{
+	int layer;
+
+	if (!used || !pid) {
+		int_error();
+		return;
+	}
+	if (!used->layermask)
+		return;
+	
+	for (layer=0; layer<=MAX_LAYER_NR; layer++) {
+		if (!(ISDN_LAYER(layer) & used->layermask))
+				continue;
+		pid->protocol[layer] = ISDN_PID_NONE;
+		pid->param[layer] = 0;
+		pid->layermask &= ~(ISDN_LAYER(layer));
+	}
+}
+
+int
+mISDN_layermask2layer(int layermask) {
+	switch(layermask) {
+		case ISDN_LAYER(0): return(0);
+		case ISDN_LAYER(1): return(1);
+		case ISDN_LAYER(2): return(2);
+		case ISDN_LAYER(3): return(3);
+		case ISDN_LAYER(4): return(4);
+		case ISDN_LAYER(5): return(5);
+		case ISDN_LAYER(6): return(6);
+		case ISDN_LAYER(7): return(7);
+		case 0:	return(-1);
+	}
+	return(-2);
+}
+
+int
+mISDN_get_protocol(mISDNstack_t *st, int layer)
+{
+
+	if (!st){
+		int_error();
+		return(-EINVAL);
+	}
+	if (LAYER_OUTRANGE(layer)) {
+		int_errtxt("L%d st(%x)", layer, st->id);
+		return(-EINVAL);
+	}
+	return(st->pid.protocol[layer]);
+}
+
+int
+mISDN_get_lowlayer(int layermask)
+{
+	int layer;
+
+	if (!layermask)
+		return(0);
+	for (layer=0; layer <= MAX_LAYER_NR; layer++)
+		if (layermask & ISDN_LAYER(layer))
+			return(layer);
+	return(0);
+}
+
+int
+mISDN_get_down_layer(int layermask)
+{
+	int downlayer = 1;
+	
+	if (layermask>255 || (layermask & 1)) {
+		int_errtxt("lmask %x out of range", layermask);
+		return(0);
+	}
+	while(downlayer <= MAX_LAYER_NR) {
+		if (ISDN_LAYER(downlayer) & layermask)
+			break;
+		downlayer++;
+	}
+	downlayer--;
+	return(downlayer);
+}
+
+int
+mISDN_get_up_layer(int layermask) {
+	int uplayer = MAX_LAYER_NR;
+	
+	if (layermask>=128) {
+		int_errtxt("lmask %x out of range", layermask);
+		return(0);
+	}
+	while(uplayer>=0) {
+		if (ISDN_LAYER(uplayer) & layermask)
+			break;
+		uplayer--;
+	}
+	uplayer++;
+	return(uplayer);
+}
+
+#ifdef OBSOLETE
+int
+mISDN_SetIF(mISDNinstance_t *owner, mISDNif_t *hif, u_int prim, void *upfunc,
+	void *downfunc, void *data)
+{
+	mISDNif_t *own_hif;
+
+	if (!owner) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (!hif) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (IF_TYPE(hif) == IF_UP) {
+		hif->func = upfunc;
+		own_hif = &owner->up;
+#ifdef DEBUG_IF
+		printk(KERN_DEBUG "%s: IF_UP: func:%p(%p)\n", __FUNCTION__, hif->func, owner->data);
+#endif
+	} else if (IF_TYPE(hif) == IF_DOWN) {
+		hif->func = downfunc;
+		own_hif = &owner->down;
+#ifdef DEBUG_IF
+		printk(KERN_DEBUG "%s: IF_DOWN: func:%p(%p)\n", __FUNCTION__, hif->func, owner->data);
+#endif
+	} else {
+		int_errtxt("stat(%x)", hif->stat);
+		return(-EINVAL);
+	}
+	hif->peer = owner;
+	hif->fdata = data;
+	if ((prim & SUBCOMMAND_MASK) == REQUEST) {
+		if (own_hif->stat == IF_NOACTIV) {
+			if (IF_TYPE(hif) == IF_UP)
+				own_hif->stat = IF_DOWN;
+			else
+				own_hif->stat = IF_UP;
+			own_hif->owner = owner;
+			return(hif->owner->obj->own_ctrl(hif->owner,
+				MGR_SETIF | INDICATION, own_hif));
+		} else {
+			int_errtxt("REQ own stat(%x)", own_hif->stat);
+			return(-EBUSY);
+		}
+	}
+	return(0);
+}
+
+int
+mISDN_ConnectIF(mISDNinstance_t *owner, mISDNinstance_t *peer)
+{
+	mISDNif_t *hif;
+
+	if (!owner) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (!peer) {
+		int_error();
+		return(-EINVAL);
+	}
+	
+	if (owner->pid.layermask < peer->pid.layermask) {
+		hif = &owner->up;
+		hif->owner = owner;
+		hif->stat = IF_DOWN;
+	} else if (owner->pid.layermask > peer->pid.layermask) {
+		hif = &owner->down;
+		hif->owner = owner;
+		hif->stat = IF_UP;
+	} else {
+		int_errtxt("OLM == PLM: %x", owner->pid.layermask);
+		return(-EINVAL);
+	}
+	return(peer->obj->own_ctrl(peer, MGR_SETIF | REQUEST, hif));
+}
+
+int
+mISDN_DisConnectIF(mISDNinstance_t *inst, mISDNif_t *hif) {
+	if (hif) {
+		if (hif->clone) {
+			if (hif->clone->owner)
+				hif->clone->owner->obj->ctrl(hif->clone->owner,
+					MGR_DISCONNECT | REQUEST, hif->clone);
+		}	
+		if (inst->up.peer) {
+			if (inst->up.peer == hif->owner)
+				inst->up.peer->obj->ctrl(inst->up.peer,
+					MGR_DISCONNECT | INDICATION, &inst->up);
+		}
+		if (inst->down.peer) {
+			if (inst->down.peer == hif->owner)
+				inst->down.peer->obj->ctrl(inst->down.peer,
+					MGR_DISCONNECT | INDICATION, &inst->down);
+		}
+	}
+	return(0);
+}
+#endif
+
+void
+mISDN_init_instance(mISDNinstance_t *inst, mISDNobject_t *obj, void *data, if_func_t *function)
+{
+	if (!obj) {
+		int_error();
+		return;
+	}
+	INIT_LIST_HEAD(&inst->list);
+	inst->obj = obj;
+	inst->privat = data;
+	inst->function = function;
+}
+
+EXPORT_SYMBOL(mISDN_set_dchannel_pid);
+EXPORT_SYMBOL(mISDN_get_lowlayer);
+EXPORT_SYMBOL(mISDN_get_up_layer);
+EXPORT_SYMBOL(mISDN_get_down_layer);
+EXPORT_SYMBOL(mISDN_layermask2layer);
+EXPORT_SYMBOL(mISDN_get_protocol);
+EXPORT_SYMBOL(mISDN_HasProtocol);
+EXPORT_SYMBOL(mISDN_SetHandledPID);
+EXPORT_SYMBOL(mISDN_RemoveUsedPID);
+EXPORT_SYMBOL(mISDN_init_instance);
+// EXPORT_SYMBOL(mISDN_SetIF);
+// EXPORT_SYMBOL(mISDN_ConnectIF);
+// EXPORT_SYMBOL(mISDN_DisConnectIF);
+EXPORT_SYMBOL(mISDN_add_pid_parameter);
+EXPORT_SYMBOL(mISDN_bprotocol2pid);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/helper.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/helper.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/helper.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,298 @@
+/* $Id: helper.h,v 1.16 2006/08/07 23:35:59 keil Exp $
+ *
+ *   Basic declarations, defines and prototypes
+ *
+ * This file is released under the GPLv2
+ *
+ */
+#ifndef _mISDN_HELPER_H
+#define	_mISDN_HELPER_H
+#include <linux/kernel.h>
+#ifdef MISDN_MEMDEBUG
+#include "memdbg.h"
+#endif
+
+/* shortcut to report errors locations, sometime also used for debugging !FIXME! */
+#define int_error() \
+        printk(KERN_ERR "mISDN: INTERNAL ERROR in %s:%d\n", \
+                       __FILE__, __LINE__)
+
+/* shortcut to report errors locations with an additional message text */
+#define int_errtxt(fmt, arg...) \
+        printk(KERN_ERR "mISDN: INTERNAL ERROR in %s:%d " fmt "\n", \
+                       __FILE__, __LINE__, ## arg)
+                       
+/* cleanup SKB queues, return count of dropped packets */
+static inline int
+discard_queue(struct sk_buff_head *q)
+{
+	struct sk_buff *skb;
+	int ret=0;
+
+	while ((skb = skb_dequeue(q))) {
+		dev_kfree_skb(skb);
+		ret++;
+	}
+	return(ret);
+}
+
+/* allocate a SKB for DATA packets in the mISDN stack with enough headroom
+ * the MEMDEBUG version is for debugging memory leaks in the mISDN stack
+ */
+ 
+#ifdef MISDN_MEMDEBUG
+#define alloc_stack_skb(s, r)	__mid_alloc_stack_skb(s, r, __FILE__, __LINE__)
+static inline struct sk_buff *
+__mid_alloc_stack_skb(u_int size, u_int reserve, char *fn, int line)
+{
+	struct sk_buff *skb;
+
+	if (!(skb = __mid_alloc_skb(size + reserve, GFP_ATOMIC, fn, line)))
+#else
+static inline struct sk_buff *
+alloc_stack_skb(u_int size, u_int reserve)
+{
+	struct sk_buff *skb;
+
+	if (!(skb = alloc_skb(size + reserve, GFP_ATOMIC)))
+#endif
+		printk(KERN_WARNING "%s(%d,%d): no skb size\n", __FUNCTION__,
+			size, reserve);
+	else
+		skb_reserve(skb, reserve);
+	return(skb);
+}
+
+/* 
+ * mISDN_set_dchannel_pid(mISDN_pid_t *pid, int protocol, int layermask)
+ *
+ * set default values for the D-channel protocol ID struct
+ *
+ * layermask - bitmask which layers should be set (default 0,1,2,3,4)
+ * protocol  - bitmask for special L2/L3 option (from protocol module parameter of L0 modules)
+ */
+extern void	mISDN_set_dchannel_pid(mISDN_pid_t *, int, int);
+
+/*
+ * int mISDN_get_lowlayer(int layermask)
+ *
+ * get the lowest layer number of a layermask
+ * e.g layermask=0x0c returns 2
+ */ 
+extern int	mISDN_get_lowlayer(int);
+
+/*
+ * int mISDN_get_up_layer(int layermask)
+ *
+ * get the next higher layer number, which is not part of the given layermask
+ */
+extern int	mISDN_get_up_layer(int);
+
+/*
+ * int mISDN_get_down_layer(int layermask)
+ *
+ * get the next lower layer number, which is not part of the given layermask
+ */
+extern int	mISDN_get_down_layer(int);
+
+/*
+ * int mISDN_layermask2layer(int layermask)
+ *
+ * translate bit position in layermask into the layernumber
+ * only valid if only one bit in the mask was set
+ */
+extern int	mISDN_layermask2layer(int);
+
+/*
+ * int mISDN_get_protocol(mISDNstack_t *st, int layer)
+ *
+ * get the protocol value of layer <layer> in stack <st>
+ */
+extern int	mISDN_get_protocol(mISDNstack_t *, int);
+
+/*
+ * int mISDN_HasProtocol(mISDNobject_t *obj, u_int protocol)
+ *
+ * test if given object can handle protocol <protocol>
+ *
+ * return 0 if yes
+ *
+ */
+extern int	mISDN_HasProtocol(mISDNobject_t *, u_int);
+
+/*
+ * int mISDN_SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
+ *
+ * returns the layermask of the supported protocols of object <obj>
+ * from the protocol ID struct <pid>
+ */
+extern int	mISDN_SetHandledPID(mISDNobject_t *, mISDN_pid_t *);
+
+/*
+ * mISDN_RemoveUsedPID(mISDN_pid_t *pid, mISDN_pid_t *used)
+ *
+ * remove the protocol values from <pid> struct which are also in the
+ * <used> struct
+ */
+extern void	mISDN_RemoveUsedPID(mISDN_pid_t *, mISDN_pid_t *);
+
+/*
+ * mISDN_init_instance(mISDNinstance_t *inst, mISDNobject_t *obj, void *data)
+ *
+ * initialisize the mISDNinstance_t struct <inst>
+ */ 
+extern void	mISDN_init_instance(mISDNinstance_t *, mISDNobject_t *, void *, if_func_t *);
+
+/* returns the member count of a list */
+static inline int
+count_list_member(struct list_head *head)
+{
+	int			cnt = 0;
+	struct list_head	*m;
+
+	list_for_each(m, head)
+		cnt++;
+	return(cnt);
+}
+
+/* same as mISDN_HasProtocol, but for a pointer */
+static inline int
+mISDN_HasProtocolP(mISDNobject_t *obj, int *PP)
+{
+	if (!PP) {
+		int_error();
+		return(-EINVAL);
+	}
+	return(mISDN_HasProtocol(obj, *PP));
+}
+
+/* set primitiv and dinfo field of a internal (SKB) mISDN message */
+static inline void
+mISDN_sethead(u_int prim, int dinfo, struct sk_buff *skb)
+{
+	mISDN_head_t *hh = mISDN_HEAD_P(skb);
+
+	hh->prim = prim;
+	hh->dinfo = dinfo;
+}
+
+#define mISDN_queue_up(i, a, s)		mISDN_queue_message(i, a | FLG_MSG_UP, s)
+#define mISDN_queue_down(i, a, s)	mISDN_queue_message(i, a | FLG_MSG_DOWN, s)
+
+static inline int
+mISDN_queueup_newhead(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, struct sk_buff *skb)
+{
+	mISDN_head_t *hh = mISDN_HEAD_P(skb);
+
+	hh->prim = prim;
+	hh->dinfo = dinfo;
+	return(mISDN_queue_up(inst, aflag, skb));
+}
+
+static inline int
+mISDN_queuedown_newhead(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, struct sk_buff *skb)
+{
+	mISDN_head_t *hh = mISDN_HEAD_P(skb);
+
+	hh->prim = prim;
+	hh->dinfo = dinfo;
+	return(mISDN_queue_down(inst, aflag, skb));
+}
+
+
+/* allocate a mISDN message SKB with enough headroom and set the header fields
+ * the MEMDEBUG version is for debugging memory leaks in the mISDN stack
+ */
+#ifdef MISDN_MEMDEBUG
+#define create_link_skb(p, d, l, dp, r)	__mid_create_link_skb(p, d, l, dp, r, __FILE__, __LINE__)
+static inline struct sk_buff *
+__mid_create_link_skb(u_int prim, int dinfo, u_int len, void *dp, u_int reserve, char *fn, int line)
+{
+	struct sk_buff	*skb;
+	mISDN_head_t	*hh;
+
+	if (!(skb = __mid_alloc_skb(len + reserve, GFP_ATOMIC, fn, line))) {
+#else
+static inline struct sk_buff *
+create_link_skb(u_int prim, int dinfo, u_int len, void *dp, u_int reserve)
+{
+	struct sk_buff	*skb;
+	mISDN_head_t	*hh;
+
+	if (!(skb = alloc_skb(len + reserve, GFP_ATOMIC))) {
+#endif
+		printk(KERN_WARNING "%s: no skb size %d+%d\n",
+			__FUNCTION__, len, reserve);
+		return(NULL);
+	} else
+		skb_reserve(skb, reserve);
+	if (len)
+		memcpy(skb_put(skb, len), dp, len);
+	hh = mISDN_HEAD_P(skb);
+	hh->prim = prim;
+	hh->dinfo = dinfo;
+	hh->len = len;
+	return(skb);
+}
+
+/* allocate a SKB for a mISDN message with enough headroom
+ * fill mesage data into this SKB and send it trough the interface
+ * the MEMDEBUG version is for debugging memory leaks in the mISDN stack
+ */
+#ifdef MISDN_MEMDEBUG
+#define mISDN_queue_data(i, a, p, d, l, dp, r)	__mid_queue_data(i, a, p, d, l, dp, r, __FILE__, __LINE__)
+static inline int
+__mid_queue_data(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, u_int len, void *dp, u_int reserve, char *fn, int line)
+{
+	struct sk_buff	*skb;
+	int		err;
+
+	if (!(skb = __mid_create_link_skb(prim, dinfo, len, dp, reserve, fn, line)))
+#else
+static inline int
+mISDN_queue_data(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, u_int len, void *dp, u_int reserve)
+{
+	struct sk_buff	*skb;
+	int		err;
+
+	if (!(skb = create_link_skb(prim, dinfo, len, dp, reserve)))
+#endif
+		return(-ENOMEM);
+	err = mISDN_queue_message(inst, aflag, skb);
+	if (err)
+		kfree_skb(skb);
+	return(err);
+}
+
+/* L3 data struct helper functions */
+
+extern	signed int	mISDN_l3_ie2pos(u_char);
+extern	unsigned char	mISDN_l3_pos2ie(int);
+extern	void		mISDN_initQ931_info(Q931_info_t *);
+#ifdef MISDN_MEMDEBUG
+#define mISDN_alloc_l3msg(a, b)	__mid_alloc_l3msg(a, b, __FILE__, __LINE__)
+extern	struct sk_buff 	*__mid_alloc_l3msg(int, u_char, char *, int);
+#else
+extern	struct sk_buff 	*mISDN_alloc_l3msg(int, u_char);
+#endif
+extern	void		mISDN_AddvarIE(struct sk_buff *, u_char *);
+extern	void		mISDN_AddIE(struct sk_buff *, u_char, u_char *);
+extern	ie_info_t	*mISDN_get_last_repeated_ie(Q931_info_t *, ie_info_t *);
+extern	int		mISDN_get_free_ext_ie(Q931_info_t *);
+extern	void		mISDN_LogL3Msg(struct sk_buff *);
+extern	int		mISDN_add_pid_parameter(mISDN_pid_t *, int, u_char *);
+
+/* manager default handler helper macros */
+
+#define PRIM_NOT_HANDLED(p)	case p: break
+
+#define MGR_HASPROTOCOL_HANDLER(p,a,o)	\
+	if ((MGR_HASPROTOCOL | REQUEST) == p) {\
+		if (a) {\
+			int prot = *((int *)a);\
+			return(mISDN_HasProtocol(o, prot));\
+		} else \
+			return(-EINVAL);\
+	}
+
+#endif /* _mISDN_HELPER_H */

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_multi.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_multi.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_multi.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,4611 @@
+/*
+ * hfc_multi.c  low level driver for hfc-4s/hfc-8s/hfc-e1 based cards
+ *
+ * Author	Andreas Eversberg (jolly at eversberg.eu)
+ * ported to mqueue mechanism:
+ * 		Peter Sprenger (sprengermoving-bytes.de)
+ *
+ * inspired by existing hfc-pci driver:
+ * Copyright 1999  by Werner Cornelius (werner at isdn-development.de)
+ * Copyright 2001  by Karsten Keil (keil at 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.
+ *
+ *
+ * Thanks to Cologne Chip AG for this great controller!
+ */
+
+/* module parameters:
+ * type:
+	Value 1	= HFC-E1 (1 port) 0x01
+	Value 4	= HFC-4S (4 ports) 0x04
+	Value 8	= HFC-8S (8 ports) 0x08
+	Bit 8	= uLaw (instead of aLaw)
+	Bit 9	= Enable DTMF detection on all B-channels
+	Bit 10	= spare
+	Bit 11	= Set PCM bus into slave mode.
+	Bit 12	= Ignore missing frame clock on PCM bus.
+	Bit 13	= Use direct RX clock for PCM sync rather than PLL. (E1 only)
+	Bit 14	= Use external ram (128K)
+	Bit 15	= Use external ram (512K)
+	Bit 16	= Use 64 timeslots instead of 32
+	Bit 17	= Use 128 timeslots instead of anything else
+	Bit 18	= Use crystal clock for PCM and E1, for autarc clocking.
+	Bit 19	= Send the Watchdog a Signal (Dual E1 with Watchdog)
+
+ * protocol:
+	NOTE: Must be given for all ports, not for the number of cards.
+	HFC-4S/HFC-8S/HFC-E1 bits:
+ 	Bit 0-3 = protocol
+	Bit 4	= NT-Mode
+	Bit 5	= PTP (instead of multipoint)
+
+	HFC-4S/HFC-8S only bits:
+	Bit 16	= Use master clock for this S/T interface (ony once per chip).
+	Bit 17	= transmitter line setup (non capacitive mode) DONT CARE!
+	Bit 18	= Disable E-channel. (No E-channel processing)
+
+	HFC-E1 only bits:
+	Bit 16	= interface: 0=copper, 1=optical
+	Bit 17	= reserved (later for 32 B-channels transparent mode)
+	Bit 18	= Report LOS
+	Bit 19	= Report AIS
+	Bit 20	= Report SLIP
+	Bit 21-22 = elastic jitter buffer (1-3), Use 0 for default.
+	Bit 23  = Turn off CRC-4 Multiframe Mode, use double frame mode instead.
+(all other bits are reserved and shall be 0)
+
+ * layermask:
+	NOTE: Must be given for all ports, not for the number of cards.
+	mask of layers to be used for D-channel stack
+
+ * debug:
+	NOTE: only one debug value must be given for all cards
+	enable debugging (see hfc_multi.h for debug options)
+
+ * poll:
+	NOTE: only one poll value must be given for all cards
+	Give the number of samples for each fifo process.
+	By default 128 is used. Decrease to reduce delay, increase to
+	reduce cpu load. If unsure, don't mess with it!
+	Valid is 8, 16, 32, 64, 128, 256.
+
+ * pcm:
+	NOTE: only one pcm value must be given for all cards
+	Give the id of the PCM bus. All PCM busses with the same ID
+	are expected to be connected and have equal slots.
+	Only one chip of the PCM bus must be master, the others slave.
+	-1 means no support of PCM bus.
+ */
+
+/* debug using register map (never use this, it will flood your system log) */
+//#define HFC_REGISTER_MAP
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "core.h"
+#include "channel.h"
+#include "layer1.h"
+#include "dsp.h"
+#include "debug.h"
+#include <linux/isdn_compat.h>
+
+//#warning
+//#define IRQCOUNT_DEBUG
+
+#include "hfc_multi.h"
+#ifdef ECHOPREP
+#include "gaintab.h"
+#endif
+
+//#warning
+
+#define bugtest {}
+#if 0
+#define bugtest \
+	if (hc->irq) free_irq(hc->irq, hc); \
+	hc->irq = 0; \
+	if (request_irq(hc->pci_dev->irq, hfcmulti_interrupt, SA_SHIRQ, "HFC-multi", hc)) { \
+		printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", hc->pci_dev->irq); \
+	hc->irq = hc->pci_dev->irq; }
+#endif
+		
+static void ph_state_change(channel_t *ch);
+
+extern const char *CardType[];
+
+static const char *hfcmulti_revision = "$Revision: 1.68 $";
+
+static int HFC_cnt;
+
+static mISDNobject_t	HFCM_obj;
+
+static char HFCName[] = "HFC_multi";
+
+extern void ztdummy_extern_interrupt(void);
+static void (* hfc_interrupt)(void);
+extern void ztdummy_register_interrupt(void);
+static void (* register_interrupt)(void);
+
+/* table entry in the PCI devices list */
+typedef struct {
+	int vendor_id;
+	int vendor_sub;
+	int device_id;
+	int device_sub;
+	char *vendor_name;
+	char *card_name;
+	int type;
+	int ports;
+	int clock2;
+	int leds;
+	int opticalsupport;
+} PCI_ENTRY;
+
+static int poll_timer = 6;	/* default = 128 samples = 16ms */
+/* number of POLL_TIMER interrupts for G2 timeout (min 120ms) */
+static int nt_t1_count[] = { 480, 240, 120, 60, 30, 15, 8, 4 };
+#define CLKDEL_TE	0x0f	/* CLKDEL in TE mode */
+#define CLKDEL_NT	0x0c	/* CLKDEL in NT mode (0x60 MUST not be included!) */
+static u_char silence =	0xff;	/* silence by LAW */
+
+/* enable 32 bit fifo access (PC usage) */
+#define FIFO_32BIT_ACCESS
+
+#define VENDOR_CCD "Cologne Chip AG"
+#define CCAG_VID 0x1397      // Cologne Chip Vendor ID
+#define HFC4S_ID 0x08B4
+#define HFC8S_ID 0x16B8
+#define HFCE1_ID 0x30B1
+
+static const PCI_ENTRY id_list[] =
+{
+#if 0
+	{CCAG_VID, 0xffffffff, HFC4S_ID, 0xffffffff, VENDOR_CCD,
+	 "HFC-4S CCAG Eval", 4, 1, 2},
+	{CCAG_VID, 0xffffffff, HFC8S_ID, 0xffffffff, VENDOR_CCD,
+	 "HFC-8S CCAG Eval", 8, 1, 0},
+	{CCAG_VID, 0xffffffff, HFCE1_ID, 0xffffffff, VENDOR_CCD,
+	 "HFC-E1 CCAG Eval", 1, 0, 1}, /* E1 only supports single clock */
+#endif
+	{CCAG_VID, CCAG_VID, HFC4S_ID, 0x08B4, VENDOR_CCD,
+	 "HFC-4S CCAG Eval (old)", 0, 4, 0, 0, 0},
+	{CCAG_VID, CCAG_VID, HFC8S_ID, 0x16B8, VENDOR_CCD,
+	 "HFC-8S CCAG Eval (old)", 0, 8, 0, 0, 0},
+	{CCAG_VID, CCAG_VID, HFCE1_ID, 0x30B1, VENDOR_CCD,
+	 "HFC-E1 CCAG Eval (old)", 1, 1, 0, 0, 0},
+	{CCAG_VID, CCAG_VID, HFC4S_ID, 0xB520, VENDOR_CCD,
+	 "HFC-4S IOB4ST", 0, 4, 1, 2, 0},
+	{CCAG_VID, CCAG_VID, HFC4S_ID, 0xB620, VENDOR_CCD,
+	 "HFC-4S", 0, 4, 1, 2, 0},
+	{CCAG_VID, CCAG_VID, HFC4S_ID, 0xB550, VENDOR_CCD,
+	 "HFC-4S (junghanns 2.0)", 0, 4, 1, 2, 0},
+	{CCAG_VID, CCAG_VID, HFC4S_ID, 0xB560, VENDOR_CCD,
+	 "HFC-4S Beronet Card", 0, 4, 1, 2, 0},
+	{CCAG_VID, CCAG_VID, HFC4S_ID, 0xB568, VENDOR_CCD,
+	 "HFC-4S Beronet Card (mini PCI)", 0, 4, 1, 2, 0},
+	{0xD161, 0xD161, 0xB410, 0xB410, VENDOR_CCD,
+	 "HFC-4S Digium Card", 0, 4, 0, 2, 0},
+	{CCAG_VID, CCAG_VID, HFC4S_ID, 0xB540, VENDOR_CCD,
+	 "HFC-4S Swyx 4xS0 SX2 QuadBri", 0, 4, 1, 2, 0},
+	{CCAG_VID, CCAG_VID, HFC8S_ID, 0xB521, VENDOR_CCD,
+	 "HFC-8S IOB4ST Recording", 0, 8, 1, 0, 0},
+	{CCAG_VID, CCAG_VID, HFC8S_ID, 0xB522, VENDOR_CCD,
+	 "HFC-8S IOB8ST", 0, 8, 1, 0, 0},
+	{CCAG_VID, CCAG_VID, HFC8S_ID, 0xB552, VENDOR_CCD,
+	 "HFC-8S", 0, 8, 1, 0, 0},
+	{CCAG_VID, CCAG_VID, HFC8S_ID, 0xB622, VENDOR_CCD,
+	 "HFC-8S", 0, 8, 1, 0, 0},
+	{CCAG_VID, CCAG_VID, HFC8S_ID, 0xB562, VENDOR_CCD,
+	 "HFC-8S Beronet Card", 0, 8, 1, 0, 0},
+	{CCAG_VID, CCAG_VID, HFC8S_ID, 0xB56B, VENDOR_CCD,
+	 "HFC-8S Beronet Card (+)", 0, 8, 1, 8, 0},
+	{CCAG_VID, CCAG_VID, HFCE1_ID, 0xB523, VENDOR_CCD,
+	 "HFC-E1 IOB1E1", 1, 1, 0, 1, 0}, /* E1 only supports single clock */
+	{CCAG_VID, CCAG_VID, HFCE1_ID, 0xC523, VENDOR_CCD,
+	 "HFC-E1", 1, 1, 0, 1, 0}, /* E1 only supports single clock */
+	{CCAG_VID, CCAG_VID, HFCE1_ID, 0xB56A, VENDOR_CCD,
+	 "HFC-E1 Beronet Card (mini PCI)", 1, 1, 0, 1, 0}, /* E1 only supports single clock */
+	{CCAG_VID, CCAG_VID, HFCE1_ID, 0xB563, VENDOR_CCD,
+	 "HFC-E1 Beronet Card", 1, 1, 0, 1, 0}, /* E1 only supports single clock */
+	{CCAG_VID, CCAG_VID, HFCE1_ID, 0xB565, VENDOR_CCD,
+	 "HFC-E1+ Beronet Card (Dual)", 1, 1, 0, 1, 0}, /* E1 only supports single clock */
+	{CCAG_VID, CCAG_VID, HFCE1_ID, 0xB564, VENDOR_CCD,
+	 "HFC-E1 Beronet Card (Dual)", 1, 1, 0, 1, 0}, /* E1 only supports single clock */
+	{0x10B5, CCAG_VID, 0x9030, 0x3136, VENDOR_CCD,
+	 "HFC-4S PCIBridgeEval", 0, 4, 0, 0, 0},      // PLX PCI-Bridge
+	{CCAG_VID, CCAG_VID, HFC4S_ID, 0xB566, VENDOR_CCD,
+	 "HFC-2S Beronet Card", 0, 2, 1, 3, 0},
+	{CCAG_VID, CCAG_VID, HFC4S_ID, 0xB569, VENDOR_CCD,
+	 "HFC-2S Beronet Card (mini PCI)", 0, 2, 1, 3, 0},
+	{CCAG_VID, CCAG_VID, HFC4S_ID, 0xB567, VENDOR_CCD,
+	 "HFC-1S Beronet Card (mini PCI)", 0, 1, 1, 3, 0},
+	{0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0},
+};
+
+
+/*
+ * debugtool helper
+ */
+static void
+dt_newstate(mISDNstack_t *stack, u_int state, char *message)
+{
+	int mlen = message ? strlen(message) + 1 : 0;
+	struct sk_buff *skb = alloc_skb(mlen + 4, GFP_ATOMIC);
+	if (!skb)
+		return;
+ 
+	*(unsigned int *)skb_put(skb, 4) = state;
+	if (message)
+		memcpy(skb_put(skb, mlen), message, mlen);
+
+	mISDN_dt_new_frame(stack, NEWSTATE, skb, 0);
+}
+
+/****************/
+/* module stuff */
+/****************/
+
+/* NOTE: MAX_PORTS must be 8*MAX_CARDS */
+#define MAX_CARDS	16
+#define MAX_PORTS	128
+static u_int type[MAX_CARDS];
+static BYTE allocated[MAX_CARDS];  // remember if card is found
+static int pcm[MAX_PORTS];
+static u_int protocol[MAX_PORTS];
+static int layermask[MAX_PORTS];
+static int debug;
+static int poll;
+static int timer;
+
+
+#ifdef MODULE
+MODULE_AUTHOR("Andreas Eversberg");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+MODULE_PARM(poll, "1i");
+MODULE_PARM(timer, "1i");
+#define MODULE_PARM_T   "1-128i"
+MODULE_PARM(protocol, MODULE_PARM_T);
+MODULE_PARM(layermask, MODULE_PARM_T);
+MODULE_PARM(type, MODULE_PARM_T);
+MODULE_PARM(pcm, MODULE_PARM_T);
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+module_param(poll, uint, S_IRUGO | S_IWUSR);
+module_param(timer, uint, S_IRUGO | S_IWUSR);
+
+
+#ifdef OLD_MODULE_PARAM_ARRAY
+static int num_type=0, num_pcm=0, num_protocol=0, num_layermask=0;
+module_param_array(type, uint, num_type, S_IRUGO | S_IWUSR);
+module_param_array(pcm, uint, num_pcm, S_IRUGO | S_IWUSR);
+module_param_array(protocol, uint, num_protocol, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, num_layermask, S_IRUGO | S_IWUSR);
+#else
+module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(pcm, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(protocol, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, NULL, S_IRUGO | S_IWUSR);
+#endif
+#endif
+#endif
+
+
+#define HFCM_FIX_IRQS
+
+static void
+enable_hwirq(hfc_multi_t *hc)
+{
+	hc->hw.r_irq_ctrl |= V_GLOB_IRQ_EN;
+	HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl);
+}
+
+static void
+disable_hwirq(hfc_multi_t *hc)
+{
+	hc->hw.r_irq_ctrl &= ~((u_char)V_GLOB_IRQ_EN);
+	HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl);
+}
+
+#ifndef CONFIG_HFCMULTI_PCIMEM
+#define B410P_CARD
+#endif
+
+#define NUM_EC 2
+#define MAX_TDM_CHAN 32
+
+
+#ifdef B410P_CARD
+inline void enablepcibridge(hfc_multi_t *c)
+{
+	HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); /*was _io before*/
+}
+
+inline void disablepcibridge(hfc_multi_t *c)
+{
+	HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x2); /*was _io before*/
+}
+
+inline unsigned char readpcibridge(hfc_multi_t *c, unsigned char address)
+{
+	unsigned short cipv;
+	unsigned char data;
+	
+	// slow down a PCI read access by 1 PCI clock cycle
+	HFC_outb(c, R_CTRL, 0x4); /*was _io before*/
+	
+	if (address == 0)
+		cipv=0x4000;
+	else
+		cipv=0x5800;
+	
+	// select local bridge port address by writing to CIP port
+	//data = HFC_inb(c, cipv); /*was _io before*/
+	outw(cipv, c->pci_iobase + 4);
+	data = inb(c->pci_iobase);
+	
+	// restore R_CTRL for normal PCI read cycle speed
+	HFC_outb(c, R_CTRL, 0x0); /*was _io before*/
+	
+	return data;
+}
+
+inline void writepcibridge(hfc_multi_t *hc, unsigned char address, unsigned char data)
+{
+	unsigned short cipv;
+	unsigned int datav;
+
+	if (address == 0)
+		cipv=0x4000;
+	else
+		cipv=0x5800;
+
+	// select local bridge port address by writing to CIP port
+	outw(cipv, hc->pci_iobase + 4);
+	
+	// define a 32 bit dword with 4 identical bytes for write sequence
+	datav=data | ( (__u32) data <<8) | ( (__u32) data <<16) | ( (__u32) data <<24);
+
+	
+	// write this 32 bit dword to the bridge data port
+	// this will initiate a write sequence of up to 4 writes to the same address on the local bus
+	// interface
+	// the number of write accesses is undefined but >=1 and depends on the next PCI transaction
+	// during write sequence on the local bus
+	outl(datav, hc->pci_iobase);
+}
+	
+inline void cpld_set_reg(hfc_multi_t *hc, unsigned char reg)
+{
+	/* Do data pin read low byte */
+	HFC_outb(hc, R_GPIO_OUT1, reg);
+}
+
+inline void cpld_write_reg(hfc_multi_t *hc, unsigned char reg, unsigned char val)
+{
+	cpld_set_reg(hc, reg);
+
+	enablepcibridge(hc);
+	writepcibridge(hc, 1, val);
+	disablepcibridge(hc);
+
+	return;
+}
+
+inline unsigned char cpld_read_reg(hfc_multi_t *hc, unsigned char reg)
+{
+	unsigned char bytein;
+
+	cpld_set_reg(hc, reg);
+
+	/* Do data pin read low byte */
+	HFC_outb(hc, R_GPIO_OUT1, reg);
+
+	enablepcibridge(hc);
+	bytein = readpcibridge(hc, 1);
+	disablepcibridge(hc);
+
+	return bytein;
+}
+
+inline void vpm_write_address(hfc_multi_t *hc, unsigned short addr)
+{
+	cpld_write_reg(hc, 0, 0xff & addr);
+	cpld_write_reg(hc, 1, 0x01 & (addr >> 8));
+}
+
+inline unsigned short vpm_read_address(hfc_multi_t *c)
+{
+	unsigned short addr;
+	unsigned short highbit;
+	
+	addr = cpld_read_reg(c, 0);
+	highbit = cpld_read_reg(c, 1);
+
+	addr = addr | (highbit << 8);
+
+	return addr & 0x1ff;
+}
+
+inline unsigned char vpm_in(hfc_multi_t *c, int which, unsigned short addr)
+{
+	unsigned char res;
+
+	vpm_write_address(c, addr);
+
+	if (!which)
+		cpld_set_reg(c, 2);
+	else
+		cpld_set_reg(c, 3);
+
+	enablepcibridge(c);
+	res = readpcibridge(c, 1);
+	disablepcibridge(c);
+
+	cpld_set_reg(c, 0);
+
+	return res;
+}
+
+inline void vpm_out(hfc_multi_t *c, int which, unsigned short addr, unsigned char data)
+{
+	vpm_write_address(c, addr);
+
+	enablepcibridge(c);
+
+	if (!which)
+		cpld_set_reg(c, 2);
+	else
+		cpld_set_reg(c, 3);
+
+	writepcibridge(c, 1, data);
+
+	cpld_set_reg(c, 0);
+
+	disablepcibridge(c);
+
+	{
+	unsigned char regin;
+	regin = vpm_in(c, which, addr);
+	if (regin != data)
+		printk("Wrote 0x%x to register 0x%x but got back 0x%x\n", data, addr, regin);
+	}
+	return;
+}
+
+
+void vpm_init(hfc_multi_t *wc)
+{
+	unsigned char reg;
+	unsigned int mask;
+	unsigned int i, x, y;
+	unsigned int ver;
+
+	for (x=0;x<NUM_EC;x++) {
+		/* Setup GPIO's */
+		if (!x) {
+			ver = vpm_in(wc, x, 0x1a0);
+			printk("VPM: Chip %d: ver %02x\n", x, ver);
+		}
+
+		for (y=0;y<4;y++) {
+			vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */
+			vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */
+			vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */
+		}
+
+		/* Setup TDM path - sets fsync and tdm_clk as inputs */
+		reg = vpm_in(wc, x, 0x1a3); /* misc_con */
+		vpm_out(wc, x, 0x1a3, reg & ~2);
+
+		/* Setup Echo length (256 taps) */
+		vpm_out(wc, x, 0x022, 1);
+		vpm_out(wc, x, 0x023, 0xff);
+
+		/* Setup timeslots */
+		vpm_out(wc, x, 0x02f, 0x00);
+		mask = 0x02020202 << (x * 4);
+
+		/* Setup the tdm channel masks for all chips*/
+		for (i = 0; i < 4; i++)
+			vpm_out(wc, x, 0x33 - i, (mask >> (i << 3)) & 0xff);
+
+		/* Setup convergence rate */
+		printk("VPM: A-law mode\n");
+		reg = 0x00 | 0x10 | 0x01;
+		vpm_out(wc,x,0x20,reg);
+		printk("VPM reg 0x20 is %x\n", reg);
+		//vpm_out(wc,x,0x20,(0x00 | 0x08 | 0x20 | 0x10));
+
+		vpm_out(wc, x, 0x24, 0x02);
+		reg = vpm_in(wc, x, 0x24);
+		printk("NLP Thresh is set to %d (0x%x)\n", reg, reg);
+
+		/* Initialize echo cans */
+		for (i = 0 ; i < MAX_TDM_CHAN; i++) {
+			if (mask & (0x00000001 << i))
+				vpm_out(wc,x,i,0x00);
+		}
+
+		udelay(10000);
+
+		/* Put in bypass mode */
+		for (i = 0 ; i < MAX_TDM_CHAN ; i++) {
+			if (mask & (0x00000001 << i)) {
+				vpm_out(wc,x,i,0x01);
+			}
+		}
+
+		/* Enable bypass */
+		for (i = 0 ; i < MAX_TDM_CHAN ; i++) {
+			if (mask & (0x00000001 << i))
+				vpm_out(wc,x,0x78 + i,0x01);
+		}
+      
+	} 
+}
+
+void vpm_check(hfc_multi_t *hctmp)
+{
+	unsigned char gpi2;
+
+	gpi2 = HFC_inb(hctmp, R_GPI_IN2);
+
+	if ((gpi2 & 0x3) != 0x3) {
+		printk("Got interrupt 0x%x from VPM!\n", gpi2);
+	}
+}
+
+
+/*
+ * Interface to enable/disable the HW Echocan
+ *
+ * these functions are called within a spin_lock_irqsave on
+ * the channel instance lock, so we are not disturbed by irqs 
+ *
+ * we can later easily change the interface to make  other 
+ * things configurable, for now we configure the taps
+ *
+ */
+	
+void vpm_echocan_on(hfc_multi_t *hc, int ch, int taps) 
+{
+	unsigned int timeslot;
+	unsigned int unit;
+	channel_t *bch = hc->chan[ch].ch;
+#ifdef TXADJ
+	int txadj = -4;
+#endif
+	if (hc->chan[ch].protocol != ISDN_PID_L1_B_64TRANS)
+		return;
+
+	if (!bch)
+		return;
+#ifdef TXADJ
+	skb = create_link_skb(PH_CONTROL | INDICATION, VOL_CHANGE_TX, sizeof(int), &txadj, 0);
+
+	if (mISDN_queue_up(&bch->inst, 0, skb))
+		dev_kfree_skb(skb);
+#endif
+
+	timeslot = ((ch/4)*8) + ((ch%4)*4) + 1;
+	unit = ch % 4;
+
+	printk(KERN_NOTICE "vpm_echocan_on called taps [%d] on timeslot %d\n", taps, timeslot);
+
+	vpm_out(hc, unit, timeslot, 0x7e);
+}
+
+void vpm_echocan_off(hfc_multi_t *hc, int ch) 
+{
+	unsigned int timeslot;
+	unsigned int unit;
+	channel_t *bch = hc->chan[ch].ch;
+	struct sk_buff *skb;
+	int txadj = 0;
+
+	if (hc->chan[ch].protocol != ISDN_PID_L1_B_64TRANS)
+		return;
+
+	if (!bch)
+		return;
+
+	skb = create_link_skb(PH_CONTROL | INDICATION, VOL_CHANGE_TX, sizeof(int), &txadj, 0);
+
+	if (mISDN_queue_up(&bch->inst, 0, skb))
+		dev_kfree_skb(skb);
+
+	timeslot = ((ch/4)*8) + ((ch%4)*4) + 1;
+	unit = ch % 4;
+
+	printk(KERN_NOTICE "vpm_echocan_off called on timeslot %d\n", timeslot);
+	/*FILLME*/
+	vpm_out(hc, unit, timeslot, 0x01);
+}
+
+#endif  /* B410_CARD */
+
+
+
+/******************************************/
+/* free hardware resources used by driver */
+/******************************************/
+
+static void
+release_io_hfcmulti(hfc_multi_t *hc)
+{
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: entered\n", __FUNCTION__);
+
+	/* soft reset also masks all interrupts */
+	hc->hw.r_cirm |= V_SRES;
+	HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
+	udelay(1000);
+	hc->hw.r_cirm &= ~V_SRES;
+	HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
+	udelay(1000); /* instead of 'wait' that may cause locking */
+
+	/* disable memory mapped ports / io ports */
+	pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0);
+#ifdef CONFIG_HFCMULTI_PCIMEM
+	if (hc->pci_membase) iounmap((void *)hc->pci_membase);
+	if (hc->plx_membase) iounmap((void *)hc->plx_membase);
+#else
+	if (hc->pci_iobase)
+		release_region(hc->pci_iobase, 8);
+#endif
+
+#if 1
+	if (hc->pci_dev) {
+		pci_disable_device(hc->pci_dev);
+		pci_set_drvdata(hc->pci_dev, NULL);
+	}
+#endif
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: done\n", __FUNCTION__);
+}
+
+/****************************************************************************/
+/* function called to reset the HFC chip. A complete software reset of chip */
+/* and fifos is done. All configuration of the chip is done.                */
+/****************************************************************************/
+
+static int
+init_chip(hfc_multi_t *hc)
+{
+	u_long 	flags, val, val2 = 0, rev;
+	int	cnt = 0;
+	int	i, err = 0;
+	u_char	r_conf_en,rval;
+
+	spin_lock_irqsave(&hc->lock, flags);
+	/* reset all registers */
+	memset(&hc->hw, 0, sizeof(hfcmulti_hw_t));
+
+	/* revision check */
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: entered\n", __FUNCTION__);
+	val = HFC_inb(hc, R_CHIP_ID)>>4;
+	if(val!=0x8 && val!=0xc && val!=0xe)
+	{
+		printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n",(u_int)val);
+		err = -EIO;
+		goto out;
+	}
+	rev = HFC_inb(hc, R_CHIP_RV);
+	printk(KERN_INFO "HFC_multi: resetting HFC with chip ID=0x%lx revision=%ld%s\n", val, rev, (rev==0)?" (old FIFO handling)":"");
+	if (rev == 0) {
+		test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip);
+		printk(KERN_WARNING "HFC_multi: NOTE: Your chip is revision 0, ask Cologne Chip for update. Newer chips have a better FIFO handling. Old chips still work but may have slightly lower HDLC transmit performance.\n");
+	}
+	if (rev > 1) {
+		printk(KERN_WARNING "HFC_multi: WARNING: This driver doesn't consider chip revision = %ld. The chip / bridge may not work.\n", rev);
+	}
+
+/* set s-ram size */
+	hc->Flen = 0x10;
+	hc->Zmin = 0x80;
+	hc->Zlen = 384;
+	hc->DTMFbase = 0x1000;
+	if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) {
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: changing to 128K extenal RAM\n", __FUNCTION__);
+		hc->hw.r_ctrl |= V_EXT_RAM;
+		hc->hw.r_ram_sz = 1;
+		hc->Flen = 0x20;
+		hc->Zmin = 0xc0;
+		hc->Zlen = 1856;
+		hc->DTMFbase = 0x2000;
+	}
+	if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) {
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: changing to 512K extenal RAM\n", __FUNCTION__);
+		hc->hw.r_ctrl |= V_EXT_RAM;
+		hc->hw.r_ram_sz = 2;
+		hc->Flen = 0x20;
+		hc->Zmin = 0xc0;
+		hc->Zlen = 8000;
+		hc->DTMFbase = 0x2000;
+	}
+
+	/* we only want the real Z2 read-pointer for revision > 0 */
+	if (!test_bit(HFC_CHIP_REVISION0, &hc->chip))
+		hc->hw.r_ram_sz |= V_FZ_MD;
+
+	/* soft reset */
+	HFC_outb(hc, R_CTRL, hc->hw.r_ctrl);
+	HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
+	HFC_outb(hc, R_FIFO_MD, 0);
+	hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES | V_RLD_EPR;
+	HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
+	udelay(100);
+	hc->hw.r_cirm = 0;
+	HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
+	udelay(100);
+	HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
+
+
+	/* set pcm mode & reset */
+	if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
+		if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: setting PCM into slave mode\n", __FUNCTION__);
+	} else {
+		if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: setting PCM into master mode\n", __FUNCTION__);
+		hc->hw.r_pcm_md0 |= V_PCM_MD;
+	}
+
+	// RAM access test
+	HFC_outb(hc, R_RAM_ADDR0, 0);
+	HFC_outb(hc, R_RAM_ADDR1, 0);
+	HFC_outb(hc, R_RAM_ADDR2, 0);
+
+	for(i=0;i<256;i++) {
+		HFC_outb(hc, R_RAM_ADDR0,i);
+		HFC_outb(hc, R_RAM_DATA,((i*3)&0xff));
+		//udelay(5);
+		//HFC_outb(hc, R_RAM_DATA,((i*3)&0xff));
+	}
+
+	for(i=0;i<256;i++) {
+		HFC_outb(hc, R_RAM_ADDR0,i);
+		HFC_inb(hc, R_RAM_DATA);
+		rval=HFC_inb(hc, R_INT_DATA);
+		if(rval!=((i*3)&0xff))
+		{
+			printk(KERN_DEBUG "addr:%x val:%x should:%x\n",i,rval,(i*3)&0xff);
+			err++;
+		}
+	}
+
+	if (err) {
+		printk(KERN_DEBUG "aborting.1 - %d RAM access errors\n",err);
+		err = -EIO;
+		goto out;
+	}
+
+#ifdef B410P_CARD
+	if (test_bit(HFC_CHIP_DIGICARD,&hc->chip)) {
+		HFC_outb(hc, R_BRG_PCM_CFG, 0x2);
+		HFC_outb(hc, R_PCM_MD0, (0x9<<4) | 0x1);
+		HFC_outb(hc, R_PCM_MD1, 0);
+	
+		printk(KERN_NOTICE "Setting GPIOs\n");
+		HFC_outb(hc, R_GPIO_SEL, 0x30);
+		HFC_outb(hc, R_GPIO_EN1, 0x3);
+
+		udelay(1000);
+		
+		printk(KERN_NOTICE "calling vpm_init\n");
+		
+		vpm_init(hc);
+
+	} else 
+#endif	
+	{
+		HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x90);
+		if (hc->slots == 32)
+			HFC_outb(hc, R_PCM_MD1, 0x00);
+		if (hc->slots == 64)
+			HFC_outb(hc, R_PCM_MD1, 0x10);
+		if (hc->slots == 128)
+			HFC_outb(hc, R_PCM_MD1, 0x20);
+		HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0);
+		HFC_outb(hc, R_PCM_MD2, 0x00);
+		HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00);
+		
+	}
+
+	i = 0;
+	while (i < 256) {
+		HFC_outb_(hc, R_SLOT, i);
+		HFC_outb_(hc, A_SL_CFG, 0);
+		HFC_outb_(hc, A_CONF, 0);
+		hc->slot_owner[i] = -1;
+		i++;
+	}
+
+	/* set clock speed */
+	if (test_bit(HFC_CHIP_CLOCK2, &hc->chip)) {
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: setting double clock\n", __FUNCTION__);
+		HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK);
+	}
+
+	/* check if R_F0_CNT counts */
+	val = HFC_inb(hc, R_F0_CNTL);
+	val += HFC_inb(hc, R_F0_CNTH) << 8;
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "HFC_multi F0_CNT %ld after status ok\n", val);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	while (cnt < 50) { /* max 50 ms */
+		spin_unlock_irqrestore(&hc->lock, flags);
+		schedule_timeout((HZ*10)/1000); /* Timeout 10ms */
+		spin_lock_irqsave(&hc->lock, flags);
+		cnt+=10;
+		val2 = HFC_inb(hc, R_F0_CNTL);
+		val2 += HFC_inb(hc, R_F0_CNTH) << 8;
+		if (val2 >= val+4) /* wait 4 pulses */
+			break;
+	}
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "HFC_multi F0_CNT %ld after %dms\n", val2, cnt);
+
+	if (val2 < val+4) {
+		printk(KERN_ERR "HFC_multi ERROR 125us pulse not counting.\n");
+		if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
+			printk(KERN_ERR "HFC_multi This happens in PCM slave mode without connected master.\n");
+		}
+		if (test_bit(HFC_CHIP_DIGICARD, &hc->chip)) {
+			printk(KERN_ERR "HFC_multi ingoring PCM clock for digicard.\n");
+			
+		} else {
+			if (!test_bit(HFC_CHIP_CLOCK_IGNORE, &hc->chip) ){ 
+				err = -EIO;
+				goto out;
+			}
+		}
+	}
+
+	/* set up timer */
+	HFC_outb(hc, R_TI_WD, poll_timer);
+	hc->hw.r_irqmsk_misc |= V_TI_IRQMSK;
+
+	/* set up 125us interrupt, only if function pointer is available 
+	   and module parameter timer is set */
+	if (timer!=0 && hfc_interrupt && register_interrupt) {
+		/* only one chip should use this interrupt */
+		timer = 0;
+		hc->hw.r_irqmsk_misc |= V_PROC_IRQMSK;
+		/* deactivate other interrupts in ztdummy */
+		register_interrupt();
+	}
+
+	/* set E1 state machine IRQ */
+	if (hc->type == 1)
+		hc->hw.r_irqmsk_misc |= V_STA_IRQMSK;
+
+	/* set DTMF detection */
+	if (test_bit(HFC_CHIP_DTMF, &hc->chip)) {
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: enabling DTMF detection for all B-channel\n", __FUNCTION__);
+		hc->hw.r_dtmf = V_DTMF_EN | V_DTMF_STOP;
+		if (test_bit(HFC_CHIP_ULAW, &hc->chip))
+			hc->hw.r_dtmf |= V_ULAW_SEL;
+		HFC_outb(hc, R_DTMF_N, 102-1);
+		hc->hw.r_irqmsk_misc |= V_DTMF_IRQMSK;
+	}
+
+	/* conference engine */
+	if (test_bit(HFC_CHIP_ULAW, &hc->chip))
+		r_conf_en = V_CONF_EN | V_ULAW;
+	else
+		r_conf_en = V_CONF_EN;
+	HFC_outb(hc, R_CONF_EN, r_conf_en);
+
+	/* setting leds */
+	switch(hc->leds) {
+		case 1: /* HFC-E1 OEM */
+		if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) 
+			HFC_outb(hc, R_GPIO_SEL, 0x32);
+		else
+			HFC_outb(hc, R_GPIO_SEL, 0x30);
+
+		HFC_outb(hc, R_GPIO_EN1, 0x0f);
+		HFC_outb(hc, R_GPIO_OUT1, 0x00);
+
+		HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3);
+		break;
+
+		case 2: /* HFC-4S OEM */
+		case 3:
+		HFC_outb(hc, R_GPIO_SEL, 0xf0);
+		HFC_outb(hc, R_GPIO_EN1, 0xff);
+		HFC_outb(hc, R_GPIO_OUT1, 0x00);
+		break;
+	}
+
+	/* set master clock */
+	if (hc->masterclk >= 0) {
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: setting ST master clock to port %d (0..%d)\n", __FUNCTION__, hc->masterclk, hc->ports-1);
+		hc->hw.r_st_sync = hc->masterclk | V_AUTO_SYNC;
+		HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync);
+	}
+
+	/* setting misc irq */
+	HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc);
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "r_irqmsk_misc.2: 0x%x\n", hc->hw.r_irqmsk_misc);
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: done\n", __FUNCTION__);
+out:
+	spin_unlock_irqrestore(&hc->lock, flags);
+	return(err);
+}
+
+
+/************************/
+/* control the watchdog */
+/************************/
+static void
+hfcmulti_watchdog(hfc_multi_t *hc)
+{
+	hc->wdcount++;
+
+	if (hc->wdcount > 10 ) {
+		hc->wdcount=0;
+		hc->wdbyte = hc->wdbyte==V_GPIO_OUT2?V_GPIO_OUT3:V_GPIO_OUT2;
+
+	/**	printk("Sending Watchdog Kill %x\n",hc->wdbyte); **/
+		HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3);
+		HFC_outb(hc, R_GPIO_OUT0, hc->wdbyte);
+	}
+}
+
+
+
+/***************/
+/* output leds */
+/***************/
+static void
+hfcmulti_leds(hfc_multi_t *hc)
+{
+	int i, state, active;
+	channel_t *dch;
+	int led[4];
+
+	hc->ledcount += poll;
+	if (hc->ledcount > 4096)
+		hc->ledcount -= 4096;
+
+	switch(hc->leds) {
+		case 1: /* HFC-E1 OEM */
+		/* 2 red blinking: LOS
+		   1 red: AIS
+		   left green: PH_ACTIVATE
+		   right green flashing: FIFO activity
+		*/
+		i = HFC_inb(hc, R_GPI_IN0) & 0xf0;
+		if (!(i & 0x40)) { /* LOS */
+			if (hc->e1_switch != i) {
+				hc->e1_switch = i;
+				hc->hw.r_tx0 &= ~V_OUT_EN;
+				HFC_outb(hc, R_TX0, hc->hw.r_tx0);
+			}
+			if (hc->ledcount & 512)
+				led[0] = led[1] = 1;
+			else
+				led[0] = led[1] = 0;
+			led[2] = led[3] = 0;
+		} else
+		if (!(i & 0x80)) { /* AIS */
+			if (hc->e1_switch != i) {
+				hc->e1_switch = i;
+				hc->hw.r_tx0 |= V_OUT_EN;
+				hc->hw.r_tx1 |= V_AIS_OUT;
+				HFC_outb(hc, R_TX0, hc->hw.r_tx0);
+				HFC_outb(hc, R_TX1, hc->hw.r_tx1);
+			}
+			if (hc->ledcount & 512)
+				led[2] = led[3] = 1;
+			else
+				led[2] = led[3] = 0;
+			led[0] = led[1] = 0;
+		} else {
+			if (hc->e1_switch != i) {
+				/* reset LOS/AIS */
+				hc->e1_switch = i;
+				hc->hw.r_tx0 |= V_OUT_EN;
+				hc->hw.r_tx1 &= ~V_AIS_OUT;
+				HFC_outb(hc, R_TX0, hc->hw.r_tx0);
+				HFC_outb(hc, R_TX1, hc->hw.r_tx1);
+			}
+			if (HFC_inb_(hc, R_RX_STA0) & V_SIG_LOS) {
+				if (hc->ledcount>>11)
+					led[0] = led[1] = 1; /* both red blinking */
+				else
+					led[0] = led[1] = 0;
+			} else
+			if (HFC_inb_(hc, R_RX_STA0) & V_AIS) {
+				led[0] = led[1] = 1; /* both red */
+			} else {
+				led[0] = led[1] = 0; /* no red */
+			}
+			state = 0;
+			active = 1;
+			dch = hc->chan[16].ch;
+			if (dch && test_bit(FLG_DCHANNEL, &dch->Flags))
+				state = dch->state;
+			if (state == active) {
+				led[2] = 1; /* left green */
+				if (hc->activity[0]) {
+					led[3] = 1; /* right green */
+					hc->activity[0] = 0;
+				} else
+					led[3] = 0; /* no right green */
+
+			} else
+				led[2] = led[3] = 0; /* no green */
+		}
+		HFC_outb(hc, R_GPIO_OUT1,
+			(led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xf); /* leds are inverted */
+
+		break;
+
+		case 2: /* HFC-4S OEM */
+		/* red blinking = PH_DEACTIVATE
+		   red steady = PH_ACTIVATE
+		   green flashing = fifo activity
+		*/
+		i = 0;
+		while(i < 4) {
+			state = 0;
+			active = -1;
+			dch = hc->chan[(i<<2)|2].ch;
+			if (dch && test_bit(FLG_DCHANNEL, &dch->Flags)) {
+				state = dch->state;
+				active = test_bit(HFC_CFG_NTMODE, &hc->chan[dch->channel].cfg)?3:7;
+			}
+			if (state) {
+				if (state==active) {
+					if (hc->activity[i]) {
+						led[i] = 1; /* led green */
+						hc->activity[i] = 0;
+					} else
+						led[i] = 2; /* led red */
+				} else if (hc->ledcount>>11)
+					led[i] = 2; /* led red */
+				else
+					led[i] = 0; /* led off */
+			} else
+				led[i] = 0; /* led off */
+			i++;
+		}
+
+#ifdef B410P_CARD
+		if (test_bit(HFC_CHIP_DIGICARD, &hc->chip)) {
+			int leds=0;
+			for (i=0; i<4; i++) {
+				if (led[i]==1) {
+					/*green*/
+					leds |=( 0x2 <<(i*2));
+				} else if (led[i]==2) {
+					/*red*/
+					leds |=( 0x1 <<(i*2));
+				}
+			}
+			vpm_out(hc, 0, 0x1a8+3,leds);
+		} else 
+#endif
+		{
+			HFC_outb(hc, R_GPIO_EN1,
+				 ((led[0]>0)<<0) | ((led[1]>0)<<1) |
+				 ((led[2]>0)<<2) | ((led[3]>0)<<3));
+			HFC_outb(hc, R_GPIO_OUT1,
+				 ((led[0]&1)<<0) | ((led[1]&1)<<1) |
+				 ((led[2]&1)<<2) | ((led[3]&1)<<3));
+		}
+		break;
+
+		case 3:
+		/* red blinking = PH_DEACTIVATE
+		   red steady = PH_ACTIVATE
+		   green flashing = fifo activity
+		*/
+		for(i=0;i<2;i++) {
+			state = 0;
+			active = -1;
+			dch = hc->chan[(i<<2)|2].ch;
+			if (dch && test_bit(FLG_DCHANNEL, &dch->Flags)) {
+				state = dch->state;
+				active = test_bit(HFC_CFG_NTMODE, &hc->chan[dch->channel].cfg)?3:7;
+			}
+			if (state) {
+				if (state==active) {
+					if (hc->activity[i]) {
+						led[i] = 1; /* led green */
+						hc->activity[i] = 0;
+					} else
+						led[i] = 2; /* led red */
+				} else if (hc->ledcount>>11)
+					led[i] = 2; /* led red */
+				else
+					led[i] = 0; /* led off */
+			} else
+				led[i] = 0; /* led off */
+		}
+
+	//	printk("leds %d %d\n", led[0], led[1]);
+	//LEDME
+
+		HFC_outb(hc, R_GPIO_EN1,
+			((led[0]>0)<<2) | ((led[1]>0)<<3) );
+		HFC_outb(hc, R_GPIO_OUT1,
+			((led[0]&1)<<2) | ((led[1]&1)<<3) );
+
+		break;
+		case 8:
+		{
+			unsigned long led=0;
+			int off=0;
+
+			if (hc->ledcount>2048) 
+				off=1;
+
+			for (i=0;i<8;i++) {
+				state = 0;
+				active = -1;
+				dch = hc->chan[(i<<2)|2].ch;
+				if (dch && test_bit(FLG_DCHANNEL, &dch->Flags)) {
+					state = dch->state;
+					active = test_bit(HFC_CFG_NTMODE, &hc->chan[dch->channel].cfg)?3:7;
+				}
+				if (state) {
+					if (state!=active && off)
+						led |= 1<<i;
+				} else
+					led |= 1<<i;
+			}
+			unsigned long leddw=led << 24 | led << 16 | led << 8 | led;
+			//HFC_outb(hc, R_BRG_PCM_CFG, 1);
+			//HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); /*was _io before*/
+#ifndef CONFIG_HFCMULTI_PCIMEM
+			HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK);
+			outw(0x4000, hc->pci_iobase + 4);
+			outl(leddw, hc->pci_iobase);
+			HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK);
+#endif 
+		}
+
+		break;
+	}
+}
+/**************************/
+/* read dtmf coefficients */
+/**************************/
+
+static void
+hfcmulti_dtmf(hfc_multi_t *hc)
+{
+	signed long coeff[16];
+	DWORD mantissa;
+	int co, ch;
+	channel_t *bch = NULL;
+	BYTE exponent;
+	int dtmf = 0;
+	int addr;
+	WORD w_float;
+	struct sk_buff *skb;
+
+	if (debug & DEBUG_HFCMULTI_DTMF)
+		printk(KERN_DEBUG "%s: dtmf detection irq\n", __FUNCTION__);
+	ch = 0;
+	while(ch < 32) {
+		// only process enabled B-channels
+		bch = hc->chan[ch].ch;
+		if ((!bch) || !test_bit(FLG_BCHANNEL, &bch->Flags)) {
+			ch++;
+			continue;
+		}
+		if (!hc->created[hc->chan[ch].port]) {
+			ch++;
+			continue;
+		}
+		if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+			ch++;
+			continue;
+		}
+		if (debug & DEBUG_HFCMULTI_DTMF)
+			printk(KERN_DEBUG "%s: dtmf channel %d:", __FUNCTION__, ch);
+		dtmf = 1;
+		co = 0;
+		while(co < 8) {
+			// read W(n-1) coefficient
+			addr = hc->DTMFbase + ((co<<7) | (ch<<2));
+			HFC_outb_(hc, R_RAM_ADDR0, addr);
+			HFC_outb_(hc, R_RAM_ADDR1, addr>>8);
+			HFC_outb_(hc, R_RAM_ADDR2, (addr>>16) | V_ADDR_INC);
+			w_float = HFC_inb_(hc, R_RAM_DATA);
+#ifdef CONFIG_HFCMULTI_PCIMEM
+			w_float |= (HFC_inb_(hc, R_RAM_DATA) << 8);
+#else
+			w_float |= (HFC_getb(hc) << 8);
+#endif
+			if (debug & DEBUG_HFCMULTI_DTMF)
+				printk(" %04x", w_float);
+
+			// decode float (see chip doc)
+			mantissa = w_float & 0x0fff;
+			if (w_float & 0x8000)
+				mantissa |= 0xfffff000;
+			exponent = (w_float>>12) & 0x7;
+			if (exponent) {
+				mantissa ^= 0x1000;
+				mantissa <<= (exponent-1);
+			}
+
+			// store coefficient
+			coeff[co<<1] = mantissa;
+
+			// read W(n) coefficient
+			w_float = HFC_inb_(hc, R_RAM_DATA);
+#ifdef CONFIG_HFCMULTI_PCIMEM
+			w_float |= (HFC_inb_(hc, R_RAM_DATA) << 8);
+#else
+			w_float |= (HFC_getb(hc) << 8);
+#endif
+			if (debug & DEBUG_HFCMULTI_DTMF)
+				printk(" %04x", w_float);
+
+			// decode float (see chip doc)
+			mantissa = w_float & 0x0fff;
+			if (w_float & 0x8000)
+				mantissa |= 0xfffff000;
+			exponent = (w_float>>12) & 0x7;
+			if (exponent) {
+				mantissa ^= 0x1000;
+				mantissa <<= (exponent-1);
+			}
+
+			// store coefficient
+			coeff[(co<<1)|1] = mantissa;
+			co++;
+		}
+		skb = create_link_skb(PH_CONTROL | INDICATION, HW_HFC_COEFF, sizeof(coeff), coeff, 0);
+		if (!skb) {
+			printk(KERN_WARNING "%s: No memory for skb\n", __FUNCTION__);
+			ch++;
+			continue;
+		}
+		if (debug & DEBUG_HFCMULTI_DTMF) {
+			printk("\n");
+			printk("%s: DTMF ready %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx len=%d\n", __FUNCTION__,
+			coeff[0], coeff[1], coeff[2], coeff[3], coeff[4], coeff[5], coeff[6], coeff[7], skb->len);
+		}
+
+#ifdef FIXME   // TODO changed
+				if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) && bch->dev)
+					hif = &bch->dev->rport.pif;
+				else
+					hif = &bch->inst.up;
+#endif
+		if (mISDN_queue_up(&bch->inst, 0, skb))
+			dev_kfree_skb(skb);
+
+		ch++;
+	}
+
+	// restart DTMF processing
+	hc->dtmf = dtmf;
+	if (dtmf)
+		HFC_outb_(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF);
+}
+
+#ifdef CONFIG_HFCMULTI_PCIMEM
+/*******************/
+/* write fifo data */
+/*******************/
+void write_fifo_data(hfc_multi_t *hc,BYTE *dest,int len)
+{
+	int i, remain;
+
+	remain = len;
+
+#ifdef FIFO_32BIT_ACCESS
+	for (i = 0; i < len/4; i++) {
+		HFC_outl_(hc, A_FIFO_DATA0, *((DWORD *)dest));
+		remain -= 4;
+		dest += 4;
+	}
+#endif
+
+#ifdef FIFO_16BIT_ACCESS
+	for (i = 0; i < len/2; i++) {
+		HFC_outw_(hc, A_FIFO_DATA0, *((WORD *)dest));
+		remain -= 2;
+		dest += 2;
+	}
+#endif
+
+	for (i = 0; i < remain; i++)
+		HFC_outb_(hc, A_FIFO_DATA0, *dest++);
+
+}
+#endif
+
+#ifndef CONFIG_HFCMULTI_PCIMEM
+/*******************/
+/* write fifo data */
+/*******************/
+void 
+write_fifo_data(hfc_multi_t *hc, BYTE *dest, int len)
+{
+	int i, remain;
+
+	remain = len;
+	HFC_set(hc, A_FIFO_DATA0);
+
+#ifdef FIFO_32BIT_ACCESS
+	for (i = 0; i < len/4; i++) {
+		HFC_putl(hc, *((DWORD *)dest));
+		remain -= 4;
+		dest += 4;
+	}
+#endif
+
+#ifdef FIFO_16BIT_ACCESS
+	for(i = 0; i < len/2; i++) {
+		HFC_putw(hc, *((WORD *)dest));
+		remain -= 2;
+		dest += 2;
+	}
+#endif
+
+	for (i = 0; i < remain; i++)
+		HFC_putb(hc, *dest++);
+}
+#endif
+
+/*********************************/
+/* fill fifo as much as possible */
+/*********************************/
+
+static void
+hfcmulti_tx(hfc_multi_t *hc, int ch, channel_t *chan)
+{
+	int i, ii, temp, len;
+	int Zspace, z1, z2;
+	int Fspace, f1, f2;
+	BYTE *d;
+	int txpending, slot_tx;
+
+	f1 = HFC_inb_(hc, A_F1);
+	f2 = HFC_inb_(hc, A_F2);
+	//printk(KERN_DEBUG "txf12:%x %x\n",f1,f2);
+	/* get skb, fifo & mode */
+	
+	txpending = hc->chan[ch].txpending;
+	slot_tx = hc->chan[ch].slot_tx;
+	len = chan->tx_skb ? chan->tx_skb->len : 0;
+	if ((!len) && txpending != 1)
+		return; /* no data */
+
+	//printk("debug: data: len = %d, txpending = %d!!!!\n", *len, txpending);
+	/* lets see how much data we will have left in buffer */
+	if (test_bit(HFC_CHIP_DIGICARD, &hc->chip) && (hc->chan[ch].protocol == ISDN_PID_L1_B_64TRANS) && (hc->chan[ch].slot_rx < 0) && (hc->chan[ch].bank_rx == 0)
+			&& (hc->chan[ch].slot_tx < 0) && (hc->chan[ch].bank_tx == 0)) {
+		HFC_outb_(hc, R_FIFO, 0x20 | (ch << 1));
+	} else
+		HFC_outb_(hc, R_FIFO, ch << 1);
+
+	HFC_wait_(hc);
+	if (txpending == 2) {
+		/* reset fifo */
+		HFC_outb_(hc, R_INC_RES_FIFO, V_RES_F);
+		HFC_wait_(hc);
+		HFC_outb(hc, A_SUBCH_CFG, 0);
+		txpending = 1;
+	}
+next_frame:
+	if (test_bit(FLG_HDLC, &chan->Flags)) {
+		f1 = HFC_inb_(hc, A_F1);
+		f2 = HFC_inb_(hc, A_F2);
+		while (f2 != (temp = HFC_inb_(hc, A_F2))) {
+			if (debug & DEBUG_HFCMULTI_FIFO)
+				printk(KERN_DEBUG "%s: reread f2 because %d!=%d\n",
+					__FUNCTION__, temp, f2);
+			f2 = temp; /* repeat until F2 is equal */
+		}
+		Fspace = f2 - f1 - 1;
+		if (Fspace < 0)
+			Fspace += hc->Flen;
+		/* Old FIFO handling doesn't give us the current Z2 read
+		 * pointer, so we cannot send the next frame before the fifo
+		 * is empty. It makes no difference except for a slightly
+		 * lower performance.
+		 */
+		if (test_bit(HFC_CHIP_REVISION0, &hc->chip)) {
+			if (f1 != f2)
+				Fspace = 0;
+			else
+				Fspace = 1;
+		}
+		/* one frame only for ST D-channels, to allow resending */
+		if (hc->type != 1 && test_bit(FLG_DCHANNEL, &chan->Flags)) {
+			if (f1 != f2)
+				Fspace = 0;
+		}
+		/* F-counter full condition */
+		if (Fspace == 0)
+			return;
+	}
+	z1 = HFC_inw_(hc, A_Z1) - hc->Zmin;
+	z2 = HFC_inw_(hc, A_Z2) - hc->Zmin;
+	while (z2 != (temp = (HFC_inw_(hc, A_Z2) - hc->Zmin))) {
+		if (debug & DEBUG_HFCMULTI_FIFO)
+			printk(KERN_DEBUG "%s: reread z2 because %d!=%d\n",
+				__FUNCTION__, temp, z2);
+		z2 = temp; /* repeat unti Z2 is equal */
+	}
+	Zspace = z2 - z1 - 1;
+	if (Zspace < 0)
+		Zspace += hc->Zlen;
+	/* buffer too full, there must be at least one more byte for 0-volume */
+	if (Zspace < 4) /* just to be safe */
+		return;
+
+	/* if no data */
+	if (!len) {
+		if (z1 == z2) { /* empty */
+			/* if done with FIFO audio data during PCM connection */
+			if (!test_bit(FLG_HDLC, &chan->Flags) && txpending && slot_tx >= 0) {
+				if (debug & DEBUG_HFCMULTI_MODE)
+					printk(KERN_DEBUG "%s: reconnecting PCM due to no more FIFO data: channel %d slot_tx %d\n",
+						__FUNCTION__, ch, slot_tx);
+				/* connect slot */
+				HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | V_HDLC_TRP | V_IFF);
+				HFC_outb_(hc, R_FIFO, ch<<1 | 1);
+				HFC_wait_(hc);
+				HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | V_HDLC_TRP | V_IFF);
+				HFC_outb_(hc, R_FIFO, ch<<1);
+				HFC_wait_(hc);
+			}
+			txpending = hc->chan[ch].txpending = 0;
+		}
+		return; /* no data */
+	}
+
+	/* if audio data */
+	if (!test_bit(FLG_HDLC, &chan->Flags) && !txpending && slot_tx >= 0) {
+		if (debug & DEBUG_HFCMULTI_MODE)
+			printk(KERN_DEBUG "%s: disconnecting PCM due to FIFO data: channel %d slot_tx %d\n",
+				__FUNCTION__, ch, slot_tx);
+		/* disconnect slot */
+		HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF);
+		HFC_outb_(hc, R_FIFO, ch<<1 | 1);
+		HFC_wait_(hc);
+		HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF);
+		HFC_outb_(hc, R_FIFO, ch<<1);
+		HFC_wait_(hc);
+	}
+	txpending = hc->chan[ch].txpending = 1;
+
+	/* show activity */
+	hc->activity[hc->chan[ch].port] = 1;
+
+	/* fill fifo to what we have left */
+	i = chan->tx_idx;
+	ii = len;
+	d = chan->tx_skb->data + i;
+	if (ii - i > Zspace)
+		ii = Zspace + i;
+	if (debug & DEBUG_HFCMULTI_FIFO)
+		printk(KERN_DEBUG "%s: fifo(%d) has %d bytes space left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n",
+			__FUNCTION__, ch, Zspace, z1, z2, ii-i, len-i,
+			test_bit(FLG_HDLC, &chan->Flags) ? "HDLC":"TRANS");
+
+	/* Have to prep the audio data */
+	write_fifo_data(hc, d, ii - i);
+	chan->tx_idx = ii;
+
+	/* if not all data has been written */
+	if (ii != len) {
+		/* NOTE: fifo is started by the calling function */
+		return;
+	}
+
+	/* if all data has been written */
+	if (test_bit(FLG_HDLC, &chan->Flags)) {
+		/* increment f-counter */
+		HFC_outb_(hc, R_INC_RES_FIFO, V_INC_F);
+		HFC_wait_(hc);
+	}
+	// check for next frame
+	if (chan->tx_skb) {
+		dev_kfree_skb(chan->tx_skb);
+	} 
+
+	if (test_bit(FLG_TX_NEXT, &chan->Flags)) {
+		chan->tx_skb = chan->next_skb;
+		if (chan->tx_skb) {
+			mISDN_head_t	*hh = mISDN_HEAD_P(chan->tx_skb);
+			chan->next_skb = NULL;
+			test_and_clear_bit(FLG_TX_NEXT, &chan->Flags);
+			chan->tx_idx = 0;
+			len = chan->tx_skb->len;
+			queue_ch_frame(chan, CONFIRM, hh->dinfo, NULL);
+			goto next_frame;
+		} else {
+			test_and_clear_bit(FLG_TX_NEXT, &chan->Flags);
+			printk(KERN_WARNING "%s: tx irq TX_NEXT without skb (dch ch=%d)\n",
+				__FUNCTION__, ch);
+		}
+	} else
+		chan->tx_skb = NULL;
+	test_and_clear_bit(FLG_TX_BUSY, &chan->Flags);
+	chan->tx_idx = 0;
+	/* now we have no more data, so in case of transparent,
+	 * we set the last byte in fifo to 'silence' in case we will get
+	 * no more data at all. this prevents sending an undefined value.
+	 */
+	if (!test_bit(FLG_HDLC, &chan->Flags))
+		HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence);
+}
+
+
+#ifdef CONFIG_HFCMULTI_PCIMEM
+/******************/
+/* read fifo data */
+/******************/
+void read_fifo_data(hfc_multi_t *hc, BYTE *dest, int len)
+{
+	int i, remain;
+
+	remain = len;
+
+#ifdef FIFO_32BIT_ACCESS
+	for(i = 0; i < len/4; i++) {
+		*((DWORD *)dest) = HFC_inl_(hc, A_FIFO_DATA0);
+		remain -= 4;
+		dest += 4;
+	}
+#endif
+
+#ifdef FIFO_16BIT_ACCESS
+	for(i = 0; i < len/2; i++) {
+		*((WORD *)dest) = HFC_inw_(hc, A_FIFO_DATA0);
+		remain -= 2;
+		dest += 2;
+	}
+#endif
+
+	for(i = 0; i < remain; i++)
+		*dest++ = HFC_inb_(hc, A_FIFO_DATA0);
+
+}
+#endif
+
+#ifndef CONFIG_HFCMULTI_PCIMEM
+/******************/
+/* read fifo data */
+/******************/
+void read_fifo_data(hfc_multi_t *hc, BYTE *dest, int len)
+{
+	int i, remain;
+
+	remain = len;
+	HFC_set(hc, A_FIFO_DATA0);
+
+#ifdef FIFO_32BIT_ACCESS
+	for(i = 0; i < len/4; i++) {
+		*((DWORD *)dest) = HFC_getl(hc);
+		remain -= 4;
+		dest += 4;
+	}
+#endif
+
+#ifdef FIFO_16BIT_ACCESS
+	for(i = 0; i < len/2; i++) {
+		*((WORD *)dest) = HFC_getw(hc);
+		remain -= 2;
+		dest += 2;
+	}
+#endif
+
+	for(i = 0;i < remain; i++)
+		*dest++ = HFC_getb(hc);
+}
+#endif
+
+
+static void
+hfcmulti_rx(hfc_multi_t *hc, int ch, channel_t *chan)
+{
+	int temp;
+	int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */
+	int f1 = 0, f2 = 0; /* = 0, to make GCC happy */
+	struct sk_buff *skb;
+
+	/* lets see how much data we received */
+	if (test_bit(HFC_CHIP_DIGICARD, &hc->chip) && (hc->chan[ch].protocol == ISDN_PID_L1_B_64TRANS) && (hc->chan[ch].slot_rx < 0) && (hc->chan[ch].bank_rx == 0)
+			&& (hc->chan[ch].slot_tx < 0) && (hc->chan[ch].bank_tx == 0)) {
+		HFC_outb_(hc, R_FIFO, 0x20 | (ch<<1) | 1);
+	} else 
+		HFC_outb_(hc, R_FIFO, (ch<<1)|1);
+	HFC_wait_(hc);
+next_frame:
+	if (test_bit(FLG_HDLC, &chan->Flags)) {
+		f1 = HFC_inb_(hc, A_F1);
+		while (f1 != (temp = HFC_inb_(hc, A_F1))) {
+			if (debug & DEBUG_HFCMULTI_FIFO)
+				printk(KERN_DEBUG "%s: reread f1 because %d!=%d\n", __FUNCTION__, temp, f1);
+			f1 = temp; /* repeat until F1 is equal */
+		}
+		f2 = HFC_inb_(hc, A_F2);
+	}
+	//if(f1!=f2) printk(KERN_DEBUG "got a chan:%d framef12:%x %x!!!!\n",ch,f1,f2);
+	//printk(KERN_DEBUG "got a chan:%d framef12:%x %x!!!!\n",ch,f1,f2);
+	z1 = HFC_inw_(hc, A_Z1) - hc->Zmin;
+	while(z1 != (temp = (HFC_inw_(hc, A_Z1) - hc->Zmin))) {
+		if (debug & DEBUG_HFCMULTI_FIFO)
+			printk(KERN_DEBUG "%s: reread z2 because %d!=%d\n", __FUNCTION__, temp, z2);
+		z1 = temp; /* repeat until Z1 is equal */
+	}
+	z2 = HFC_inw_(hc, A_Z2) - hc->Zmin;
+	Zsize = z1 - z2;
+	if (test_bit(FLG_HDLC, &chan->Flags) && f1 != f2) /* complete hdlc frame */
+		Zsize++;
+	if (Zsize < 0)
+		Zsize += hc->Zlen;
+	/* if buffer is empty */
+	if (Zsize <= 0)
+		return;
+
+	if (!chan->rx_skb) {
+		chan->rx_skb = alloc_stack_skb(chan->maxlen + 3, chan->up_headerlen);
+		if (!chan->rx_skb) {
+			printk(KERN_DEBUG "%s: No mem for rx_skb\n", __FUNCTION__);
+			return;
+		}
+	}
+	/* show activity */
+	hc->activity[hc->chan[ch].port] = 1;
+
+	/* empty fifo with what we have */
+	if (test_bit(FLG_HDLC, &chan->Flags)) {
+		if (debug & DEBUG_HFCMULTI_FIFO)
+			printk(KERN_DEBUG "%s: fifo(%d) reading %d bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) got=%d\n",
+				__FUNCTION__, ch, Zsize, z1, z2,
+				(f1 == f2) ? "fragment" : "COMPLETE",
+				f1, f2, Zsize + chan->rx_skb->len);
+		/* HDLC */
+		if ((Zsize + chan->rx_skb->len) > (chan->maxlen + 3)) {
+			if (debug & DEBUG_HFCMULTI_FIFO)
+				printk(KERN_DEBUG "%s: hdlc-frame too large.\n", __FUNCTION__);
+			skb_trim(chan->rx_skb, 0);
+			HFC_outb_(hc, R_INC_RES_FIFO, V_RES_F);
+			HFC_wait_(hc);
+			return;
+		}
+
+		read_fifo_data(hc, skb_put(chan->rx_skb, Zsize), Zsize);
+
+		if (f1 != f2) {
+			/* increment Z2,F2-counter */
+			HFC_outb_(hc, R_INC_RES_FIFO, V_INC_F);
+			HFC_wait_(hc);
+			/* check size */
+			if (chan->rx_skb->len < 4) {
+				if (debug & DEBUG_HFCMULTI_FIFO)
+					printk(KERN_DEBUG "%s: Frame below minimum size\n", __FUNCTION__);
+				skb_trim(chan->rx_skb, 0);
+				goto next_frame;
+			}
+			/* there is at least one complete frame, check crc */
+			if (chan->rx_skb->data[chan->rx_skb->len - 1]) {
+				if (debug & DEBUG_HFCMULTI_CRC)
+					printk(KERN_DEBUG "%s: CRC-error\n", __FUNCTION__);
+				mISDN_dt_new_frame(chan->inst.st, CRC_ERR, NULL, 0);
+				skb_trim(chan->rx_skb, 0);
+				goto next_frame;
+			}
+			/* only send dchannel if in active state */
+			if (test_bit(FLG_DCHANNEL, &chan->Flags) &&
+				hc->type == 1 && hc->chan[ch].e1_state != 1) {
+				skb_trim(chan->rx_skb, 0);
+				goto next_frame;
+			}
+			skb_trim(chan->rx_skb, chan->rx_skb->len - 3);
+			if (chan->rx_skb->len < MISDN_COPY_SIZE) {
+				skb = alloc_stack_skb(chan->rx_skb->len, chan->up_headerlen);
+				if (skb) {
+					memcpy(skb_put(skb, chan->rx_skb->len),
+						chan->rx_skb->data, chan->rx_skb->len);
+					skb_trim(chan->rx_skb, 0);
+				} else {
+					skb = chan->rx_skb;
+					chan->rx_skb = NULL;
+				}
+			} else {
+				skb = chan->rx_skb;
+				chan->rx_skb = NULL;
+			}
+			if (debug & DEBUG_HFCMULTI_FIFO) {
+				temp = 0;
+				while(temp < skb->len)
+					printk("%02x ", skb->data[temp++]);
+				printk("\n");
+			}
+			queue_ch_frame(chan, INDICATION, MISDN_ID_ANY, skb);
+			goto next_frame;
+		}
+		/* there is an incomplete frame */
+	} else {
+		/* transparent */
+		if (Zsize > skb_tailroom(chan->rx_skb))
+			Zsize = skb_tailroom(chan->rx_skb);
+		if (Zsize < MISDN_COPY_SIZE) {
+			skb = alloc_stack_skb(Zsize, chan->up_headerlen);
+			if (!skb) {
+				skb = chan->rx_skb;
+				chan->rx_skb = NULL;
+			}
+		} else {
+			skb = chan->rx_skb;
+			chan->rx_skb = NULL;
+		}
+		if (debug & DEBUG_HFCMULTI_FIFO)
+			printk(KERN_DEBUG "%s: fifo(%d) reading %d bytes (z1=%04x, z2=%04x) TRANS\n",
+				__FUNCTION__, ch, Zsize, z1, z2);
+		read_fifo_data(hc, skb_put(skb, Zsize), Zsize);
+		queue_ch_frame(chan, INDICATION, MISDN_ID_ANY, skb);
+	}
+}
+
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+
+static void signal_state_up(channel_t *dch, int dinfo, char *msg)
+{
+	struct sk_buff *skb;
+
+	if (debug & DEBUG_HFCMULTI_STATE)
+		 printk(KERN_DEBUG "%s: %s\n", __FUNCTION__,msg);
+
+	skb = create_link_skb(PH_CONTROL | INDICATION, dinfo, 0, NULL, 0);
+	if(!skb) return;
+
+	if (mISDN_queue_up(&dch->inst, 0, skb))
+		dev_kfree_skb(skb);
+}
+
+static inline void
+handle_timer_irq(hfc_multi_t *hc)
+{
+	int		ch, temp;
+	channel_t	*chan;
+
+	ch = 0;
+	while(ch < 32) {
+		chan = hc->chan[ch].ch;
+		if (chan && hc->created[hc->chan[ch].port]) {
+			hfcmulti_tx(hc, ch, chan);
+			/* fifo is started when switching to rx-fifo */
+			hfcmulti_rx(hc, ch, chan);
+			if (test_bit(FLG_DCHANNEL, &chan->Flags) &&
+				hc->chan[ch].nt_timer > -1) {
+				if (!(--hc->chan[ch].nt_timer)) {
+					ph_state_change(chan);
+					if (debug & DEBUG_HFCMULTI_STATE)
+						printk(KERN_DEBUG "%s: nt_timer at state %x\n",
+							__FUNCTION__, chan->state);
+				}
+			}
+		}
+		ch++;
+	}
+	if (hc->type == 1 && hc->created[0]) {
+		chan = hc->chan[16].ch;
+		if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[16].cfg)) {
+			if (debug & DEBUG_HFCMULTI_SYNC)
+				printk(KERN_DEBUG "%s: (id=%d) E1 got LOS\n",
+					__FUNCTION__, hc->id);
+					/* LOS */
+			temp = HFC_inb_(hc, R_RX_STA0) & V_SIG_LOS;
+			if (!temp && hc->chan[16].los)
+				signal_state_up(chan, HW_LOS, "LOS detected");
+			if (temp && !hc->chan[16].los)
+				signal_state_up(chan, HW_LOS_OFF, "LOS gone");
+			hc->chan[16].los = temp;
+		}
+		if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[16].cfg)) {
+			if (debug & DEBUG_HFCMULTI_SYNC)
+				printk(KERN_DEBUG "%s: (id=%d) E1 got AIS\n",
+					__FUNCTION__, hc->id);
+			/* AIS */
+			temp = HFC_inb_(hc, R_RX_STA0) & V_AIS;
+			if (!temp && hc->chan[16].ais)
+				signal_state_up(chan, HW_AIS, "AIS detected");
+			if (temp && !hc->chan[16].ais)
+				signal_state_up(chan, HW_AIS_OFF, "AIS gone");
+			hc->chan[16].ais = temp;
+		}
+		if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[16].cfg)) {
+			if (debug & DEBUG_HFCMULTI_SYNC)
+				printk(KERN_DEBUG "%s: (id=%d) E1 got SLIP (RX)\n",
+					__FUNCTION__, hc->id);
+			/* SLIP */
+			temp = HFC_inb_(hc, R_SLIP) & V_FOSLIP_RX;
+			if (!temp && hc->chan[16].slip_rx)
+				signal_state_up(chan, HW_SLIP_RX, " bit SLIP detected RX");
+			hc->chan[16].slip_rx = temp;
+			temp = HFC_inb_(hc, R_SLIP) & V_FOSLIP_TX;
+			if (!temp && hc->chan[16].slip_tx)
+				signal_state_up(chan, HW_SLIP_TX, " bit SLIP detected TX");
+			hc->chan[16].slip_tx = temp;
+		}
+		temp = HFC_inb_(hc, R_JATT_DIR);
+		switch(hc->chan[16].sync) {
+			case 0:
+				if ((temp & 0x60) == 0x60) {
+					if (debug & DEBUG_HFCMULTI_SYNC)
+						printk(KERN_DEBUG "%s: (id=%d) E1 now in clock sync\n",
+							__FUNCTION__, hc->id);
+					HFC_outb(hc, R_RX_OFF, hc->chan[16].jitter | V_RX_INIT);
+					HFC_outb(hc, R_TX_OFF, hc->chan[16].jitter | V_RX_INIT);
+					hc->chan[16].sync = 1;
+					goto check_framesync;
+				}
+				break;
+			case 1:
+				if ((temp & 0x60) != 0x60) {
+					if (debug & DEBUG_HFCMULTI_SYNC)
+						printk(KERN_DEBUG "%s: (id=%d) E1 lost clock sync\n",
+							__FUNCTION__, hc->id);
+					hc->chan[16].sync = 0;
+					break;
+				}
+				check_framesync:
+				temp = HFC_inb_(hc, R_RX_STA0);
+				if (temp == 0x27) {
+					if (debug & DEBUG_HFCMULTI_SYNC)
+						printk(KERN_DEBUG "%s: (id=%d) E1 now in frame sync\n",
+							__FUNCTION__, hc->id);
+					hc->chan[16].sync = 2;
+				}
+				break;
+			case 2:
+				if ((temp & 0x60) != 0x60) {
+					if (debug & DEBUG_HFCMULTI_SYNC)
+						printk(KERN_DEBUG "%s: (id=%d) E1 lost clock & frame sync\n",
+							__FUNCTION__, hc->id);
+					hc->chan[16].sync = 0;
+					break;
+				}
+				temp = HFC_inb_(hc, R_RX_STA0);
+				if (temp != 0x27) {
+					if (debug & DEBUG_HFCMULTI_SYNC)
+						printk(KERN_DEBUG "%s: (id=%d) E1 lost frame sync\n",
+							__FUNCTION__, hc->id);
+					hc->chan[16].sync = 1;
+				}
+				break;
+		}
+	}
+
+	if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) 
+		hfcmulti_watchdog(hc);
+
+	if (hc->leds)
+		hfcmulti_leds(hc);
+
+}
+
+static irqreturn_t
+hfcmulti_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+#ifdef IRQCOUNT_DEBUG
+	static int iq1=0,iq2=0,iq3=0,iq4=0,iq5=0,iq6=0,iqcnt=0;
+#endif
+	static int count=0;
+	hfc_multi_t	*hc = dev_id;
+	channel_t	*chan;
+	u_char 		r_irq_statech, status, r_irq_misc, r_irq_oview, r_irq_fifo_bl;
+	//u_char bl1,bl2;
+#ifdef CONFIG_PLX_PCI_BRIDGE
+	u_short *plx_acc,wval;
+#endif
+	int ch,i,j;
+
+#ifdef CONFIG_PLX_PCI_BRIDGE
+	plx_acc=(u_short*)(hc->plx_membase+0x4c);
+	wval=*plx_acc;
+	if(!(wval&0x04))
+	{
+		if(wval&0x20)
+		{
+			//printk(KERN_WARNING "NO irq  LINTI1:%x\n",wval);
+			printk(KERN_WARNING "got irq  LINTI2\n");
+		}
+		return(IRQ_NONE);
+	}
+#endif
+
+	spin_lock(&hc->lock);
+
+	if (!hc) {
+		printk(KERN_WARNING "HFC-multi: Spurious interrupt!\n");
+		irq_notforus:
+
+#ifdef CONFIG_PLX_PCI_BRIDGE
+	//plx_acc=(u_short*)(hc->plx_membase+0x4c);
+	//*plx_acc=0xc00;  // clear LINTI1 & LINTI2
+	//*plx_acc=0xc41;
+#endif
+		spin_unlock(&hc->lock);
+		return(IRQ_NONE);
+	}
+	status = HFC_inb_(hc, R_STATUS);
+	r_irq_statech = HFC_inb_(hc, R_IRQ_STATECH);
+#ifdef IRQCOUNT_DEBUG
+	if (r_irq_statech)
+		iq1++;
+	if (status&V_DTMF_STA)
+		iq2++;
+	if (status&V_LOST_STA)
+		iq3++;
+	if (status&V_EXT_IRQSTA)
+		iq4++;
+	if (status&V_MISC_IRQSTA)
+		iq5++;
+	if (status&V_FR_IRQSTA)
+		iq6++;
+	if (iqcnt++ > 5000) {
+		printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n",iq1,iq2,iq3,iq4,iq5,iq6);
+		iqcnt=0;
+	}
+#endif
+	if (!r_irq_statech && !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | V_MISC_IRQSTA | V_FR_IRQSTA))) {
+		/* irq is not for us */
+		//if(status) printk(KERN_WARNING "nofus:%x\n",status);
+		goto irq_notforus;
+	}
+	hc->irqcnt++;
+	if (r_irq_statech) {
+		if (hc->type != 1) {
+			/* state machine */
+			ch = 0;
+			while(ch < 32) {
+				chan = hc->chan[ch].ch;
+				if (chan && test_bit(FLG_DCHANNEL, &chan->Flags)) {
+					if (r_irq_statech & 1) {
+						HFC_outb_(hc, R_ST_SEL, hc->chan[ch].port);
+						chan->state = HFC_inb(hc, A_ST_RD_STATE) & 0x0f;
+						if (chan->state == (test_bit(HFC_CFG_NTMODE,
+							&hc->chan[chan->channel].cfg) ? 3: 7)) {
+							HFC_outb_(hc, R_FIFO, (ch<<1) | 1);
+							HFC_wait_(hc);
+							HFC_outb_(hc, R_INC_RES_FIFO, V_RES_F);
+							HFC_wait_(hc);
+							chan->tx_idx=0;
+						}
+						ph_state_change(chan);
+						if (debug & DEBUG_HFCMULTI_STATE)
+							printk(KERN_DEBUG "%s: S/T newstate %x port %d\n",
+								__FUNCTION__, chan->state, hc->chan[ch].port);
+						dt_newstate(chan->inst.st,
+						    chan->state, "S/T");
+					}
+					r_irq_statech >>= 1;
+				}
+				ch++;
+			}
+		}
+	}
+	if (status & V_EXT_IRQSTA) {
+		/* external IRQ */
+	}
+	if (status & V_LOST_STA) {
+		/* LOST IRQ */
+		HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */
+	}
+	if (status & V_MISC_IRQSTA) {
+		/* misc IRQ */
+		r_irq_misc = HFC_inb_(hc, R_IRQ_MISC);
+		if (r_irq_misc & V_STA_IRQ) {
+			if (hc->type == 1) {
+				/* state machine */
+				chan = hc->chan[16].ch;
+				chan->state = HFC_inb_(hc, R_E1_RD_STA) & 0x7;
+				ph_state_change(chan);
+				if (debug & DEBUG_HFCMULTI_STATE)
+					printk(KERN_DEBUG "%s: E1 newstate %x\n",
+						__FUNCTION__, chan->state);
+				dt_newstate(chan->inst.st, chan->state, "E1");
+			}
+		}
+		if (r_irq_misc & V_TI_IRQ)
+			handle_timer_irq(hc);
+
+		if (r_irq_misc & V_DTMF_IRQ) {
+			/* -> DTMF IRQ */
+			hfcmulti_dtmf(hc);
+		}
+		if (r_irq_misc & V_IRQ_PROC) {
+			/* IRQ every 125us */
+			count++;
+			/* generate 1kHz signal */
+			if(count==8) {
+				if (hfc_interrupt) 
+					hfc_interrupt();
+				count = 0;
+			}
+		}
+				 
+	}
+	if (status & V_FR_IRQSTA) {
+		/* FIFO IRQ */
+		r_irq_oview = HFC_inb_(hc, R_IRQ_OVIEW);
+		//if(r_irq_oview) printk(KERN_DEBUG "OV:%x\n",r_irq_oview);
+		i = 0;
+		while(i < 8) {
+			if (r_irq_oview & (1 << i)) {
+				r_irq_fifo_bl = HFC_inb_(hc, R_IRQ_FIFO_BL0 + i);
+				//r_irq_fifo_bl = HFC_inb_(hc, R_INT_DATA);
+				//if(r_irq_fifo_bl) printk(KERN_DEBUG "BL%d:%x\n",i,r_irq_fifo_bl);
+				//bl1 = HFC_inb_(hc, R_IRQ_FIFO_BL0);
+				//bl2 = HFC_inb_(hc, R_IRQ_FIFO_BL0);
+				//printk(KERN_DEBUG "zero:%x :%x\n",bl1,bl2);
+				r_irq_fifo_bl = HFC_inb_(hc, R_IRQ_FIFO_BL0 + i);
+				j = 0;
+				while(j < 8) {
+					ch = (i<<2) + (j>>1);
+					if (ch >= 16) {
+						if (ch == 16)
+							printk("Shouldn't be servicing high FIFOs.  Continuing.\n");
+						continue;
+					}
+					chan = hc->chan[ch].ch;
+					if (r_irq_fifo_bl & (1 << j)) {
+						if (chan && hc->created[hc->chan[ch].port] &&
+							test_bit(FLG_ACTIVE, &chan->Flags)) {
+							//printk(KERN_DEBUG "txchan:%d\n",ch);
+							hfcmulti_tx(hc, ch, chan);
+							/* start fifo */
+							HFC_outb_(hc, R_FIFO, 0);
+							HFC_wait_(hc);
+						}
+					}
+					j++;
+					if (r_irq_fifo_bl & (1 << j)) {
+						if (chan && hc->created[hc->chan[ch].port] &&
+							test_bit(FLG_ACTIVE, &chan->Flags)) {
+							hfcmulti_rx(hc, ch, chan);
+							//printk(KERN_DEBUG "rxchan:%d\n",ch);
+						}
+					}
+					j++;
+				}
+			}
+			i++;
+		}
+	}
+
+#ifdef CONFIG_PLX_PCI_BRIDGE
+	//plx_acc=(u_short*)(hc->plx_membase+0x4c);
+	//*plx_acc=0xc00;  // clear LINTI1 & LINTI2
+	//*plx_acc=0xc41;
+#endif
+	spin_unlock(&hc->lock);
+	return(IRQ_HANDLED);
+}
+
+
+/********************************************************************/
+/* timer callback for D-chan busy resolution. Currently no function */
+/********************************************************************/
+
+static void
+hfcmulti_dbusy_timer(hfc_multi_t *hc)
+{
+}
+
+
+/***************************************************************/
+/* activate/deactivate hardware for selected channels and mode */
+/***************************************************************/
+
+/* configure B-channel with the given protocol
+ * ch eqals to the HFC-channel (0-31)
+ * ch is the number of channel (0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31 for S/T, 1-31 for E1)
+ * the hdlc interrupts will be set/unset
+ *
+ */
+static int
+mode_hfcmulti(hfc_multi_t *hc, int ch, int protocol, int slot_tx, int bank_tx, int slot_rx, int bank_rx)
+{
+	int flow_tx = 0, flow_rx = 0, routing = 0;
+	int oslot_tx = hc->chan[ch].slot_tx;
+	int oslot_rx = hc->chan[ch].slot_rx;
+	int conf = hc->chan[ch].conf;
+
+	if (debug & DEBUG_HFCMULTI_MODE)
+		printk(KERN_DEBUG "%s: channel %d protocol %x slot %d bank %d (TX) slot %d bank %d (RX)\n",
+			__FUNCTION__, ch, protocol, slot_tx, bank_tx, slot_rx, bank_rx);
+
+	if (oslot_tx>=0 && slot_tx!=oslot_tx) {
+		/* remove from slot */
+		if (debug & DEBUG_HFCMULTI_MODE)
+			printk(KERN_DEBUG "%s: remove from slot %d (TX)\n", __FUNCTION__, oslot_tx);
+		if (hc->slot_owner[oslot_tx<<1] == ch) {
+			HFC_outb(hc, R_SLOT, oslot_tx<<1);
+			HFC_outb(hc, A_SL_CFG, 0);
+			HFC_outb(hc, A_CONF, 0);
+			hc->slot_owner[oslot_tx<<1] = -1;
+		} else {
+			if (debug & DEBUG_HFCMULTI_MODE)
+				printk(KERN_DEBUG "%s: we are not owner of this slot anymore, channel %d is.\n", __FUNCTION__, hc->slot_owner[oslot_tx<<1]);
+		}
+	}
+
+	if (oslot_rx>=0 && slot_rx!=oslot_rx) {
+		/* remove from slot */
+		if (debug & DEBUG_HFCMULTI_MODE)
+			printk(KERN_DEBUG "%s: remove from slot %d (RX)\n", __FUNCTION__, oslot_rx);
+		if (hc->slot_owner[(oslot_rx<<1)|1] == ch) {
+			HFC_outb(hc, R_SLOT, (oslot_rx<<1) | V_SL_DIR);
+			HFC_outb(hc, A_SL_CFG, 0);
+			hc->slot_owner[(oslot_rx<<1)|1] = -1;
+		} else {
+			if (debug & DEBUG_HFCMULTI_MODE)
+				printk(KERN_DEBUG "%s: we are not owner of this slot anymore, channel %d is.\n", __FUNCTION__, hc->slot_owner[(oslot_rx<<1)|1]);
+		}
+	}
+
+	if (slot_tx < 0) {
+		flow_tx = 0x80; /* FIFO->ST */
+		/* disable pcm slot */
+		hc->chan[ch].slot_tx = -1;
+		hc->chan[ch].bank_tx = 0;
+	} else {
+		/* set pcm slot */
+		if (hc->chan[ch].txpending)
+			flow_tx = 0x80; /* FIFO->ST */
+		else
+			flow_tx = 0xc0; /* PCM->ST */
+		/* put on slot */
+		routing = bank_tx?0xc0:0x80;
+		if (conf>=0 || bank_tx>1)
+			routing = 0x40; /* loop */
+		if (debug & DEBUG_HFCMULTI_MODE)
+			printk(KERN_DEBUG "%s: put to slot %d bank %d flow %02x routing %02x conf %d (TX)\n", __FUNCTION__, slot_tx, bank_tx, flow_tx, routing, conf);
+		HFC_outb(hc, R_SLOT, slot_tx<<1);
+		HFC_outb(hc, A_SL_CFG, (ch<<1) | routing);
+		HFC_outb(hc, A_CONF, (conf<0)?0:(conf|V_CONF_SL));
+		hc->slot_owner[slot_tx<<1] = ch;
+		hc->chan[ch].slot_tx = slot_tx;
+		hc->chan[ch].bank_tx = bank_tx;
+	}
+	if (slot_rx < 0) {
+		/* disable pcm slot */
+		flow_rx = 0x80; /* ST->FIFO */
+		hc->chan[ch].slot_rx = -1;
+		hc->chan[ch].bank_rx = 0;
+	} else {
+		/* set pcm slot */
+		if (hc->chan[ch].txpending)
+			flow_rx = 0x80; /* ST->FIFO */
+		else
+			flow_rx = 0xc0; /* ST->(FIFO,PCM) */
+		/* put on slot */
+		routing = bank_rx?0x80:0xc0; /* reversed */
+		if (conf >= 0 || bank_rx > 1)
+			routing = 0x40; /* loop */
+		if (debug & DEBUG_HFCMULTI_MODE)
+			printk(KERN_DEBUG "%s: put to slot %d bank %d flow %02x routing %02x conf %d (RX)\n",
+				__FUNCTION__, slot_rx, bank_rx, flow_rx, routing, conf);
+		HFC_outb(hc, R_SLOT, (slot_rx<<1) | V_SL_DIR);
+		HFC_outb(hc, A_SL_CFG, (ch<<1) | V_CH_DIR | routing);
+		hc->slot_owner[(slot_rx<<1)|1] = ch;
+		hc->chan[ch].slot_rx = slot_rx;
+		hc->chan[ch].bank_rx = bank_rx;
+	}
+
+	switch (protocol) {
+		case (ISDN_PID_NONE):
+			/* disable TX fifo */
+			HFC_outb(hc, R_FIFO, ch << 1);
+			HFC_wait(hc);
+			HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF);
+			HFC_outb(hc, A_SUBCH_CFG, 0);
+			HFC_outb(hc, A_IRQ_MSK, 0);
+			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+			HFC_wait(hc);
+			/* disable RX fifo */
+			HFC_outb(hc, R_FIFO, (ch<<1)|1);
+			HFC_wait(hc);
+			HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00);
+			HFC_outb(hc, A_SUBCH_CFG, 0);
+			HFC_outb(hc, A_IRQ_MSK, 0);
+			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+			HFC_wait(hc);
+			if (hc->type == 1) {
+			} else if ((ch & 0x3) < 2) {
+				hc->hw.a_st_ctrl0[hc->chan[ch].port] &= ((ch & 0x3) == 0)? ~V_B1_EN: ~V_B2_EN;
+				HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
+				HFC_outb(hc, A_ST_CTRL0,  hc->hw.a_st_ctrl0[hc->chan[ch].port]);
+			}
+			if (test_bit(FLG_BCHANNEL, &hc->chan[ch].ch->Flags)) {
+				test_and_clear_bit(FLG_HDLC, &hc->chan[ch].ch->Flags);
+				test_and_clear_bit(FLG_TRANSPARENT, &hc->chan[ch].ch->Flags);
+			}
+			break;
+		case (ISDN_PID_L1_B_64TRANS): /* B-channel */
+
+#ifdef B410P_CARD
+			if (test_bit(HFC_CHIP_DIGICARD, &hc->chip) && (hc->chan[ch].slot_rx < 0) && (hc->chan[ch].bank_rx == 0)
+					&& (hc->chan[ch].slot_tx < 0) && (hc->chan[ch].bank_tx == 0)) {
+
+				printk("Setting B-channel %d to echo cancelable state on PCM slot %d\n", ch,
+						((ch/4)*8) + ((ch%4)*4) + 1);
+				printk("Enabling pass through for channel\n");
+				vpm_out(hc, ch, ((ch/4)*8) + ((ch%4)*4) + 1, 0x01);
+				/* rx path */
+				/* S/T -> PCM */
+				HFC_outb(hc, R_FIFO, (ch << 1));
+				HFC_wait(hc);
+				HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF);
+				HFC_outb(hc, R_SLOT, (((ch/4)*8) + ((ch%4)*4) + 1) << 1);
+				HFC_outb(hc, A_SL_CFG, 0x80 | (ch << 1));
+
+				/* PCM -> FIFO */
+				HFC_outb(hc, R_FIFO, 0x20 | (ch << 1) | 1);
+				HFC_wait(hc);
+				HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF);
+				HFC_outb(hc, A_SUBCH_CFG, 0);
+				HFC_outb(hc, A_IRQ_MSK, 0);
+				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+				HFC_wait(hc);
+				HFC_outb(hc, R_SLOT, ((((ch/4)*8) + ((ch%4)*4) + 1) << 1) | 1);
+				HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1);
+
+				/* tx path */
+				/* PCM -> S/T */
+				HFC_outb(hc, R_FIFO, (ch << 1) | 1);
+				HFC_wait(hc);
+				HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF);
+				HFC_outb(hc, R_SLOT, ((((ch/4)*8) + ((ch%4)*4)) << 1) | 1);
+				HFC_outb(hc, A_SL_CFG, 0x80 | 0x40 | (ch << 1) | 1);
+
+				/* FIFO -> PCM */
+				HFC_outb(hc, R_FIFO, 0x20 | (ch << 1));
+				HFC_wait(hc);
+				HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF);
+				HFC_outb(hc, A_SUBCH_CFG, 0);
+				HFC_outb(hc, A_IRQ_MSK, 0);
+				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+				HFC_wait(hc);
+				HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence); /* tx silence */
+				HFC_outb(hc, R_SLOT, (((ch/4)*8) + ((ch%4)*4)) << 1);
+				HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1));
+			} else 
+#endif	
+			{
+				/* enable TX fifo */
+				HFC_outb(hc, R_FIFO, ch<<1);
+				HFC_wait(hc);
+				HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_HDLC_TRP | V_IFF);
+				HFC_outb(hc, A_SUBCH_CFG, 0);
+				HFC_outb(hc, A_IRQ_MSK, 0);
+				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+				HFC_wait(hc);
+				HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence); /* tx silence */
+				/* enable RX fifo */
+				HFC_outb(hc, R_FIFO, (ch<<1)|1);
+				HFC_wait(hc);
+				HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | V_HDLC_TRP);
+				HFC_outb(hc, A_SUBCH_CFG, 0);
+				HFC_outb(hc, A_IRQ_MSK, 0);
+				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+				HFC_wait(hc);
+			}
+			if (hc->type != 1) {
+				hc->hw.a_st_ctrl0[hc->chan[ch].port] |= ((ch&0x3)==0)?V_B1_EN:V_B2_EN;
+				HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
+				HFC_outb(hc, A_ST_CTRL0,  hc->hw.a_st_ctrl0[hc->chan[ch].port]);
+			}
+			if (test_bit(FLG_BCHANNEL, &hc->chan[ch].ch->Flags))
+				test_and_set_bit(FLG_TRANSPARENT, &hc->chan[ch].ch->Flags);
+			break;
+		case (ISDN_PID_L1_B_64HDLC): /* B-channel */
+		case (ISDN_PID_L1_TE_E1): /* D-channel E1 */
+		case (ISDN_PID_L1_NT_E1):
+			/* enable TX fifo */
+			HFC_outb(hc, R_FIFO, ch<<1);
+			HFC_wait(hc);
+			HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04);
+			HFC_outb(hc, A_SUBCH_CFG, 0);
+			HFC_outb(hc, A_IRQ_MSK, V_IRQ);
+			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+			HFC_wait(hc);
+			/* enable RX fifo */
+			HFC_outb(hc, R_FIFO, (ch<<1)|1);
+			HFC_wait(hc);
+			HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04);
+			HFC_outb(hc, A_SUBCH_CFG, 0);
+			HFC_outb(hc, A_IRQ_MSK, V_IRQ);
+			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+			HFC_wait(hc);
+			if (hc->type == 1) {
+			} else {
+				hc->hw.a_st_ctrl0[hc->chan[ch].port] |= ((ch&0x3)==0)?V_B1_EN:V_B2_EN;
+				HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
+				HFC_outb(hc, A_ST_CTRL0,  hc->hw.a_st_ctrl0[hc->chan[ch].port]);
+			}
+			if (test_bit(FLG_BCHANNEL, &hc->chan[ch].ch->Flags))
+				test_and_set_bit(FLG_HDLC, &hc->chan[ch].ch->Flags);
+			break;
+
+		case (ISDN_PID_L1_TE_S0): /* D-channel S0 */
+		case (ISDN_PID_L1_NT_S0):
+			/* enable TX fifo */
+			HFC_outb(hc, R_FIFO, ch<<1);
+			HFC_wait(hc);
+			HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF);
+			HFC_outb(hc, A_SUBCH_CFG, 2);
+			HFC_outb(hc, A_IRQ_MSK, V_IRQ);
+			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+			HFC_wait(hc);
+			/* enable RX fifo */
+			HFC_outb(hc, R_FIFO, (ch<<1)|1);
+			HFC_wait(hc);
+			HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04);
+			HFC_outb(hc, A_SUBCH_CFG, 2);
+			HFC_outb(hc, A_IRQ_MSK, V_IRQ);
+			HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+			HFC_wait(hc);
+			break;
+
+		default:
+			printk(KERN_DEBUG "%s: protocol not known %x\n", __FUNCTION__, protocol);
+			hc->chan[ch].protocol = ISDN_PID_NONE;
+			return(-ENOPROTOOPT);
+	}
+	hc->chan[ch].protocol = protocol;
+	return(0);
+}
+
+
+/**************************/
+/* connect/disconnect PCM */
+/**************************/
+
+static void
+hfcmulti_pcm(hfc_multi_t *hc, int ch, int slot_tx, int bank_tx, int slot_rx, int bank_rx)
+{
+	if (slot_rx<0 || slot_rx<0 || bank_tx<0 || bank_rx<0) {
+		/* disable PCM */
+		mode_hfcmulti(hc, ch, hc->chan[ch].protocol, -1, 0, -1, 0);
+		return;
+	}
+
+	/* enable pcm */
+	mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx,
+		slot_rx, bank_rx);
+}
+
+
+/**************************/
+/* set/disable conference */
+/**************************/
+
+static void
+hfcmulti_conf(hfc_multi_t *hc, int ch, int num)
+{
+	if (num>=0 && num<=7)
+		hc->chan[ch].conf = num;
+	else
+		hc->chan[ch].conf = -1;
+	mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx,
+		hc->chan[ch].bank_tx, hc->chan[ch].slot_rx, hc->chan[ch].bank_rx);
+}
+
+
+/***************************/
+/* set/disable sample loop */
+/***************************/
+// NOTE: this function is experimental and therefore disabled
+static void
+hfcmulti_splloop(hfc_multi_t *hc, int ch, u_char *data, int len)
+{
+	channel_t *bch = hc->chan[ch].ch;
+
+	/* flush pending TX data */
+	if (bch->next_skb) {
+		test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+		dev_kfree_skb(bch->next_skb);
+		bch->next_skb = NULL;
+	}
+	bch->tx_idx = 0;
+
+	/* prevent overflow */
+	if (len > hc->Zlen-1)
+		len = hc->Zlen-1;
+
+	/* select fifo */
+	HFC_outb_(hc, R_FIFO, ch<<1);
+	HFC_wait_(hc);
+
+	/* reset fifo */
+	HFC_outb(hc, A_SUBCH_CFG, 0);
+	udelay(500);
+	HFC_outb_(hc, R_INC_RES_FIFO, V_RES_F);
+	HFC_wait_(hc);
+	udelay(500);
+
+	/* if off */
+	if (len <= 0) {
+		HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence);
+		if (hc->chan[ch].slot_tx>=0) {
+			if (debug & DEBUG_HFCMULTI_MODE)
+				printk(KERN_DEBUG "%s: connecting PCM due to no more TONE: channel %d slot_tx %d\n", __FUNCTION__, ch, hc->chan[ch].slot_tx);
+			/* connect slot */
+			HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | V_HDLC_TRP | V_IFF);
+			HFC_outb(hc, R_FIFO, ch<<1 | 1);
+			HFC_wait(hc);
+			HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | V_HDLC_TRP | V_IFF);
+		}
+		hc->chan[ch].txpending = 0;
+		return;
+	}
+
+	/* loop fifo */
+
+	/* set mode */
+	hc->chan[ch].txpending = 2;
+
+//printk("len=%d %02x %02x %02x\n", len, data[0], data[1], data[2]);
+	/* write loop data */
+	write_fifo_data(hc,data,len);
+
+	udelay(500);
+	HFC_outb(hc, A_SUBCH_CFG, V_LOOP_FIFO);
+	udelay(500);
+
+	/* disconnect slot */
+	if (hc->chan[ch].slot_tx>=0) {
+		if (debug & DEBUG_HFCMULTI_MODE)
+			printk(KERN_DEBUG "%s: disconnecting PCM due to TONE: channel %d slot_tx %d\n", __FUNCTION__, ch, hc->chan[ch].slot_tx);
+		HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF);
+		HFC_outb(hc, R_FIFO, ch<<1 | 1);
+		HFC_wait(hc);
+		HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF);
+		HFC_outb(hc, R_FIFO, ch<<1);
+		HFC_wait(hc);
+	} else {
+		/* change fifo */
+		HFC_outb(hc, R_FIFO, ch<<1);
+		HFC_wait(hc);
+	}
+
+//udelay(300);
+}
+
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+
+static int
+handle_dmsg(channel_t *ch, struct sk_buff *skb)
+{
+
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	hfc_multi_t	*hc = ch->inst.privat;
+	int		slot_tx, slot_rx, bank_tx, bank_rx;
+	int		ret = -EAGAIN;
+	u_long		flags;
+
+	if (hh->prim == (PH_SIGNAL | REQUEST)) {
+		spin_lock_irqsave(ch->inst.hwlock, flags);
+		switch (hh->dinfo) {
+			case INFO3_P8:
+			case INFO3_P10:
+				break;
+			default:
+				printk(KERN_DEBUG "%s: unknown PH_SIGNAL info %x\n",
+					__FUNCTION__, hh->dinfo);
+				ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(ch->inst.hwlock, flags);
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		spin_lock_irqsave(ch->inst.hwlock, flags);
+		ret = 0;
+		switch (hh->dinfo) {
+			case HW_RESET:
+				/* start activation */
+				if (hc->type == 1) {
+					HFC_outb(hc, R_E1_WR_STA, V_E1_LD_STA | 0);
+					udelay(6); /* wait at least 5,21us */
+					HFC_outb(hc, R_E1_WR_STA, 0);
+				} else {
+					HFC_outb(hc, R_ST_SEL, hc->chan[ch->channel].port);
+					HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* G1 */
+					udelay(6); /* wait at least 5,21us */
+					HFC_outb(hc, A_ST_WR_STATE, 3);
+					HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT*3)); /* activate */
+				}
+				spin_unlock_irqrestore(ch->inst.hwlock, flags);
+				skb_trim(skb, 0);
+				return(mISDN_queueup_newhead(&ch->inst, 0, PH_CONTROL | INDICATION,HW_POWERUP, skb));
+			case HW_DEACTIVATE:
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_DEBUG "%s: HW_DEACTIVATE\n",
+						__FUNCTION__);
+				goto hw_deactivate; /* after lock */
+			case HW_PCM_CONN: /* connect interface to pcm timeslot (0..N) */
+				if (skb->len < 4*sizeof(u_long)) {
+					printk(KERN_WARNING "%s: HW_PCM_CONN lacks parameters\n",
+						__FUNCTION__);
+					break;
+				}
+				slot_tx = ((int *)skb->data)[0];
+				bank_tx = ((int *)skb->data)[1];
+				slot_rx = ((int *)skb->data)[2];
+				bank_rx = ((int *)skb->data)[3];
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_INFO "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX)\n",
+						__FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx);
+				if (slot_tx <= hc->slots && bank_tx <=2 &&
+					slot_rx <= hc->slots && bank_rx <= 2)
+					hfcmulti_pcm(hc, ch->channel, slot_tx,
+						bank_tx, slot_rx, bank_rx);
+				else
+					printk(KERN_WARNING "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX) out of range\n",
+						__FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx);
+				break;
+			case HW_PCM_DISC: /* release interface from pcm timeslot */
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_INFO "%s: HW_PCM_DISC\n",
+						__FUNCTION__);
+				hfcmulti_pcm(hc, ch->channel, -1, -1, -1, -1);
+				break;
+			case HW_POWERUP:
+				HFC_outb(hc, R_ST_SEL, hc->chan[ch->channel].port);
+				HFC_outb(hc, A_ST_WR_STATE, 3 | 0x10); /* activate */
+				udelay(6); /* wait at least 5,21us */
+				HFC_outb(hc, A_ST_WR_STATE, 3); /* activate */
+				break;
+			default:
+				printk(KERN_DEBUG "%s: unknown PH_CONTROL info %x\n",
+					__FUNCTION__, hh->dinfo);
+				ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(ch->inst.hwlock, flags);
+	} else if (hh->prim == (PH_ACTIVATE | REQUEST)) {
+		if (test_bit(HFC_CFG_NTMODE, &hc->chan[ch->channel].cfg)) {
+			if (debug & DEBUG_HFCMULTI_MSG)
+				printk(KERN_DEBUG "%s: PH_ACTIVATE port %d (0..%d)\n",
+					__FUNCTION__, hc->chan[ch->channel].port, hc->ports-1);
+			spin_lock_irqsave(ch->inst.hwlock, flags);
+			/* start activation */
+			if (hc->type == 1) {
+				//chanannel_sched_event(chan, D_L1STATECHANGE);
+				ph_state_change(ch);
+				if (debug & DEBUG_HFCMULTI_STATE)
+					printk(KERN_DEBUG "%s: E1 report state %x \n",
+						__FUNCTION__, ch->state);
+			} else {
+				HFC_outb(hc, R_ST_SEL, hc->chan[ch->channel].port);
+				HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1); /* G1 */
+				udelay(6); /* wait at least 5,21us */
+				HFC_outb(hc, A_ST_WR_STATE, 1);
+				HFC_outb(hc, A_ST_WR_STATE, 1 | (V_ST_ACT*3)); /* activate */
+				ch->state = 1;
+			}
+			spin_unlock_irqrestore(ch->inst.hwlock, flags);
+			ret = 0;
+		} else {
+			if (debug & DEBUG_HFCMULTI_MSG)
+				printk(KERN_DEBUG "%s: PH_ACTIVATE no NT-mode port %d (0..%d)\n",
+					__FUNCTION__, hc->chan[ch->channel].port, hc->ports-1);
+			ret = -EINVAL;
+		}
+	} else if (hh->prim == (PH_DEACTIVATE | REQUEST)) {
+		if (test_bit(HFC_CFG_NTMODE, &hc->chan[ch->channel].cfg)) {
+			if (debug & DEBUG_HFCMULTI_MSG)
+				printk(KERN_DEBUG "%s: PH_DEACTIVATE port %d (0..%d)\n",
+					__FUNCTION__, hc->chan[ch->channel].port, hc->ports-1);
+			spin_lock_irqsave(ch->inst.hwlock, flags);
+hw_deactivate:
+			//ch->state = 0;
+			ch->state = 1;
+
+			/* start deactivation */
+			if (hc->type == 1) {
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_DEBUG "%s: PH_DEACTIVATE no BRI\n",
+						__FUNCTION__);
+			} else {
+				HFC_outb(hc, R_ST_SEL, hc->chan[ch->channel].port);
+				HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT*2); /* deactivate */
+			}
+			if (ch->next_skb) {
+				dev_kfree_skb(ch->next_skb);
+				ch->next_skb = NULL;
+			}
+			if (ch->rx_skb) {
+				dev_kfree_skb(ch->rx_skb);
+				ch->rx_skb = NULL;
+			}
+			ch->tx_idx = 0;
+			if (ch->tx_skb) {
+				dev_kfree_skb(ch->tx_skb);
+				ch->tx_skb = NULL;
+			}
+			test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
+			test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
+			if (test_and_clear_bit(FLG_BUSY_TIMER, &ch->Flags))
+				del_timer(&ch->timer);
+			spin_unlock_irqrestore(ch->inst.hwlock, flags);
+			ret = 0;
+		} else {
+			if (debug & DEBUG_HFCMULTI_MSG)
+				printk(KERN_DEBUG "%s: PH_DEACTIVATE no NT-mode port %d (0..%d)\n",
+					__FUNCTION__, hc->chan[ch->channel].port, hc->ports-1);
+			ret = -EINVAL;
+		}
+	} else if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS) {
+		u_int		temp = hh->dinfo & SSTATUS_ALL; // remove SSTATUS_BROADCAST_BIT
+		if (((hc->type == 1) || test_bit(HFC_CFG_NTMODE,
+			&hc->chan[ch->channel].cfg)) &&
+			(temp == SSTATUS_ALL || temp == SSTATUS_L1)) {
+			if (hh->dinfo & SSTATUS_BROADCAST_BIT)
+				temp = ch->inst.id | MSG_BROADCAST;
+			else
+				temp = hh->addr | FLG_MSG_TARGET;
+			skb_trim(skb, 0);
+			hh->dinfo = test_bit(FLG_ACTIVE, &ch->Flags) ?
+				SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED;
+			hh->prim = MGR_SHORTSTATUS | CONFIRM;
+			return(mISDN_queue_message(&ch->inst, temp, skb));
+		}
+		ret = -EOPNOTSUPP;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+static int
+handle_bmsg(channel_t *ch, struct sk_buff *skb)
+{
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	hfc_multi_t	*hc = ch->inst.privat;
+	u_long		flags, num;
+	int		slot_tx, slot_rx, bank_tx, bank_rx;
+	int		ret = -EAGAIN;
+	struct		dsp_features *features;
+	int taps;
+
+	if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_ESTABLISH  | REQUEST))) {
+		/* activate B-channel if not already activated */
+		if (debug & DEBUG_HFCMULTI_MSG)
+			printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n",
+				__FUNCTION__, ch->channel);
+		if (!test_and_set_bit(FLG_ACTIVE, &ch->Flags)) {
+			spin_lock_irqsave(ch->inst.hwlock, flags);
+			if (ch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				test_and_set_bit(FLG_L2DATA, &ch->Flags);
+			ret = mode_hfcmulti(hc, ch->channel,
+				ch->inst.pid.protocol[1],
+				hc->chan[ch->channel].slot_tx,
+				hc->chan[ch->channel].bank_tx,
+				hc->chan[ch->channel].slot_rx,
+				hc->chan[ch->channel].bank_rx);
+			if (!ret) {
+				if (ch->inst.pid.protocol[1] ==
+					 ISDN_PID_L1_B_64TRANS && !hc->dtmf) {
+					/* start decoder */
+					hc->dtmf = 1;
+					if (debug & DEBUG_HFCMULTI_DTMF)
+						printk(KERN_DEBUG "%s: start dtmf decoder\n",
+							__FUNCTION__);
+					HFC_outb(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF);
+				}
+			}
+			spin_unlock_irqrestore(ch->inst.hwlock, flags);
+		} else
+			ret = 0;
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(&ch->inst, 0, hh->prim | CONFIRM, ret, skb));
+	} 
+	if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_RELEASE | REQUEST)) ||
+		((hh->prim == (PH_CONTROL | REQUEST) &&
+		(hh->dinfo == HW_DEACTIVATE)))) {
+		if (debug & DEBUG_HFCMULTI_MSG)
+			printk(KERN_DEBUG "%s: PH_DEACTIVATE ch %d (0..32)\n",
+				__FUNCTION__, ch->channel);
+		/* deactivate B-channel if not already deactivated */
+		spin_lock_irqsave(ch->inst.hwlock, flags);
+		if (ch->next_skb) {
+			test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
+			dev_kfree_skb(ch->next_skb);
+			ch->next_skb = NULL;
+		}
+		if (ch->tx_skb) {
+			dev_kfree_skb(ch->tx_skb);
+			ch->tx_skb = NULL;
+		}
+		ch->tx_idx = 0;
+		if (ch->rx_skb) {
+			dev_kfree_skb(ch->rx_skb);
+			ch->rx_skb = NULL;
+		}
+		test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
+		hc->chan[ch->channel].slot_tx = -1;
+		hc->chan[ch->channel].slot_rx = -1;
+		hc->chan[ch->channel].conf = -1;
+		mode_hfcmulti(hc, ch->channel, ISDN_PID_NONE,
+			hc->chan[ch->channel].slot_tx,
+			hc->chan[ch->channel].bank_tx,
+			hc->chan[ch->channel].slot_rx,
+			hc->chan[ch->channel].bank_rx);
+		test_and_clear_bit(FLG_L2DATA, &ch->Flags);
+		test_and_clear_bit(FLG_ACTIVE, &ch->Flags);
+		spin_unlock_irqrestore(ch->inst.hwlock, flags);
+		skb_trim(skb, 0);
+		ret = 0;
+		if (hh->prim != (PH_CONTROL | REQUEST))
+			return(mISDN_queueup_newhead(&ch->inst, 0,
+				hh->prim | CONFIRM, ret, skb));
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		spin_lock_irqsave(ch->inst.hwlock, flags);
+		switch (hh->dinfo) {
+			case HW_FEATURES: /* fill features structure */
+				#warning this is dangerous, the skb should never used to transfer a pointer please use a message
+				if (skb->len != sizeof(void *)) {
+					printk(KERN_WARNING "%s: HW_FEATURES lacks parameters\n",
+						__FUNCTION__);
+					break;
+				}
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_DEBUG "%s: HW_FEATURE request\n",
+						__FUNCTION__);
+				features = *((struct dsp_features **)skb->data);
+				features->hfc_id = hc->id;
+				if (test_bit(HFC_CHIP_DTMF, &hc->chip))
+					features->hfc_dtmf = 1;
+				features->hfc_loops = 0;
+				features->pcm_id = hc->pcm;
+				features->pcm_slots = hc->slots;
+				features->pcm_banks = 2;
+				
+				if (test_bit(HFC_CHIP_DIGICARD, &hc->chip))
+					features->hfc_echocanhw=1;
+
+				ret = 0;
+				break;
+			case HW_PCM_CONN: /* connect interface to pcm timeslot (0..N) */
+				if (skb->len < 4*sizeof(s32)) {
+					printk(KERN_WARNING "%s: HW_PCM_CONN lacks parameters\n",
+						__FUNCTION__);
+					break;
+				}
+				slot_tx = ((s32 *)skb->data)[0];
+				bank_tx = ((s32 *)skb->data)[1];
+				slot_rx = ((s32 *)skb->data)[2];
+				bank_rx = ((s32 *)skb->data)[3];
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_DEBUG "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX)\n",
+						__FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx);
+				if (slot_tx <= hc->slots && bank_tx <= 2 &&
+					slot_rx <= hc->slots && bank_rx <= 2)
+					hfcmulti_pcm(hc, ch->channel, slot_tx, bank_tx, slot_rx, bank_rx);
+				else
+					printk(KERN_WARNING "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX) out of range\n",
+						__FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx);
+				ret = 0;
+				break;
+			case HW_PCM_DISC: /* release interface from pcm timeslot */
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_DEBUG "%s: HW_PCM_DISC\n",
+						__FUNCTION__);
+				hfcmulti_pcm(hc, ch->channel, -1, -1, -1, -1);
+				ret = 0;
+				break;
+			case HW_CONF_JOIN: /* join conference (0..7) */
+				if (skb->len < sizeof(u32)) {
+					printk(KERN_WARNING "%s: HW_CONF_JOIN lacks parameters\n", __FUNCTION__);
+					break;
+				}
+				num = ((u32 *)skb->data)[0];
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_DEBUG "%s: HW_CONF_JOIN conf %ld\n",
+						__FUNCTION__, num);
+				if (num <= 7) {
+					hfcmulti_conf(hc, ch->channel, num);
+					ret = 0;
+				} else
+					printk(KERN_WARNING "%s: HW_CONF_JOIN conf %ld out of range\n",
+						__FUNCTION__, num);
+				break;
+			case HW_CONF_SPLIT: /* split conference */
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_DEBUG "%s: HW_CONF_SPLIT\n",
+						__FUNCTION__);
+				hfcmulti_conf(hc, ch->channel, -1);
+				ret = 0;
+				break;
+			case HW_SPL_LOOP_ON: /* set sample loop */
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_DEBUG "%s: HW_SPL_LOOP_ON (len = %d)\n",
+						__FUNCTION__, skb->len);
+				hfcmulti_splloop(hc, ch->channel, skb->data, skb->len);
+				ret = 0;
+				break;
+			case HW_SPL_LOOP_OFF: /* set silence */
+				if (debug & DEBUG_HFCMULTI_MSG)
+					printk(KERN_DEBUG "%s: HW_SPL_LOOP_OFF\n",
+						__FUNCTION__);
+				hfcmulti_splloop(hc, ch->channel, NULL, 0);
+				ret = 0;
+				break;
+
+			case HW_ECHOCAN_ON:
+				
+				if (skb->len < sizeof(u32)) {
+					printk(KERN_WARNING "%s: HW_ECHOCAN_ON lacks parameters\n",
+					       __FUNCTION__);
+				}
+				
+				taps = ((u32 *)skb->data)[0];
+#ifdef B410P_CARD		
+				vpm_echocan_on(hc, ch->channel, taps);
+#endif
+				ret=0;
+				break;
+
+			case HW_ECHOCAN_OFF:
+#ifdef B410P_CARD		
+				vpm_echocan_off(hc, ch->channel);
+#endif
+				ret=0;
+				break;
+
+			default:
+				if (debug)
+					printk(KERN_DEBUG "%s: unknown PH_CONTROL info %x\n",
+						__FUNCTION__, hh->dinfo);
+				ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(ch->inst.hwlock, flags);
+	} 
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+/* 
+ * message transfer from layer 1 to hardware.
+ */
+static int
+hfcmulti_l2l1(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*chan = container_of(inst, channel_t, inst);
+	hfc_multi_t	*hc;
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	hc = chan->inst.privat;
+	if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		ret = channel_senddata(chan, hh->dinfo, skb);
+		if (ret > 0) { /* direct TX */
+			hfcmulti_tx(hc, chan->channel, chan);
+			/* start fifo */
+			HFC_outb(hc, R_FIFO, 0);
+			HFC_wait(hc);
+			ret = 0;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		return(ret);
+	} 
+	if (test_bit(FLG_DCHANNEL, &chan->Flags)) {
+		ret = handle_dmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (test_bit(FLG_BCHANNEL, &chan->Flags)) {
+		ret = handle_bmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+/***************************/
+/* handle D-channel events */
+/***************************/
+
+/* handle state change event
+ */
+static void ph_state_change(channel_t *dch)
+{
+	hfc_multi_t *hc = dch->inst.privat;
+	u_int prim = PH_SIGNAL | INDICATION;
+	u_int para = 0;
+	int ch;
+
+	if (!dch) {
+		printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __FUNCTION__);
+		return;
+	}
+	ch = dch->channel;
+
+	if (hc->type == 1) {
+		if (!test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg)) {
+			if (debug & DEBUG_HFCMULTI_STATE)
+				printk(KERN_DEBUG "%s: E1 TE newstate %x\n", __FUNCTION__, dch->state);
+			dt_newstate(dch->inst.st, dch->state, "E1 TE");
+		} else {
+			if (debug & DEBUG_HFCMULTI_STATE)
+				printk(KERN_DEBUG "%s: E1 NT newstate %x\n", __FUNCTION__, dch->state);
+			dt_newstate(dch->inst.st, dch->state, "E1 NT");
+		}
+		switch (dch->state) {
+			case (1):
+				prim = PH_ACTIVATE | INDICATION;
+				para = 0;
+				test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+				break;
+
+			default:
+				if (hc->chan[ch].e1_state != 1)
+					return;
+				prim = PH_DEACTIVATE | INDICATION;
+				para = 0;
+				test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+		}
+		hc->chan[ch].e1_state = dch->state;
+	} else {
+		if (!test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg)) {
+			if (debug & DEBUG_HFCMULTI_STATE)
+				printk(KERN_DEBUG "%s: S/T TE newstate %x\n", __FUNCTION__, dch->state);
+			dt_newstate(dch->inst.st, dch->state, "S/T TE");
+			switch (dch->state) {
+				case (0):
+					prim = PH_CONTROL | INDICATION;
+					para = HW_RESET;
+					break;
+
+				case (3):
+					prim = PH_CONTROL | INDICATION;
+					para = HW_DEACTIVATE;
+					break;
+
+				case (5):
+				case (8):
+					para = ANYSIGNAL;
+					break;
+
+				case (6):
+					para = INFO2;
+					break;
+
+				case (7):
+					para = INFO4_P8;
+					break;
+
+				default:
+					return;
+			}
+		} else {
+			if (debug & DEBUG_HFCMULTI_STATE)
+				printk(KERN_DEBUG "%s: S/T NT newstate %x\n", __FUNCTION__, dch->state);
+			dt_newstate(dch->inst.st, dch->state, "S/T NT");
+			switch (dch->state) {
+				case (2):
+					if (hc->chan[ch].nt_timer == 0) {
+						hc->chan[ch].nt_timer = -1;
+						HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
+						HFC_outb(hc, A_ST_WR_STATE, 4 | V_ST_LD_STA); /* G4 */
+						udelay(6); /* wait at least 5,21us */
+						HFC_outb(hc, A_ST_WR_STATE, 4);
+						dch->state = 4;
+					} else {
+						/* one extra count for the next event */
+						hc->chan[ch].nt_timer = nt_t1_count[poll_timer] + 1;
+						HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
+						HFC_outb(hc, A_ST_WR_STATE, 2 | V_SET_G2_G3); /* allow G2 -> G3 transition */
+					}
+					return;
+
+				case (1):
+					prim = PH_DEACTIVATE | INDICATION;
+					para = 0;
+					hc->chan[ch].nt_timer = -1;
+					test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+					break;
+
+				case (4):
+					hc->chan[ch].nt_timer = -1;
+					return;
+
+				case (3):
+					prim = PH_ACTIVATE | INDICATION;
+					para = 0;
+					hc->chan[ch].nt_timer = -1;
+					test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+					break;
+
+				default:
+					return;
+			}
+		}
+	}
+
+	mISDN_queue_data(&dch->inst, FLG_MSG_UP, prim, para, 0, NULL, 0);
+	if ((hc->type == 1) || test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg))
+		mISDN_queue_data(&dch->inst, dch->inst.id | MSG_BROADCAST,
+			MGR_SHORTSTATUS | INDICATION, test_bit(FLG_ACTIVE, &dch->Flags) ?
+			SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED,
+			0, NULL, 0);
+}
+
+/*************************************/
+/* called for card mode init message */
+/*************************************/
+
+static void
+hfcmulti_initmode(hfc_multi_t *hc)
+{
+	int		nt_mode;
+	BYTE		r_sci_msk, a_st_wr_state, r_e1_wr_sta;
+	int		i, port;
+	channel_t	*dch;
+//	u_long		flags;
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk("%s: entered\n", __FUNCTION__);
+
+	if (hc->type == 1) {
+		nt_mode = test_bit(HFC_CFG_NTMODE, &hc->chan[16].cfg);
+		hc->chan[16].slot_tx = -1;
+		hc->chan[16].slot_rx = -1;
+		hc->chan[16].conf = -1;
+		mode_hfcmulti(hc, 16, nt_mode?ISDN_PID_L1_NT_E1:ISDN_PID_L1_TE_E1, -1, 0, -1, 0);
+		hc->chan[16].ch->timer.function = (void *) hfcmulti_dbusy_timer;
+		hc->chan[16].ch->timer.data = (long) &hc->chan[16].ch;
+		init_timer(&hc->chan[16].ch->timer);
+
+		i = 0;
+		while (i < 30) {
+			hc->chan[i+1+(i>=15)].slot_tx = -1;
+			hc->chan[i+1+(i>=15)].slot_rx = -1;
+			hc->chan[i+1+(i>=15)].conf = -1;
+			mode_hfcmulti(hc, i+1+(i>=15), ISDN_PID_NONE, -1, 0, -1, 0);
+			i++;
+		}
+	} else {
+		i = 0;
+		while (i < hc->ports) {
+			nt_mode = test_bit(HFC_CFG_NTMODE, &hc->chan[(i<<2)+2].cfg);
+			hc->chan[(i<<2)+2].slot_tx = -1;
+			hc->chan[(i<<2)+2].slot_rx = -1;
+			hc->chan[(i<<2)+2].conf = -1;
+			mode_hfcmulti(hc, (i<<2)+2, nt_mode?ISDN_PID_L1_NT_S0:ISDN_PID_L1_TE_S0, -1, 0, -1, 0);
+			hc->chan[(i<<2)+2].ch->timer.function = (void *) hfcmulti_dbusy_timer;
+			hc->chan[(i<<2)+2].ch->timer.data = (long) &hc->chan[(i<<2)+2].ch;
+			init_timer(&hc->chan[(i<<2)+2].ch->timer);
+
+			hc->chan[i<<2].slot_tx = -1;
+			hc->chan[i<<2].slot_rx = -1;
+			hc->chan[i<<2].conf = -1;
+			mode_hfcmulti(hc, i<<2, ISDN_PID_NONE, -1, 0, -1, 0);
+			hc->chan[(i<<2)+1].slot_tx = -1;
+			hc->chan[(i<<2)+1].slot_rx = -1;
+			hc->chan[(i<<2)+1].conf = -1;
+			mode_hfcmulti(hc, (i<<2)+1, ISDN_PID_NONE, -1, 0, -1, 0);
+			i++;
+		}
+	}
+
+	/* set up interface */
+	if (hc->type != 1) {
+		/* ST */
+		r_sci_msk = 0;
+		i = 0;
+		while(i < 32) {
+			dch = hc->chan[i].ch;
+			if (!dch || !test_bit(FLG_DCHANNEL, &dch->Flags)) {
+				i++;
+				continue;
+			}
+			port = hc->chan[i].port;
+			/* select interface */
+			HFC_outb(hc, R_ST_SEL, port);
+			if (test_bit(HFC_CFG_NTMODE, &hc->chan[i].cfg)) {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: ST port %d is NT-mode\n", __FUNCTION__, port);
+				/* clock delay */
+				HFC_outb(hc, A_ST_CLK_DLY, CLKDEL_NT | 0x60);
+				a_st_wr_state = 1; /* G1 */
+				hc->hw.a_st_ctrl0[port] = V_ST_MD;
+			} else {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: ST port %d is TE-mode\n", __FUNCTION__, port);
+				/* clock delay */
+				HFC_outb(hc, A_ST_CLK_DLY, CLKDEL_TE);
+				a_st_wr_state = 2; /* F2 */
+				hc->hw.a_st_ctrl0[port] = 0;
+			}
+			if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg)) {
+				hc->hw.a_st_ctrl0[port] |= V_TX_LI;
+			}
+			/* line setup */
+			HFC_outb(hc, A_ST_CTRL0,  hc->hw.a_st_ctrl0[port]);
+			/* disable E-channel */
+			if (test_bit(HFC_CFG_NTMODE, &hc->chan[i].cfg)
+			 || test_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i].cfg))
+				HFC_outb(hc, A_ST_CTRL1, V_E_IGNO);
+			/* enable B-channel receive */
+			HFC_outb(hc, A_ST_CTRL2,  V_B1_RX_EN | V_B2_RX_EN);
+			/* state machine setup */
+			HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state | V_ST_LD_STA);
+			udelay(6); /* wait at least 5,21us */
+			HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state);
+			r_sci_msk |= 1 << port;
+			i++;
+		}
+		/* state machine interrupts */
+		HFC_outb(hc, R_SCI_MSK, r_sci_msk);
+	} else {
+		/* E1 */
+		if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[16].cfg)) {
+			HFC_outb(hc, R_LOS0, 255); /* 2 ms */
+			HFC_outb(hc, R_LOS1, 255); /* 512 ms */
+		}
+		if (test_bit(HFC_CFG_OPTICAL, &hc->chan[16].cfg)) {
+			HFC_outb(hc, R_RX0, 0);
+			hc->hw.r_tx0 = 0 | V_OUT_EN;
+		} else {
+			HFC_outb(hc, R_RX0, 1);
+			hc->hw.r_tx0 = 1 | V_OUT_EN;
+		}
+		hc->hw.r_tx1 = V_ATX | V_NTRI;
+		HFC_outb(hc, R_TX0, hc->hw.r_tx0);
+		HFC_outb(hc, R_TX1, hc->hw.r_tx1);
+		HFC_outb(hc, R_TX_FR0, 0x00);
+		HFC_outb(hc, R_TX_FR1, 0xf8);
+
+		if (test_bit(HFC_CFG_CRC4, &hc->chan[16].cfg)) 
+			HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E);
+
+		HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0);
+
+		if (test_bit(HFC_CFG_CRC4, &hc->chan[16].cfg)) 
+			HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC);
+
+		if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
+			/* SLAVE (clock master) */
+			if (debug & DEBUG_HFCMULTI_INIT)
+				printk(KERN_DEBUG "%s: E1 port is clock master (clock from PCM)\n", __FUNCTION__);
+			HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC);
+		} else {
+			if (test_bit(HFC_CHIP_CRYSTAL_CLOCK, &hc->chip)) {
+				/* MASTER (clock master) */
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: E1 port is clock master (clock from crystal)\n", __FUNCTION__);
+				HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC | V_JATT_OFF);
+			} else {
+				/* MASTER (clock slave) */
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: E1 port is clock slave (clock to PCM)\n", __FUNCTION__);
+				HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS);
+			}
+		}
+		if (test_bit(HFC_CFG_NTMODE, &hc->chan[(i<<2)+2].cfg)) {
+			if (debug & DEBUG_HFCMULTI_INIT)
+				printk(KERN_DEBUG "%s: E1 port is NT-mode\n", __FUNCTION__);
+			r_e1_wr_sta = 0; /* G0 */
+		}else {
+			if (debug & DEBUG_HFCMULTI_INIT)
+				printk(KERN_DEBUG "%s: E1 port is TE-mode\n", __FUNCTION__);
+			r_e1_wr_sta = 0; /* F0 */
+		}
+		HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */
+		if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) {
+			HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX | V_IPATS0 | V_IPATS1 | V_IPATS2);
+		} else {
+			HFC_outb(hc, R_SYNC_OUT, V_IPATS0 | V_IPATS1 | V_IPATS2);
+		}
+		HFC_outb(hc, R_PWM_MD, V_PWM0_MD);
+		HFC_outb(hc, R_PWM0, 0x50);
+		HFC_outb(hc, R_PWM1, 0xff);
+		/* state machine setup */
+		HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA);
+		udelay(6); /* wait at least 5,21us */
+		HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta);
+
+	}
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk("%s: done\n", __FUNCTION__);
+}
+
+
+/***********************/
+/* initialize the card */
+/***********************/
+
+/* start timer irq, wait some time and check if we have interrupts.
+ * if not, reset chip and try again.
+ */
+static int
+init_card(hfc_multi_t *hc)
+{
+	int 	cnt = 1; /* as long as there is no trouble */
+	int 	err = -EIO;
+	u_long		flags;
+#ifdef CONFIG_PLX_PCI_BRIDGE
+	u_short	*plx_acc;
+#endif
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: entered\n", __FUNCTION__);
+
+	spin_lock_irqsave(&hc->lock, flags);
+	/* set interrupts but let global interrupt disabled*/
+	hc->hw.r_irq_ctrl = V_FIFO_IRQ;
+	disable_hwirq(hc);
+	spin_unlock_irqrestore(&hc->lock, flags);
+
+	if (request_irq(hc->pci_dev->irq, hfcmulti_interrupt, SA_SHIRQ, "HFC-multi", hc)) {
+		printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", hc->pci_dev->irq);
+		return(-EIO);
+	}
+	hc->irq = hc->pci_dev->irq;
+
+#ifdef CONFIG_PLX_PCI_BRIDGE
+	plx_acc=(u_short*)(hc->plx_membase+0x4c);
+	*plx_acc=0x41;  // enable PCI & LINT1 irq
+#endif
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: IRQ %d count %d\n", __FUNCTION__, hc->irq, hc->irqcnt);
+	while (cnt) {
+		if ((err = init_chip(hc))) {
+			goto error;
+		}
+		/* Finally enable IRQ output
+		 * this is only allowed, if an IRQ routine is allready
+		 * established for this HFC, so don't do that earlier
+		 */
+		spin_lock_irqsave(&hc->lock, flags);
+		enable_hwirq(hc);
+		spin_unlock_irqrestore(&hc->lock, flags);
+		//printk(KERN_DEBUG "no master irq set!!!\n");
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((100*HZ)/1000); /* Timeout 100ms */
+		/* turn IRQ off until chip is completely initialized */
+		spin_lock_irqsave(&hc->lock, flags);
+		disable_hwirq(hc);
+		spin_unlock_irqrestore(&hc->lock, flags);
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: IRQ %d count %d\n", __FUNCTION__, hc->irq, hc->irqcnt);
+		if (hc->irqcnt) {
+			if (debug & DEBUG_HFCMULTI_INIT)
+				printk(KERN_DEBUG "%s: done\n", __FUNCTION__);
+
+			
+			return(0);
+		} 
+		printk(KERN_WARNING "HFC PCI: IRQ(%d) getting no interrupts during init (try %d)\n", hc->irq, cnt);
+
+		if (test_bit(HFC_CHIP_CLOCK_IGNORE, &hc->chip) || test_bit(HFC_CHIP_DIGICARD, &hc->chip)) {
+			printk(KERN_WARNING "HFC PCI: Ignoring Clock so we go on here\n");
+			return 0;
+		}
+		
+#ifdef CONFIG_PLX_PCI_BRIDGE
+		plx_acc=(u_short*)(hc->plx_membase+0x4c);
+		*plx_acc=0x00;  // disable PCI & LINT1 irq
+#endif
+		cnt--;
+		err = -EIO;
+	}
+
+	error:
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_WARNING "%s: free irq %d\n", __FUNCTION__, hc->irq);
+	if (hc->irq) {
+		free_irq(hc->irq, hc);
+		hc->irq = 0;
+	}
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: done (err=%d)\n", __FUNCTION__, err);
+	return(err);
+}
+
+
+/*********************************************************/
+/* select free channel and return OK(0), -EBUSY, -EINVAL */
+/*********************************************************/
+
+static int
+SelFreeBChannel(hfc_multi_t *hc, int ch, channel_info_t *ci)
+{
+	channel_t		*bch;
+	hfc_multi_t		*hfc;
+	mISDNstack_t		*bst;
+	struct list_head	*head;
+	int			cnr;
+	int			port = hc->chan[ch].port;
+
+	if (port < 0 || port >= hc->ports) {
+		printk(KERN_WARNING "%s: port(%d) out of range", __FUNCTION__, port);
+		return(-EINVAL);
+	}
+
+	if (!ci)
+		return(-EINVAL);
+	ci->st.p = NULL;
+	cnr=0;
+	bst = hc->chan[ch].ch->inst.st;
+	if (list_empty(&bst->childlist)) {
+		if ((bst->id & FLG_CLONE_STACK) &&
+			(bst->childlist.prev != &bst->childlist)) {
+			head = bst->childlist.prev;
+		} else {
+			printk(KERN_ERR "%s: invalid empty childlist (no clone) stid(%x) childlist(%p<-%p->%p)\n",
+				__FUNCTION__, bst->id, bst->childlist.prev, &bst->childlist, bst->childlist.next);
+			return(-EINVAL);
+		}
+	} else
+		head = &bst->childlist;
+	list_for_each_entry(bst, head, list) {
+		if (cnr == ((hc->type == 1) ? 30: 2)) /* 30 or 2 B-channels */ {
+			printk(KERN_WARNING "%s: fatal error: more b-stacks than ports", __FUNCTION__);
+			return(-EINVAL);
+		}
+		if(!bst->mgr) {
+			int_errtxt("no mgr st(%p)", bst);
+			return(-EINVAL);
+		}
+		hfc = bst->mgr->privat;
+		if (!hfc) {
+			int_errtxt("no mgr->data st(%p)", bst);
+			return(-EINVAL);
+		}
+		if (hc->type == 1)
+			bch = hc->chan[cnr + 1 + (cnr>=15)].ch;
+		else
+			bch = hc->chan[(port<<2) + cnr].ch;
+		if (!(ci->channel & (~CHANNEL_NUMBER))) {
+			/* only number is set */
+			if ((ci->channel & 0x3) == (cnr + 1)) {
+				if (test_bit(FLG_ACTIVE, &bch->Flags))
+					return(-EBUSY);
+				ci->st.p = bst;
+				return(0);
+			}
+		}
+		if ((ci->channel & (~CHANNEL_NUMBER)) == 0x00a18300) {
+			if (!test_bit(FLG_ACTIVE, &bch->Flags)) {
+				ci->st.p = bst;
+				return(0);
+			}
+		}
+		cnr++;
+	}
+	return(-EBUSY);
+}
+
+
+/*********************************/
+/* find pci device and set it up */
+/*********************************/
+
+static int
+setup_pci(hfc_multi_t *hc, struct pci_dev *pdev, int id_idx)
+{
+	int i;
+
+	printk(KERN_INFO "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", id_list[id_idx].vendor_name, id_list[id_idx].card_name, (id_list[id_idx].clock2)?"double":"normal");
+
+	/* go into 0-state (we might already be due to zero-filled-object */
+	for (i = 0; i < 32; i++) {
+		if (hc->chan[i].ch && test_bit(FLG_DCHANNEL, &hc->chan[i].ch->Flags))
+			hc->chan[i].ch->state = 0;
+	}
+
+	hc->pci_dev = pdev;
+	if (id_list[id_idx].clock2)
+		test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip);
+
+#if 1
+	if (id_list[id_idx].device_id == 0xB410)
+		test_and_set_bit(HFC_CHIP_DIGICARD, &hc->chip);
+#endif
+
+	if (hc->pci_dev->irq <= 0) {
+		printk(KERN_WARNING "HFC-multi: No IRQ for PCI card found.\n");
+		return (-EIO);
+	}
+	if (pci_enable_device(hc->pci_dev)) {
+		printk(KERN_WARNING "HFC-multi: Error enabling PCI card.\n");
+		return (-EIO);
+	}
+	hc->leds = id_list[id_idx].leds;
+	hc->opticalsupport = id_list[id_idx].opticalsupport;
+	
+#ifdef CONFIG_HFCMULTI_PCIMEM
+	hc->pci_membase = NULL;
+	hc->plx_membase = NULL;
+
+#ifdef CONFIG_PLX_PCI_BRIDGE
+	hc->plx_origmembase =  get_pcibase(hc->pci_dev, 0);  // MEMBASE 1 is PLX PCI Bridge
+
+	if (!hc->plx_origmembase) {
+		printk(KERN_WARNING "HFC-multi: No IO-Memory for PCI PLX bridge found\n");
+		pci_disable_device(hc->pci_dev);
+		return (-EIO);
+	}
+
+	if (!(hc->plx_membase = ioremap(hc->plx_origmembase, 128))) {
+		printk(KERN_WARNING "HFC-multi: failed to remap plx address space. (internal error)\n");
+		hc->plx_membase = NULL;
+		pci_disable_device(hc->pci_dev);
+		return (-EIO);
+	}
+	printk(KERN_WARNING "HFC-multi: plx_membase:%#x plx_origmembase:%#x\n",(u_int) hc->plx_membase, (u_int)hc->plx_origmembase);
+
+	hc->pci_origmembase =  get_pcibase(hc->pci_dev, 2);  // MEMBASE 1 is PLX PCI Bridge
+	if (!hc->pci_origmembase) {
+		printk(KERN_WARNING "HFC-multi: No IO-Memory for PCI card found\n");
+		pci_disable_device(hc->pci_dev);
+		return (-EIO);
+	}
+
+	if (!(hc->pci_membase = ioremap(hc->pci_origmembase, 0x400))) {
+		printk(KERN_WARNING "HFC-multi: failed to remap io address space. (internal error)\n");
+		hc->pci_membase = NULL;
+		pci_disable_device(hc->pci_dev);
+		return (-EIO);
+	}
+
+	printk(KERN_INFO "%s: defined at MEMBASE %#x (%#x) IRQ %d HZ %d leds-type %d\n", hc->name, (u_int) hc->pci_membase, (u_int) hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds);
+	pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO);
+#else // CONFIG_PLX_PCI_BRIDGE
+	hc->pci_origmembase = get_pcibase(hc->pci_dev, 1);
+	if (!hc->pci_origmembase) {
+		printk(KERN_WARNING "HFC-multi: No IO-Memory for PCI card found\n");
+		pci_disable_device(hc->pci_dev);
+		return (-EIO);
+	}
+
+	if (!(hc->pci_membase = ioremap(hc->pci_origmembase, 256))) {
+		printk(KERN_WARNING "HFC-multi: failed to remap io address space. (internal error)\n");
+		hc->pci_membase = NULL;
+		pci_disable_device(hc->pci_dev);
+		return (-EIO);
+	}
+	printk(KERN_INFO "%s: defined at MEMBASE %#x (%#x) IRQ %d HZ %d leds-type %d\n", hc->name, (u_int) hc->pci_membase, (u_int) hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds);
+	pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO);
+#endif // CONFIG_PLX_PCI_BRIDGE
+#else
+	hc->pci_iobase = (u_int) get_pcibase(hc->pci_dev, 0);
+	if (!hc->pci_iobase) {
+		printk(KERN_WARNING "HFC-multi: No IO for PCI card found\n");
+		pci_disable_device(hc->pci_dev);
+		return (-EIO);
+	}
+
+	if (!request_region(hc->pci_iobase, 8, "hfcmulti")) {
+		printk(KERN_WARNING "HFC-multi: failed to rquest address space at 0x%04x (internal error)\n", hc->pci_iobase);
+		hc->pci_iobase = 0;
+		pci_disable_device(hc->pci_dev);
+		return (-EIO);
+	}
+
+	printk(KERN_INFO "%s: defined at IOBASE %#x IRQ %d HZ %d leds-type %d\n", hc->name, (u_int) hc->pci_iobase, hc->pci_dev->irq, HZ, hc->leds);
+	pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_REGIO);
+#endif
+
+	pci_set_drvdata(hc->pci_dev, hc);
+
+	/* At this point the needed PCI config is done */
+	/* fifos are still not enabled */
+	return (0);
+}
+
+
+
+
+static void release_ports_hw(hfc_multi_t *hc)
+{
+	u_long flags;
+
+	spin_lock_irqsave(&hc->lock, flags);
+	
+	/*first we disable all the hw stuff*/
+	disable_hwirq(hc);
+
+	spin_unlock_irqrestore(&hc->lock, flags);
+	
+	udelay(1000);
+	
+	/* disable D-channels & B-channels */
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: disable all channels (d and b)\n", __FUNCTION__);
+
+
+	/* dimm leds */
+	if (hc->leds)
+		hfcmulti_leds(hc);
+
+#if 0
+	if (hc->type == 1) {
+		hc->chan[16].slot_tx = -1;
+		hc->chan[16].slot_rx = -1;
+		hc->chan[16].conf = -1;
+		mode_hfcmulti(hc, 16, ISDN_PID_NONE, -1, 0, -1, 0);//d
+		i = 0;
+		while(i < 30) {
+			hc->chan[i+1+(i>=15)].slot_tx = -1;
+			hc->chan[i+1+(i>=15)].slot_rx = -1;
+			hc->chan[i+1+(i>=15)].conf = -1;
+			mode_hfcmulti(hc, i+1+(i>=15), ISDN_PID_NONE, -1, 0, -1, 0); //b
+			i++;
+		}
+	} else {
+		i = 0;
+		while(i < hc->ports) {
+			if (hc->created[i]) {
+				hc->chan[(i<<2)+2].slot_tx = -1;
+				hc->chan[(i<<2)+2].slot_rx = -1;
+				hc->chan[(i<<2)+2].conf = -1;
+				mode_hfcmulti(hc, (i<<2)+2, ISDN_PID_NONE, -1, 0, -1, 0); //d
+				hc->chan[i<<2].slot_tx = -1;
+				hc->chan[i<<2].slot_rx = -1;
+				hc->chan[i<<2].conf = -1;
+				mode_hfcmulti(hc, i<<2, ISDN_PID_NONE, -1, 0, -1, 0); //b1
+				hc->chan[(i<<2)+1].slot_tx = -1;
+				hc->chan[(i<<2)+1].slot_rx = -1;
+				hc->chan[(i<<2)+1].conf = -1;
+				mode_hfcmulti(hc, (i<<2)+1, ISDN_PID_NONE, -1, 0, -1, 0); //b2
+			}
+			i++;
+		}
+	}
+#endif
+
+	release_io_hfcmulti(hc);
+
+	if (hc->irq) {
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_WARNING "%s: free irq %d\n", __FUNCTION__, hc->irq);
+		free_irq(hc->irq, hc);
+		hc->irq = 0;
+
+	}
+	udelay(1000);	
+	
+	/*now we finish off the lists and stuff*/
+	/* remove us from list and delete */
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_WARNING "%s: remove instance from list\n", __FUNCTION__);
+
+#if 1
+	u_long flags2;
+	spin_lock_irqsave(&HFCM_obj.lock,flags2);
+	list_del(&hc->list);
+	spin_unlock_irqrestore(&HFCM_obj.lock,flags2);
+#endif
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_WARNING "%s: delete instance\n", __FUNCTION__);
+	
+
+	kfree(hc);
+	hc=NULL;
+	HFC_cnt--;
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_WARNING "%s: card successfully removed\n", __FUNCTION__);
+
+}
+
+/***************************
+ * remove port  from stack *
+ ***************************/
+
+static void
+release_port(hfc_multi_t *hc, int port)
+{
+	int	i = 0;
+	u_long	flags;
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: entered\n", __FUNCTION__);
+	
+	if (port >= hc->ports) {
+		printk(KERN_WARNING "%s: ERROR port out of range (%d).\n", __FUNCTION__, port);
+		return;
+	}
+
+	spin_lock_irqsave(&hc->lock, flags);
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: releasing port=%d\n", __FUNCTION__, port);
+	
+	if ( !hc->created[port]) {
+		printk(KERN_WARNING "%s: ERROR given stack is not used by card (port=%d).\n", __FUNCTION__, port);
+		spin_unlock_irqrestore(&hc->lock,flags);
+		return;
+	}
+	
+
+
+	for (i=0;i<32;i++) {
+		if (hc->chan[i].ch && test_bit(FLG_DCHANNEL, &hc->chan[i].ch->Flags)  &&
+		    hc->chan[i].ch->timer.function != NULL ) {
+			del_timer(&hc->chan[i].ch->timer);
+			hc->chan[i].ch->timer.function = NULL;
+		}
+	}
+	
+	/* free channels */
+	i = 0;
+	while(i < 32) {
+		if (hc->chan[i].ch) {
+			if (debug & DEBUG_HFCMULTI_INIT)
+				printk(KERN_DEBUG "%s: free port %d %c-channel %d (1..32)\n",
+				       __FUNCTION__, hc->chan[i].port,
+				       test_bit(FLG_DCHANNEL, &hc->chan[i].ch->Flags) ?
+				       'D' : 'B', i);
+			mISDN_freechannel(hc->chan[i].ch);
+
+			spin_unlock_irqrestore(&hc->lock,flags);
+			
+			if (test_bit(FLG_DCHANNEL, &hc->chan[i].ch->Flags))
+				mISDN_ctrl(&hc->chan[i].ch->inst, MGR_UNREGLAYER | REQUEST, NULL);
+			spin_lock_irqsave(&hc->lock,flags);
+			
+			kfree(hc->chan[i].ch);
+			hc->chan[i].ch = NULL;
+		}
+		i++;
+	}
+	
+	hc->created[port]=0;
+
+	spin_unlock_irqrestore(&hc->lock,flags);
+	
+}
+
+static int
+HFC_manager(void *data, u_int prim, void *arg)
+{
+	hfc_multi_t	*hc;
+	mISDNinstance_t	*inst = data;
+	struct sk_buff	*skb;
+	channel_t	*chan = NULL;
+	int		ch = -1;
+	int		i;
+	u_long		flags;
+
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim,arg,&HFCM_obj)
+		printk(KERN_ERR "%s: no data prim %x arg %p\n", __FUNCTION__, prim, arg);
+		return(-EINVAL);
+	}
+
+	/* find channel and card */
+	spin_lock_irqsave(&HFCM_obj.lock, flags);
+	list_for_each_entry(hc, &HFCM_obj.ilist, list) {
+		i = 0;
+		while(i < 32) {
+//printk(KERN_DEBUG "comparing (D-channel) card=%08x inst=%08x with inst=%08x\n", hc, &hc->dch[i].inst, inst);
+			if ((hc->chan[i].ch) &&
+				(&hc->chan[i].ch->inst == inst)) {
+				ch = i;
+				chan = hc->chan[i].ch;
+				break;
+			}
+			i++;
+		}
+		if (ch >= 0)
+			break;
+	}
+	spin_unlock_irqrestore(&HFCM_obj.lock, flags);
+	if (ch < 0) {
+		printk(KERN_ERR "%s: no card/channel found  data %p prim %x arg %p\n", __FUNCTION__, data, prim, arg);
+		return(-EINVAL);
+	}
+	if (debug & DEBUG_HFCMULTI_MGR)
+		printk(KERN_DEBUG "%s: channel %d (0..31)  data %p prim %x arg %p\n", __FUNCTION__, ch, data, prim, arg);
+
+	switch(prim) {
+		case MGR_REGLAYER | CONFIRM:
+bugtest
+		if (debug & DEBUG_HFCMULTI_MGR)
+			printk(KERN_DEBUG "%s: MGR_REGLAYER\n", __FUNCTION__);
+		mISDN_setpara(chan, &inst->st->para);
+bugtest
+		break;
+
+		case MGR_UNREGLAYER | REQUEST:
+bugtest
+		if (debug & DEBUG_HFCMULTI_MGR)
+			printk(KERN_DEBUG "%s: MGR_UNREGLAYER\n", __FUNCTION__);
+		i = test_bit(FLG_DCHANNEL, &chan->Flags) ? HW_DEACTIVATE : 0;
+		if ((skb = create_link_skb(PH_CONTROL | REQUEST, i, 0, NULL, 0))) {
+			if (hfcmulti_l2l1(inst, skb))
+				dev_kfree_skb(skb);
+		}
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+bugtest
+		break;
+
+		case MGR_CLRSTPARA | INDICATION:
+		arg = NULL;
+		// fall through
+		case MGR_ADDSTPARA | INDICATION:
+		if (debug & DEBUG_HFCMULTI_MGR)
+			printk(KERN_DEBUG "%s: MGR_***STPARA\n", __FUNCTION__);
+		mISDN_setpara(chan, arg);
+		break;
+
+		case MGR_RELEASE | INDICATION:
+		if (debug & DEBUG_HFCMULTI_MGR)
+			printk(KERN_DEBUG "%s: MGR_RELEASE = remove port from mISDN\n", __FUNCTION__);
+		break;
+#ifdef FIXME
+		case MGR_CONNECT | REQUEST:
+		if (debug & DEBUG_HFCMULTI_MGR)
+			printk(KERN_DEBUG "%s: MGR_CONNECT\n", __FUNCTION__);
+		return(mISDN_ConnectIF(inst, arg));
+
+		case MGR_SETIF | REQUEST:
+		case MGR_SETIF | INDICATION:
+		if (debug & DEBUG_HFCMULTI_MGR)
+			printk(KERN_DEBUG "%s: MGR_SETIF\n", __FUNCTION__);
+		if (dch)
+			return(mISDN_SetIF(inst, arg, prim, hfcmulti_l1hw, NULL, dch));
+		if (bch)
+			return(mISDN_SetIF(inst, arg, prim, hfcmulti_l2l1, NULL, bch));
+		break;
+
+		case MGR_DISCONNECT | REQUEST:
+		case MGR_DISCONNECT | INDICATION:
+		if (debug & DEBUG_HFCMULTI_MGR)
+			printk(KERN_DEBUG "%s: MGR_DISCONNECT\n", __FUNCTION__);
+		return(mISDN_DisConnectIF(inst, arg));
+#endif
+		case MGR_SELCHANNEL | REQUEST:
+		if (debug & DEBUG_HFCMULTI_MGR)
+			printk(KERN_DEBUG "%s: MGR_SELCHANNEL\n", __FUNCTION__);
+		if (!test_bit(FLG_DCHANNEL, &chan->Flags)) {
+			printk(KERN_WARNING "%s(MGR_SELCHANNEL|REQUEST): selchannel not dinst\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+		return(SelFreeBChannel(hc, ch, arg));
+
+		case MGR_SETSTACK | INDICATION:
+bugtest
+		if (debug & DEBUG_HFCMULTI_MGR)
+			printk(KERN_DEBUG "%s: MGR_SETSTACK\n", __FUNCTION__);
+		if (test_bit(FLG_BCHANNEL, &chan->Flags) && inst->pid.global==2) {
+			if ((skb = create_link_skb(PH_ACTIVATE | REQUEST, 0, 0, NULL, 0))) {
+				if (hfcmulti_l2l1(inst, skb))
+					dev_kfree_skb(skb);
+			}
+			if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION, 0, 0, NULL, 0);
+			else
+				mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION, 0, 0, NULL, 0);
+		}
+bugtest
+		break;
+
+		PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+		PRIM_NOT_HANDLED(MGR_GLOBALOPT | REQUEST);
+		default:
+		printk(KERN_WARNING "%s: prim %x not handled\n", __FUNCTION__, prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+static int find_idlist_entry(int vendor,int subvendor, int device, int subdevice)
+{
+	int cnt;
+
+	cnt=0;
+	while(id_list[cnt].vendor_id)
+	{
+		if(id_list[cnt].vendor_id==vendor && id_list[cnt].vendor_sub==subvendor
+		   && id_list[cnt].device_id==device && id_list[cnt].device_sub==subdevice) return(cnt);
+		cnt++;
+	}
+
+	return(-1);
+}
+
+static int __devinit hfcpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int		i, ret_err=0;
+	static int HFC_idx=0, HFC_port_idx=0;
+	int port_idx;
+	int		bchperport, card_type, pt;
+	int		ch, ch2;
+	int		id_idx;        // index to id_list
+	int		hfc_type;      // chip type
+	int		hfc_ports;     // chip ports
+	hfc_multi_t	*hc;
+	mISDN_pid_t	pid, pids[8];
+	mISDNstack_t	*dst = NULL; /* make gcc happy */
+	channel_t	*chan;
+	u_long		flags;
+	u_char		dips=0, pmj=0; // dip settings, port mode Jumpers
+
+	id_idx = find_idlist_entry(ent->vendor,ent->subvendor,ent->device,ent->subdevice);
+	if (id_idx == -1) {
+		if (ent->vendor == CCAG_VID)
+			if (ent->device == HFC4S_ID
+			 || ent->device == HFC8S_ID
+			 || ent->device == HFCE1_ID)
+				printk( KERN_ERR "unknown HFC multiport controller (vendor:%x device:%x subvendor:%x subdevice:%x) Please contact the driver maintainer for support.\n",
+					ent->vendor,ent->device,ent->subvendor,ent->subdevice);
+		return (-ENODEV);
+	}
+
+	//hfc_type=id_list[id_idx].type;
+	hfc_ports=id_list[id_idx].ports;
+
+	/* check card type */
+	switch (ent->device) {
+		case HFCE1_ID:
+		bchperport = 30;
+		card_type=1;
+		hfc_type=0x1;
+		break;
+
+		case HFC4S_ID:
+		bchperport = 2;
+		card_type=0;
+		hfc_type=0x4;
+		break;
+
+		case 0xB410:
+		bchperport = 2;
+		card_type=0;
+		hfc_type=0x4;
+		break;
+
+		case HFC8S_ID:
+		bchperport = 2;
+		card_type=0;
+		hfc_type=0x8;
+		break;
+
+		default:
+		printk(KERN_ERR "Card type(%d) not supported.\n", type[HFC_idx] & 0xff);
+		ret_err = -EINVAL;
+		goto free_object;
+	}
+
+	port_idx=HFC_port_idx;
+
+	if(HFC_idx == -1) {
+		printk( KERN_ERR "HFC-MULTI: Card '%s' found, but not given by module's options, ignoring...\n",
+			id_list[id_idx].card_name);
+		return (-ENODEV);
+	}
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: Registering chip type %d (0x%x)\n",
+			__FUNCTION__, type[HFC_idx] & 0xff, type[HFC_idx]);
+
+	/* allocate card+fifo structure */
+//#warning
+//void *davor=kmalloc(8, GFP_ATOMIC);
+	if (!(hc = kmalloc(sizeof(hfc_multi_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "No kmem for HFC-Multi card\n");
+		ret_err = -ENOMEM;
+		goto free_object;
+	}
+//void *danach=kmalloc(8, GFP_ATOMIC);
+	memset(hc, 0, sizeof(hfc_multi_t));
+//hc->davor=davor;
+//hc->danach=danach;
+	hc->idx = HFC_idx;
+	hc->id = HFC_idx + 1;
+	hc->pcm = pcm[HFC_idx];
+
+	/* set chip specific features */
+	hc->masterclk = -1;
+	hc->type  = card_type;
+	hc->ports = hfc_ports;
+	
+//	printk( KERN_NOTICE "type:%d ports:%d HFC_idx:%d port_idx:%d\n",card_type, hfc_ports, HFC_idx, port_idx);
+
+	if (type[HFC_idx] & 0x100) {
+		test_and_set_bit(HFC_CHIP_ULAW, &hc->chip);
+		silence = 0xff; /* ulaw silence */
+	} else
+		silence = 0x2a; /* alaw silence */
+	if (type[HFC_idx] & 0x200)
+		test_and_set_bit(HFC_CHIP_DTMF, &hc->chip);
+//		if ((type[HFC_idx]&0x400) && hc->type==4)
+//			test_and_set_bit(HFC_CHIP_LEDS, &hc->chip);
+	if (type[HFC_idx] & 0x800)
+		test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
+	if (type[HFC_idx] & 0x1000)
+		test_and_set_bit(HFC_CHIP_CLOCK_IGNORE, &hc->chip);
+	if (type[HFC_idx] & 0x2000)
+		test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip);
+	if (type[HFC_idx] & 0x4000)
+		test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip);
+	if (type[HFC_idx] & 0x8000)
+		test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip);
+	hc->slots = 32;
+	if (type[HFC_idx] & 0x10000)
+		hc->slots = 64;
+	if (type[HFC_idx] & 0x20000)
+		hc->slots = 128;
+	if (type[HFC_idx] & 0x40000)
+		test_and_set_bit(HFC_CHIP_CRYSTAL_CLOCK, &hc->chip);
+	if (type[HFC_idx] & 0x80000) {
+		test_and_set_bit(HFC_CHIP_WATCHDOG, &hc->chip);
+		hc->wdcount=0;
+		hc->wdbyte=V_GPIO_OUT2;
+		printk(KERN_NOTICE "Watchdog enabled\n");
+	}
+	if (hc->type == 1)
+		sprintf(hc->name, "HFC-E1#%d", HFC_idx+1);
+	else
+		sprintf(hc->name, "HFC-%dS#%d", hc->ports, HFC_idx+1);
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__);
+	
+	spin_lock_irqsave(&HFCM_obj.lock, flags);
+	list_add_tail(&hc->list, &HFCM_obj.ilist);
+	spin_unlock_irqrestore(&HFCM_obj.lock, flags);
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__);
+
+	spin_lock_init(&hc->lock);
+
+	pt = 0;
+	while (pt < hc->ports) {
+		if (port_idx >= MAX_PORTS) {
+			printk(KERN_ERR "Invalid HFC type.\n");
+			ret_err = -EINVAL;
+			goto free_channels;
+		}
+		if (protocol[port_idx] == 0) {
+			printk(KERN_ERR "Not enough 'protocol' values given.\n");
+			ret_err = -EINVAL;
+			goto free_channels;
+		}
+		if (hc->type == 1)
+			ch = 16;
+		else
+			ch = (pt<<2)+2;
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: Registering D-channel, card(%d) ch(%d) port(%d) protocol(%x)\n", __FUNCTION__, HFC_idx+1, ch, pt+1, protocol[port_idx]);
+		hc->chan[ch].port = pt;
+		hc->chan[ch].nt_timer = -1;
+		chan = kmalloc(sizeof(channel_t), GFP_ATOMIC);
+		if (!chan) {
+			ret_err = -ENOMEM;
+			goto free_channels;
+		}
+		memset(chan, 0, sizeof(channel_t));
+		chan->channel = ch;
+		//chan->debug = debug;
+		chan->inst.obj = &HFCM_obj;
+		chan->inst.hwlock = &hc->lock;
+		chan->inst.class_dev.dev = &pdev->dev;
+		mISDN_init_instance(&chan->inst, &HFCM_obj, hc, hfcmulti_l2l1);
+		chan->inst.pid.layermask = ISDN_LAYER(0);
+		sprintf(chan->inst.name, "HFCm%d/%d", HFC_idx+1, pt+1);
+		ret_err = mISDN_initchannel(chan, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
+		if (ret_err)
+			goto free_channels;
+		hc->chan[ch].ch = chan;
+
+		i=0;
+		while(i < bchperport) {
+			if (hc->type == 1)
+				ch2 = i + 1 + (i>=15);
+			else
+				ch2 = (pt<<2)+i;
+			if (debug & DEBUG_HFCMULTI_INIT)
+				printk(KERN_DEBUG "%s: Registering B-channel, card(%d) ch(%d) port(%d) channel(%d)\n", __FUNCTION__, HFC_idx+1, ch2, pt+1, i);
+			hc->chan[ch2].port = pt;
+			chan = kmalloc(sizeof(channel_t), GFP_ATOMIC);
+			if (!chan) {
+				ret_err = -ENOMEM;
+				goto free_channels;
+			}
+			memset(chan, 0, sizeof(channel_t));
+			chan->channel = ch2;
+			mISDN_init_instance(&chan->inst, &HFCM_obj, hc, hfcmulti_l2l1);
+			chan->inst.pid.layermask = ISDN_LAYER(0);
+			chan->inst.hwlock = &hc->lock;
+			chan->inst.class_dev.dev = &pdev->dev;
+			//bch->debug = debug;
+			sprintf(chan->inst.name, "%s B%d",
+				hc->chan[ch].ch->inst.name, i+1);
+			ret_err = mISDN_initchannel(chan, MSK_INIT_BCHANNEL, MAX_DATA_MEM);
+			if (ret_err) {
+				kfree(chan);
+				goto free_channels;
+			}
+			hc->chan[ch2].ch = chan;
+#ifdef FIXME  // TODO
+			if (chan->dev) {
+				chan->dev->wport.pif.func = hfcmulti_l2l1;
+				chan->dev->wport.pif.fdata = chan;
+			}
+#endif
+			i++;
+		}
+		chan = hc->chan[ch].ch;
+
+		/* set D-channel */
+		mISDN_set_dchannel_pid(&pid, protocol[port_idx], layermask[port_idx]);
+
+		/* set PRI */
+		if (hc->type == 1) {
+			if (layermask[port_idx] & ISDN_LAYER(2)) {
+				pid.protocol[2] |= ISDN_PID_L2_DF_PTP;
+			}
+			if (layermask[port_idx] & ISDN_LAYER(3)) {
+				pid.protocol[3] |= ISDN_PID_L3_DF_PTP;
+				pid.protocol[3] |= ISDN_PID_L3_DF_EXTCID;
+				pid.protocol[3] |= ISDN_PID_L3_DF_CRLEN2;
+			}
+		}
+
+		/* set protocol type */
+		if (protocol[port_idx] & 0x10) {
+			/* NT-mode */
+			chan->inst.pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_NT_E1:ISDN_PID_L0_NT_S0;
+			chan->inst.pid.protocol[1] = (hc->type==1)?ISDN_PID_L1_NT_E1:ISDN_PID_L1_NT_S0;
+			pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_NT_E1:ISDN_PID_L0_NT_S0;
+			pid.protocol[1] = (hc->type==1)?ISDN_PID_L1_NT_E1:ISDN_PID_L1_NT_S0;
+			chan->inst.pid.layermask |= ISDN_LAYER(1);
+			pid.layermask |= ISDN_LAYER(1);
+			if (layermask[port_idx] & ISDN_LAYER(2))
+				pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
+			test_and_set_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg);
+		} else {
+			/* TE-mode */
+			chan->inst.pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_TE_E1:ISDN_PID_L0_TE_S0;
+			pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_TE_E1:ISDN_PID_L0_TE_S0;
+			if (hc->type == 1) {
+				/* own E1 for E1 */
+				chan->inst.pid.protocol[1] = ISDN_PID_L1_TE_E1;
+				pid.protocol[1] = ISDN_PID_L1_TE_E1;
+				chan->inst.pid.layermask |= ISDN_LAYER(1);
+				pid.layermask |= ISDN_LAYER(1);
+			}
+		}
+
+
+		if (hc->type != 1) {
+			/* S/T */
+			/* set master clock */
+			if (protocol[port_idx] & 0x10000) {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: PROTOCOL set master clock: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+				if (test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg)) {
+					printk(KERN_ERR "Error: Master clock for port(%d) of card(%d) is only possible with TE-mode\n", pt+1, HFC_idx+1);
+					ret_err = -EINVAL;
+					goto free_channels;
+				}
+				if (hc->masterclk >= 0) {
+					printk(KERN_ERR "Error: Master clock for port(%d) of card(%d) already defined for port(%d)\n", pt+1, HFC_idx+1, hc->masterclk+1);
+					ret_err = -EINVAL;
+					goto free_channels;
+				}
+				hc->masterclk = pt;
+			}
+
+			/* set transmitter line to non capacitive */
+			if (protocol[port_idx] & 0x20000) {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: PROTOCOL set non capacitive transmitter: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+				test_and_set_bit(HFC_CFG_NONCAP_TX, &hc->chan[ch].cfg);
+			}
+
+			/* disable E-channel */
+			if (protocol[port_idx] & 0x40000) {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: PROTOCOL disable E-channel: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+				test_and_set_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[ch].cfg);
+			}
+			/* register E-channel */
+			if (protocol[port_idx] & 0x80000) {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: PROTOCOL register E-channel: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+				test_and_set_bit(HFC_CFG_REG_ECHANNEL, &hc->chan[ch].cfg);
+			}
+		} else {
+			/* E1 */
+			/* set optical line type */
+			if (protocol[port_idx] & 0x10000) {
+				if (!id_list[id_idx].opticalsupport)  {
+					printk(KERN_INFO "This board has no optical support\n");
+				} else {
+
+					if (debug & DEBUG_HFCMULTI_INIT)
+						printk(KERN_DEBUG "%s: PROTOCOL set optical interfacs: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+					test_and_set_bit(HFC_CFG_OPTICAL, &hc->chan[ch].cfg);
+				}
+			}
+
+			/* set LOS report */
+			if (protocol[port_idx] & 0x40000) {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: PROTOCOL set LOS report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+				test_and_set_bit(HFC_CFG_REPORT_LOS, &hc->chan[ch].cfg);
+			}
+
+			/* set AIS report */
+			if (protocol[port_idx] & 0x80000) {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: PROTOCOL set AIS report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+				test_and_set_bit(HFC_CFG_REPORT_AIS, &hc->chan[ch].cfg);
+			}
+
+			/* set SLIP report */
+			if (protocol[port_idx] & 0x100000) {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: PROTOCOL set SLIP report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+				test_and_set_bit(HFC_CFG_REPORT_SLIP, &hc->chan[ch].cfg);
+			}
+
+			/* set elastic jitter buffer */
+			if (protocol[port_idx] & 0x600000) {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: PROTOCOL set elastic buffer to %d: card(%d) port(%d)\n", __FUNCTION__, hc->chan[ch].jitter, HFC_idx+1, pt);
+				hc->chan[ch].jitter = (protocol[port_idx]>>21) & 0x3;
+			} else
+				hc->chan[ch].jitter = 2; /* default */
+
+			
+			/* set CRC-4 Mode */
+			if (! (protocol[port_idx] & 0x800000)) {
+				if (debug & DEBUG_HFCMULTI_INIT)
+					printk(KERN_DEBUG "%s: PROTOCOL turn on CRC4 report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+				test_and_set_bit(HFC_CFG_CRC4, &hc->chan[ch].cfg);
+				
+				printk(KERN_DEBUG "%s: PROTOCOL turn on CRC4 report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+			} else {
+				printk(KERN_DEBUG "%s: PROTOCOL turn off CRC4 report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt);
+			}
+
+		}
+
+		memcpy(&pids[pt], &pid, sizeof(pid));
+
+		pt++;
+		port_idx++;
+	}
+
+	/* run card setup */
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: Setting up card(%d)\n", __FUNCTION__, HFC_idx+1);
+	if ((ret_err = setup_pci(hc,pdev,id_idx))) {
+		goto free_channels;
+	}
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: Initializing card(%d)\n", __FUNCTION__, HFC_idx+1);
+	if ((ret_err = init_card(hc))) {
+		if (debug & DEBUG_HFCMULTI_INIT) {
+			printk(KERN_DEBUG "%s: do release_io_hfcmulti\n", __FUNCTION__);
+			release_io_hfcmulti(hc);
+		}
+		goto free_channels;
+	}
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: Init modes card(%d)\n", __FUNCTION__, HFC_idx+1);
+
+	hfcmulti_initmode(hc);
+	
+	/* check if Port Jumper config matches module param 'protocol' */
+	if (!hc->type && hc->ports<=4) {
+		// Dip Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) + GPI 19/20/23 (R_GPI_IN2))
+		dips = ((HFC_inb(hc, R_GPIO_IN1) >> 5)  & 0x7) | (HFC_inb(hc, R_GPI_IN2) & 0x98);
+
+		// Port mode (TE/NT) jumpers
+		pmj = ((HFC_inb(hc, R_GPI_IN3) >> 4)  & 0xf);
+
+		if (test_bit(HFC_CHIP_DIGICARD, &hc->chip))
+			pmj = ~pmj & 0xf;
+
+		printk(KERN_INFO "%s: DIPs(0x%x) jumpers(0x%x)\n", __FUNCTION__, dips, pmj);
+
+		pt = 0;
+		while(pt < hc->type) {
+			chan = hc->chan[(pt<<2)+2].ch;
+			// check for protocol param mismatch
+			if (((pmj & (1 << pt)) && (chan->inst.pid.protocol[0] == ISDN_PID_L0_TE_S0)) ||
+			    ((!(pmj & (1 << pt))) && (chan->inst.pid.protocol[0] == ISDN_PID_L0_NT_S0))) {
+				printk ("%s: protocol WARNING: port %i is jumpered for %s mode!\n",
+				        __FUNCTION__,
+				        pt,
+				        (pmj & (1 << pt)?"NT":"TE")
+				        );
+			}
+			pt++;
+		}
+	}
+	/* add stacks */
+	pt = 0;
+	while(pt < hc->ports) {
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: Adding d-stack: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt+1);
+		if (hc->type == 1)
+			chan = hc->chan[16].ch;
+		else
+			chan = hc->chan[(pt<<2)+2].ch;
+		if ((ret_err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &chan->inst))) {
+			int i=0;
+			printk(KERN_ERR  "MGR_ADDSTACK REQUEST dch err(%d)\n", ret_err);
+
+free_release:
+			/* all ports, hc is free */
+			for (i=0; i<hc->ports; i++)
+				release_port(hc, i); 
+			goto free_object;
+		}
+		/* indicate that this stack is created */
+		hc->created[pt] = 1;
+
+		dst = chan->inst.st;
+
+		i = 0;
+		while(i < bchperport) {
+			if (debug & DEBUG_HFCMULTI_INIT)
+				printk(KERN_DEBUG "%s: Adding b-stack: card(%d) port(%d) B-channel(%d)\n", __FUNCTION__, HFC_idx+1, pt+1, i+1);
+			if (hc->type == 1)
+				chan = hc->chan[i + 1 + (i>=15)].ch;
+			else
+				chan = hc->chan[(pt<<2) + i].ch;
+			if ((ret_err = mISDN_ctrl(dst, MGR_NEWSTACK | REQUEST, &chan->inst))) {
+				printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", ret_err);
+free_delstack:
+				mISDN_ctrl(dst, MGR_DELSTACK | REQUEST, NULL);
+				goto free_release;
+			}
+			i++;
+		}
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: (before MGR_SETSTACK REQUEST) layermask=0x%x\n", __FUNCTION__, pids[pt].layermask);
+
+		if ((ret_err = mISDN_ctrl(dst, MGR_SETSTACK | REQUEST, &pids[pt]))) {
+			printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", ret_err);
+			goto free_delstack;
+		}
+		if (debug & DEBUG_HFCMULTI_INIT)
+			printk(KERN_DEBUG "%s: (after MGR_SETSTACK REQUEST)\n", __FUNCTION__);
+
+		/* delay some time */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((100*HZ)/1000); /* Timeout 100ms */
+
+		/* tell stack, that we are ready */
+		mISDN_ctrl(dst, MGR_CTRLREADY | INDICATION, NULL);
+
+		pt++;
+	}
+
+	/* now turning on irq */
+	spin_lock_irqsave(&hc->lock, flags);
+	enable_hwirq(hc);
+	/* we are on air! */
+	allocated[HFC_idx] = 1;
+	HFC_cnt++;
+	spin_unlock_irqrestore(&hc->lock, flags);
+
+	HFC_idx++;
+	HFC_port_idx+=hc->ports;
+	return(0);
+
+	/* if an error ocurred */
+	free_channels:
+	i = 0;
+	while(i < 32) {
+		if (hc->chan[i].ch) {
+			if (debug & DEBUG_HFCMULTI_INIT)
+				printk(KERN_DEBUG "%s: free %c-channel %d (1..32)\n",
+					__FUNCTION__, test_bit(FLG_DCHANNEL, &hc->chan[i].ch->Flags) ?
+					'D' : 'B', i);
+			mISDN_freechannel(hc->chan[i].ch);
+			kfree(hc->chan[i].ch);
+			hc->chan[i].ch = NULL;
+		}
+		i++;
+	}
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: before REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt);
+	spin_lock_irqsave(&HFCM_obj.lock, flags);
+	list_del(&hc->list);
+	spin_unlock_irqrestore(&HFCM_obj.lock, flags);
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: after REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt);
+	kfree(hc);
+
+	free_object:
+	return(ret_err);
+}
+
+static void __devexit hfc_remove_pci(struct pci_dev *pdev)
+{
+	int i,ch;
+	hfc_multi_t	*card = pci_get_drvdata(pdev);
+
+	if (debug)
+		printk( KERN_INFO "removing hfc_multi card vendor:%x device:%x subvendor:%x subdevice:%x\n",
+			pdev->vendor,pdev->device,pdev->subsystem_vendor,pdev->subsystem_device);
+	if (card) {
+#if 1
+		for(i=0;i<card->ports;i++) { // type is also number of d-channel
+			if(card->created[i]) {
+				if (card->type == 1)
+					ch = 16;
+				else
+					ch = (i*4)+2;
+				// if created elete stack
+				if (card->chan[ch].ch &&
+					test_bit(FLG_DCHANNEL, &card->chan[ch].ch->Flags))
+					mISDN_ctrl(card->chan[ch].ch->inst.st,
+						MGR_DELSTACK | REQUEST, NULL);
+			}
+		}
+#endif
+		// relase all ports
+		allocated[card->idx] = 0;
+	}
+	else {
+		if (debug)
+			printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__);
+	}
+}
+
+static struct pci_device_id hfmultipci_ids[] __devinitdata = {
+
+	/** Cards with HFC-4S Chip**/
+	{ CCAG_VID, 0x08B4   , CCAG_VID, 0xB567, 0, 0, 0 }, //BN1S mini PCI
+	{ CCAG_VID, 0x08B4   , CCAG_VID, 0xB566, 0, 0, 0 }, //BN2S
+	{ CCAG_VID, 0x08B4   , CCAG_VID, 0xB569, 0, 0, 0 }, //BN2S mini PCI
+	{ CCAG_VID, 0x08B4   , CCAG_VID, 0xB560, 0, 0, 0 }, //BN4S
+	{ CCAG_VID, 0x08B4   , CCAG_VID, 0xB568, 0, 0, 0 }, //BN4S mini PCI
+	{ CCAG_VID, 0x08B4   , CCAG_VID, 0x08B4, 0, 0, 0 }, //Old Eval
+	{ CCAG_VID, 0x08B4   , CCAG_VID, 0xB520, 0, 0, 0 }, //IOB4ST
+	{ CCAG_VID, 0x08B4   , CCAG_VID, 0xB620, 0, 0, 0 }, //4S
+	{ 0xD161, 0xB410   , 0xD161, 0xB410, 0, 0, 0 }, //4S - Digium
+	{ CCAG_VID, 0x08B4   , CCAG_VID, 0xB540, 0, 0, 0 }, //4S Swyx
+	{ CCAG_VID, 0x08B4   , CCAG_VID, 0xB550, 0, 0, 0 }, //4S junghanns 2.0
+	
+	/** Cards with HFC-8S Chip**/
+	{ CCAG_VID, 0x16B8   , CCAG_VID, 0xB562, 0, 0, 0 }, //BN8S
+	{ CCAG_VID, 0x16B8   , CCAG_VID, 0xB56B, 0, 0, 0 }, //BN8S+
+	{ CCAG_VID, 0x16B8   , CCAG_VID, 0x16B8, 0, 0, 0 }, //old Eval
+	{ CCAG_VID, 0x16B8   , CCAG_VID, 0xB521, 0, 0, 0 }, //IOB8ST Recording
+	{ CCAG_VID, 0x16B8   , CCAG_VID, 0xB522, 0, 0, 0 }, //IOB8ST 
+	{ CCAG_VID, 0x16B8   , CCAG_VID, 0xB552, 0, 0, 0 }, //IOB8ST 
+	{ CCAG_VID, 0x16B8   , CCAG_VID, 0xB622, 0, 0, 0 }, //8S
+
+
+	/** Cards with HFC-E1 Chip**/
+	{ CCAG_VID, 0x30B1   , CCAG_VID, 0xB563, 0, 0, 0 }, //BNE1
+	{ CCAG_VID, 0x30B1   , CCAG_VID, 0xB56A, 0, 0, 0 }, //BNE1 mini PCI
+	{ CCAG_VID, 0x30B1   , CCAG_VID, 0xB565, 0, 0, 0 }, //BNE1 + (Dual)
+	{ CCAG_VID, 0x30B1   , CCAG_VID, 0xB564, 0, 0, 0 }, //BNE1 (Dual)
+
+	{ CCAG_VID, 0x30B1   , CCAG_VID, 0x30B1, 0, 0, 0 }, //Old Eval
+	{ CCAG_VID, 0x30B1   , CCAG_VID, 0xB523, 0, 0, 0 }, //IOB1E1
+	{ CCAG_VID, 0x30B1   , CCAG_VID, 0xC523, 0, 0, 0 }, //E1
+	
+#if 0
+	{ CCAG_VID, 0x08B4   , PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ CCAG_VID, 0x16B8   , PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ CCAG_VID, 0x30B1   , PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+	{ 0x10B5,   0x9030   , CCAG_VID,   0x3136 ,    0, 0, 0 },  // PLX PCI Bridge
+	{ 0x10B5,   0x9030   , PCI_ANY_ID,   PCI_ANY_ID ,  0, 0, 0 },  // PLX PCI Bridge
+	{0, }
+};
+MODULE_DEVICE_TABLE(pci, hfmultipci_ids);
+
+static struct pci_driver hfcmultipci_driver = {
+	name:     "hfc_multi",
+	probe:    hfcpci_probe,
+	remove:   __devexit_p(hfc_remove_pci),
+	id_table: hfmultipci_ids,
+};
+
+static void __exit
+HFCmulti_cleanup(void)
+{
+	hfc_multi_t *hc,*next;
+	int err;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	/* unload interrupt function symbol*/
+	if (hfc_interrupt) {
+		symbol_put(ztdummy_extern_interrupt);
+	}
+	if (register_interrupt) {
+		symbol_put(ztdummy_register_interrupt);
+	}
+	/* unregister mISDN object */
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: entered (refcnt = %d HFC_cnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt, HFC_cnt);
+
+	if ((err = mISDN_unregister(&HFCM_obj))) {
+		printk(KERN_ERR "Can't unregister HFC-Multi cards error(%d)\n", err);
+	}
+	
+	/* remove remaining devices, but this should never happen */
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: now checking ilist (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt);
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: done (refcnt = %d HFC_cnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt, HFC_cnt);
+
+
+	list_for_each_entry_safe(hc, next, &HFCM_obj.ilist, list) {
+		if (debug) printk(KERN_ERR "HFC PCI card struct not empty refs %d\n", HFCM_obj.refcnt);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+		int i;
+		for (i=0;i<hc->ports;i++) {
+				release_port(hc, i);
+		}
+#endif
+		release_ports_hw(hc); /* all ports, hc is free */
+		udelay(1000);
+	}
+	
+	/* get rid of all devices of this driver */
+	pci_unregister_driver(&hfcmultipci_driver);
+}
+
+static int __init
+HFCmulti_init(void)
+{
+	int err, i;
+	char tmpstr[64];
+
+#if !defined(CONFIG_HOTPLUG) || !defined(MODULE)
+#error	"CONFIG_HOTPLUG and MODULE are not defined."
+#endif
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: init entered\n", __FUNCTION__);
+
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+	strcpy(tmpstr, hfcmulti_revision);
+	/* get interrupt function pointer */
+	hfc_interrupt = symbol_get(ztdummy_extern_interrupt);
+	register_interrupt = symbol_get(ztdummy_register_interrupt);
+	printk(KERN_INFO "mISDN: HFC-multi driver Rev. %s\n", mISDN_getrev(tmpstr));
+
+	switch(poll) {
+		case 0:
+		poll_timer = 6;
+		poll = 128;
+		break; /* wenn dieses break nochmal verschwindet, gibt es heisse ohren :-) */
+		case 8:
+		poll_timer = 2;
+		break;
+		case 16:
+		poll_timer = 3;
+		break;
+		case 32:
+		poll_timer = 4;
+		break;
+		case 64:
+		poll_timer = 5;
+		break;
+		case 128:
+		poll_timer = 6;
+		break;
+		case 256:
+		poll_timer = 7;
+		break;
+		default:
+		printk(KERN_ERR "%s: Wrong poll value (%d).\n", __FUNCTION__, poll);
+		err = -EINVAL;
+		return(err);
+
+	}
+
+	memset(&HFCM_obj, 0, sizeof(HFCM_obj));
+#ifdef MODULE
+	HFCM_obj.owner = THIS_MODULE;
+#endif
+	spin_lock_init(&HFCM_obj.lock);
+	INIT_LIST_HEAD(&HFCM_obj.ilist);
+	HFCM_obj.name = HFCName;
+	HFCM_obj.own_ctrl = HFC_manager;
+	HFCM_obj.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0 | ISDN_PID_L0_NT_S0
+				| ISDN_PID_L0_TE_E1 | ISDN_PID_L0_NT_E1;
+	HFCM_obj.DPROTO.protocol[1] = ISDN_PID_L1_NT_S0
+				| ISDN_PID_L1_TE_E1 | ISDN_PID_L1_NT_E1;
+	HFCM_obj.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS | ISDN_PID_L1_B_64HDLC;
+	HFCM_obj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS | ISDN_PID_L2_B_RAWDEV;
+
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: registering HFCM_obj\n", __FUNCTION__);
+	if ((err = mISDN_register(&HFCM_obj))) {
+		printk(KERN_ERR "Can't register HFC-Multi cards error(%d)\n", err);
+		return(err);
+	}
+	if (debug & DEBUG_HFCMULTI_INIT)
+		printk(KERN_DEBUG "%s: new mISDN object (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt);
+
+	for(i=0;i<MAX_CARDS;i++) allocated[i]=0;
+	HFC_cnt = 0;
+
+#if 1
+	err = pci_register_driver(&hfcmultipci_driver);
+	if (err < 0)
+	{
+		printk(KERN_ERR "error registering pci driver:%x\n",err);
+		HFCmulti_cleanup();
+		return(err);
+	}
+#endif
+	printk(KERN_INFO "%d devices registered\n", HFC_cnt);
+
+	mISDN_module_register(THIS_MODULE);
+
+	return(0);
+}
+
+
+#ifdef MODULE
+module_init(HFCmulti_init);
+module_exit(HFCmulti_cleanup);
+#endif
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_multi.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_multi.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_multi.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1311 @@
+/*
+
+ * see notice in hfc_multi.c
+ */
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+
+
+/* If you want to use Memory Access instead of IO Access uncoment the following line*/
+//#define CONFIG_HFCMULTI_PCIMEM
+
+// IMPORTANT!!! use  CONFIG_PLX_PCI_BRIDGE only in conjunction with  CONFIG_HFCMULTI_PCIMEM
+//#define CONFIG_PLX_PCI_BRIDGE   // TODO should be defined in kernel config
+
+#ifdef CONFIG_PLX_PCI_BRIDGE
+#undef FIFO_32BIT_ACCESS
+#ifndef CONFIG_HFCMULTI_PCIMEM
+#define CONFIG_HFCMULTI_PCIMEM
+#endif
+#endif
+
+#define DEBUG_HFCMULTI_FIFO	0x0001
+#define DEBUG_HFCMULTI_CRC	0x0002
+#define DEBUG_HFCMULTI_INIT 0x0004
+#define DEBUG_HFCMULTI_MGR	0x0008
+#define DEBUG_HFCMULTI_MODE	0x0010
+#define DEBUG_HFCMULTI_MSG	0x0020
+#define DEBUG_HFCMULTI_STATE 0x0040
+#define DEBUG_HFCMULTI_SYNC	0x0100
+#define DEBUG_HFCMULTI_DTMF	0x0200
+#define DEBUG_HFCMULTI_LOCK	0x8000
+
+#define PCI_ENA_REGIO	0x01
+#define PCI_ENA_MEMIO	0x02
+
+/* NOTE: some registers are assigned multiple times due to different modes
+         also registers are assigned differen for HFC-4s/8s and HFC-E1
+*/
+
+// #define MAX_FRAME_SIZE	2048
+
+struct hfc_chan {
+	channel_t	*ch;	/* link if channel is a D-channel */
+	int		port; 	/* the interface port this channel is associated with */
+	int		nt_timer; /* -1 if off, 0 if elapsed, >0 if running */
+	int		los, ais, slip_tx, slip_rx; /* current alarms */
+	int		jitter;
+	u_long		cfg;	/* port configuration */
+	int		sync;	/* sync state (used by E1) */
+	DWORD		protocol;/* current protocol */
+	int		slot_tx; /* current pcm slot */
+	int		bank_tx; /* current pcm bank */
+	int		slot_rx;
+	int		bank_rx;
+	int		conf;	/* conference setting of TX slot */
+	int		txpending; /* if there is currently data in the FIFO 0=no, 1=yes, 2=splloop */
+	int		e1_state; /* keep track of last state */
+};
+
+typedef struct hfc_chan		hfc_chan_t;
+
+struct hfcmulti_hw {
+	BYTE	r_ctrl;
+	BYTE	r_irq_ctrl;
+	BYTE	r_cirm;
+	BYTE	r_ram_sz;
+	BYTE	r_pcm_md0;
+	BYTE	r_irqmsk_misc;
+	BYTE	r_dtmf;
+	BYTE	r_st_sync;
+	BYTE	r_sci_msk;
+	BYTE	r_tx0, r_tx1;
+	BYTE	a_st_ctrl0[8];
+	timer_t	timer;
+};
+
+typedef struct hfcmulti_hw	hfcmulti_hw_t;
+
+/* for each stack these flags are used (cfg) */
+#define HFC_CFG_NTMODE		0 /* NT-mode */
+#define HFC_CFG_NONCAP_TX	1 /* S/T TX interface has less capacity */
+#define HFC_CFG_DIS_ECHANNEL	2 /* disable E-channel processing */
+#define HFC_CFG_REG_ECHANNEL	3 /* register E-channel */
+#define HFC_CFG_OPTICAL		4 /* the E1 interface is optical */
+#define HFC_CFG_REPORT_LOS	5 /* the card should report loss of signal */
+#define HFC_CFG_REPORT_AIS	6 /* the card should report alarm ind. sign. */
+#define HFC_CFG_REPORT_SLIP	7 /* the card should report bit slips */
+#define HFC_CFG_DTMF		8 /* enable DTMF-detection */
+#define HFC_CFG_CRC4		9 /* disable CRC-4 Multiframe mode,
+				     use double frame instead. */
+
+#define HFC_CHIP_EXRAM_128	0 /* external ram 128k */
+#define HFC_CHIP_EXRAM_512	1 /* external ram 256k */
+#define HFC_CHIP_REVISION0	2 /* old fifo handling */
+#define HFC_CHIP_PCM_SLAVE	3 /* PCM is slave */
+#define HFC_CHIP_CLOCK_IGNORE	4 /* ignore missing PCM clock */
+#define HFC_CHIP_RX_SYNC	5 /* ignore missing PCM clock */
+#define HFC_CHIP_DTMF		6 /* DTMF decoding is enabled */
+#define HFC_CHIP_ULAW		7 /* ULAW mode */
+#define HFC_CHIP_CLOCK2		8 /* double clock mode */
+#define HFC_CHIP_CRYSTAL_CLOCK	9 /* autarc clocking mode */
+#define HFC_CHIP_WATCHDOG	10 /* wether we should send signals 
+					to the watchdog */
+#define HFC_CHIP_DIGICARD       11 /* wether we have a b410p with echocan in 
+					hw */
+
+struct hfc_multi {
+	struct list_head	list;
+	char		name[32];
+	int		idx;	/* chip index for module parameters */
+	int		id;	/* chip number starting with 1 */
+	int		pcm;	/* id of pcm bus */
+	int		type;
+	int		ports;
+
+	u_int		irq;	/* irq used by card */
+	u_int		irqcnt;
+	struct pci_dev	*pci_dev;
+#ifdef CONFIG_HFCMULTI_PCIMEM
+	u_long	 pci_origmembase, plx_origmembase, dsp_origmembase;
+	u_char	*pci_membase;/* PCI memory (MUST BE BYTE POINTER) */
+	u_char	*plx_membase;/* PCI memory (MUST BE BYTE POINTER) */
+	u_char	*dsp_membase;/* PCI memory (MUST BE BYTE POINTER) */
+#else
+	u_int		pci_iobase;/* PCI IO (MUST BE BYTE POINTER) */
+#endif
+	hfcmulti_hw_t	hw;	/* remember data of write-only-registers */
+	u_char		e1_switch; /* last state of the switches */
+
+	u_long		chip;	/* chip configuration */
+	int		masterclk;/* port that provides master clock -1=off */
+	int		dtmf;	/* flag that dtmf is currently in process */
+	int		Flen;	/* F-buffer size */
+	int		Zlen;	/* Z-buffer size (not maximum) */
+	int		Zmin;	/* Z-buffer offset */
+	int		DTMFbase;/* base address of DTMF coefficients */
+
+	u_int		slots;	/* number of PCM slots */
+	u_int		leds;	/* type of leds */
+	u_int		ledcount; /* used to animate leds */
+	int		opticalsupport; /* has the e1 board an optical Interface*/
+
+	u_long		wdcount; /* every 500 ms we need to send the watchdog a signal */
+	u_char		wdbyte; /* watchdog toggle byte*/
+	u_int		activity[8]; /* if there is any action on this port (will be cleared after showing led-states) */
+
+	spinlock_t	lock;	/* the lock */
+
+	/* the channel index is counted from 0, regardless where the channel
+	 * is located on the hfc-channel.
+	 * the bch->channel is equvalent to the hfc-channel
+	 */
+	hfc_chan_t	chan[32];
+	u_char		created[8]; /* what port is created */
+	signed char	slot_owner[256]; /* owner channel of slot */
+};
+
+typedef struct hfc_multi	hfc_multi_t;
+
+
+/*********************************************\
+|* REGISTER SETTING FOR HFC-4S/8S AND HFC-E1 *|
+\*********************************************/
+
+/* write only registers */
+#define R_CIRM			0x00
+#define R_CTRL			0x01
+#define R_BRG_PCM_CFG 		0x02
+#define R_RAM_ADDR0		0x08
+#define R_RAM_ADDR1		0x09
+#define R_RAM_ADDR2		0x0A
+#define R_FIRST_FIFO		0x0B
+#define R_RAM_SZ		0x0C
+#define R_FIFO_MD		0x0D
+#define R_INC_RES_FIFO		0x0E
+#define R_FSM_IDX		0x0F
+#define R_FIFO			0x0F
+#define R_SLOT			0x10
+#define R_IRQMSK_MISC		0x11
+#define R_SCI_MSK		0x12
+#define R_IRQ_CTRL		0x13
+#define R_PCM_MD0		0x14
+#define R_PCM_MD1		0x15
+#define R_PCM_MD2		0x15
+#define R_SH0H			0x15
+#define R_SH1H			0x15
+#define R_SH0L			0x15
+#define R_SH1L			0x15
+#define R_SL_SEL0		0x15
+#define R_SL_SEL1		0x15
+#define R_SL_SEL2		0x15
+#define R_SL_SEL3		0x15
+#define R_SL_SEL4		0x15
+#define R_SL_SEL5		0x15
+#define R_SL_SEL6		0x15
+#define R_SL_SEL7		0x15
+#define R_ST_SEL		0x16
+#define R_ST_SYNC		0x17
+#define R_CONF_EN		0x18
+#define R_TI_WD			0x1A
+#define R_BERT_WD_MD		0x1B
+#define R_DTMF			0x1C
+#define R_DTMF_N		0x1D
+#define R_E1_WR_STA		0x20
+#define R_E1_RD_STA		0x20
+#define R_LOS0			0x22
+#define R_LOS1			0x23
+#define R_RX0			0x24
+#define R_RX_FR0		0x25
+#define R_RX_FR1		0x26
+#define R_TX0			0x28
+#define R_TX1			0x29
+#define R_TX_FR0		0x2C
+
+#define R_TX_FR1		0x2D
+#define R_TX_FR2		0x2E
+#define R_JATT_ATT		0x2F /* undocumented */
+#define A_ST_RD_STATE		0x30
+#define A_ST_WR_STATE		0x30
+#define R_RX_OFF		0x30
+#define A_ST_CTRL0		0x31
+#define R_SYNC_OUT		0x31
+#define A_ST_CTRL1		0x32
+#define A_ST_CTRL2		0x33
+#define A_ST_SQ_WR		0x34
+#define R_TX_OFF		0x34
+#define R_SYNC_CTRL		0x35
+#define A_ST_CLK_DLY		0x37
+#define R_PWM0			0x38
+#define R_PWM1			0x39
+#define A_ST_B1_TX		0x3C
+#define A_ST_B2_TX		0x3D
+#define A_ST_D_TX		0x3E
+#define R_GPIO_OUT0		0x40
+#define R_GPIO_OUT1		0x41
+#define R_GPIO_EN0		0x42
+#define R_GPIO_EN1		0x43
+#define R_GPIO_SEL		0x44
+#define R_BRG_CTRL		0x45
+#define R_PWM_MD		0x46
+#define R_BRG_MD		0x47
+#define R_BRG_TIM0		0x48
+#define R_BRG_TIM1		0x49
+#define R_BRG_TIM2		0x4A
+#define R_BRG_TIM3		0x4B
+#define R_BRG_TIM_SEL01		0x4C
+#define R_BRG_TIM_SEL23		0x4D
+#define R_BRG_TIM_SEL45		0x4E
+#define R_BRG_TIM_SEL67		0x4F
+#define A_SL_CFG		0xD0
+#define A_CONF			0xD1
+#define A_CH_MSK		0xF4
+#define A_CON_HDLC		0xFA
+#define A_SUBCH_CFG		0xFB
+#define A_CHANNEL		0xFC
+#define A_FIFO_SEQ		0xFD
+#define A_IRQ_MSK		0xFF
+
+/* read only registers */
+#define A_Z12			0x04
+#define A_Z1L			0x04
+#define A_Z1			0x04
+#define A_Z1H			0x05
+#define A_Z2L			0x06
+#define A_Z2			0x06
+#define A_Z2H			0x07
+#define A_F1			0x0C
+#define A_F12			0x0C
+#define A_F2			0x0D
+#define R_IRQ_OVIEW		0x10
+#define R_IRQ_MISC		0x11
+#define R_IRQ_STATECH		0x12
+#define R_CONF_OFLOW		0x14
+#define R_RAM_USE		0x15
+#define R_CHIP_ID		0x16
+#define R_BERT_STA		0x17
+#define R_F0_CNTL		0x18
+#define R_F0_CNTH		0x19
+#define R_BERT_EC		0x1A
+#define R_BERT_ECL		0x1A
+#define R_BERT_ECH		0x1B
+#define R_STATUS		0x1C
+#define R_CHIP_RV		0x1F
+#define R_STATE			0x20
+#define R_RX_STA0		0x24
+#define R_RX_STA1		0x25
+#define R_RX_STA2		0x26
+#define R_RX_STA3		0x27
+#define R_JATT_DIR		0x2b /* undocumented */
+#define R_SLIP			0x2c
+#define A_ST_RD_STA		0x30
+#define R_FAS_EC		0x30
+#define R_FAS_ECL		0x30
+#define R_FAS_ECH		0x31
+#define R_VIO_EC		0x32
+#define R_VIO_ECL		0x32
+#define R_VIO_ECH		0x33
+#define A_ST_SQ_RD		0x34
+#define R_CRC_EC		0x34
+#define R_CRC_ECL		0x34
+#define R_CRC_ECH		0x35
+#define R_E_EC			0x36
+#define R_E_ECL			0x36
+#define R_E_ECH			0x37
+#define R_SA6_SA13_EC		0x38
+#define R_SA6_SA13_ECL		0x38
+#define R_SA6_SA13_ECH		0x39
+#define R_SA6_SA23_EC		0x3A
+#define R_SA6_SA23_ECL		0x3A
+#define R_SA6_SA23_ECH		0x3B
+#define A_ST_B1_RX		0x3C
+#define A_ST_B2_RX		0x3D
+#define A_ST_D_RX		0x3E
+#define A_ST_E_RX		0x3F
+#define R_GPIO_IN0		0x40
+#define R_GPIO_IN1		0x41
+#define R_GPI_IN0		0x44
+#define R_GPI_IN1		0x45
+#define R_GPI_IN2		0x46
+#define R_GPI_IN3		0x47
+#define R_INT_DATA		0x88
+#define R_IRQ_FIFO_BL0		0xC8
+#define R_IRQ_FIFO_BL1		0xC9
+#define R_IRQ_FIFO_BL2		0xCA
+#define R_IRQ_FIFO_BL3		0xCB
+#define R_IRQ_FIFO_BL4		0xCC
+#define R_IRQ_FIFO_BL5		0xCD
+#define R_IRQ_FIFO_BL6		0xCE
+#define R_IRQ_FIFO_BL7		0xCF
+
+/* read and write registers */
+#define A_FIFO_DATA0		0x80
+#define A_FIFO_DATA1		0x80
+#define A_FIFO_DATA2		0x80
+#define A_FIFO_DATA0_NOINC	0x84
+#define A_FIFO_DATA1_NOINC	0x84
+#define A_FIFO_DATA2_NOINC	0x84
+#define R_RAM_DATA		0xC0
+
+
+/****************************************\
+|* BIT SETTING FOR HFC-4S/8S AND HFC-E1 *|
+\****************************************/
+
+/* chapter 2: universal bus interface */
+/* R_CIRM */
+#define V_IRQ_SEL		0x01
+#define V_SRES			0x08
+#define V_HFCRES		0x10
+#define V_PCMRES		0x20
+#define V_STRES			0x40
+#define V_ETRES			0x40
+#define V_RLD_EPR		0x80
+/* R_CTRL */
+#define V_FIFO_LPRIO		0x02
+#define V_SLOW_RD		0x04
+#define V_EXT_RAM		0x08
+#define V_CLK_OFF		0x20
+#define V_ST_CLK		0x40
+/* R_RAM_ADDR0 */
+#define V_RAM_ADDR2		0x01
+#define V_ADDR_RES		0x40
+#define V_ADDR_INC		0x80
+/* R_RAM_SZ */
+#define V_RAM_SZ		0x01
+#define V_PWM0_16KHZ		0x10
+#define V_PWM1_16KHZ		0x20
+#define V_FZ_MD			0x80
+/* R_CHIP_ID */
+#define V_PNP_IRQ		0x01
+#define V_CHIP_ID		0x10
+
+/* chapter 3: data flow */
+/* R_FIRST_FIFO */
+#define V_FIRST_FIRO_DIR	0x01
+#define V_FIRST_FIFO_NUM	0x02
+/* R_FIFO_MD */
+#define V_FIFO_MD		0x01
+#define V_CSM_MD		0x04
+#define V_FSM_MD		0x08
+#define V_FIFO_SZ		0x10
+/* R_FIFO */
+#define V_FIFO_DIR		0x01
+#define V_FIFO_NUM		0x02
+#define V_REV			0x80
+/* R_SLOT */
+#define V_SL_DIR		0x01
+#define V_SL_NUM		0x02
+/* A_SL_CFG */
+#define V_CH_DIR		0x01
+#define V_CH_SEL		0x02
+#define V_ROUTING		0x40
+/* A_CON_HDLC */
+#define V_IFF			0x01
+#define V_HDLC_TRP		0x02
+#define V_TRP_IRQ		0x04
+#define V_DATA_FLOW		0x20
+/* A_SUBCH_CFG */
+#define V_BIT_CNT		0x01
+#define V_START_BIT		0x08
+#define V_LOOP_FIFO		0x40
+#define V_INV_DATA		0x80
+/* A_CHANNEL */
+#define V_CH_DIR0		0x01
+#define V_CH_NUM0		0x02
+/* A_FIFO_SEQ */
+#define V_NEXT_FIFO_DIR		0x01
+#define V_NEXT_FIFO_NUM		0x02
+#define V_SEQ_END		0x40
+
+/* chapter 4: FIFO handling and HDLC controller */
+/* R_INC_RES_FIFO */
+#define V_INC_F			0x01
+#define V_RES_F			0x02
+#define V_RES_LOST		0x04
+
+/* chapter 5: S/T interface */
+/* R_SCI_MSK */
+#define V_SCI_MSK_ST0		0x01
+#define V_SCI_MSK_ST1		0x02
+#define V_SCI_MSK_ST2		0x04
+#define V_SCI_MSK_ST3		0x08
+#define V_SCI_MSK_ST4		0x10
+#define V_SCI_MSK_ST5		0x20
+#define V_SCI_MSK_ST6		0x40
+#define V_SCI_MSK_ST7		0x80
+/* R_ST_SEL */
+#define V_ST_SEL		0x01
+#define V_MULT_ST		0x08
+/* R_ST_SYNC */
+#define V_SYNC_SEL		0x01
+#define V_AUTO_SYNC		0x08
+/* A_ST_WR_STA */
+#define V_ST_SET_STA		0x01
+#define V_ST_LD_STA		0x10
+#define V_ST_ACT		0x20
+#define V_SET_G2_G3		0x80
+/* A_ST_CTRL0 */
+#define V_B1_EN			0x01
+#define V_B2_EN			0x02
+#define V_ST_MD			0x04
+#define V_D_PRIO		0x08
+#define V_SQ_EN			0x10
+#define V_96KHZ			0x20
+#define V_TX_LI			0x40
+#define V_ST_STOP		0x80
+/* A_ST_CTRL1 */
+#define V_G2_G3_EN		0x01
+#define V_D_HI			0x04
+#define V_E_IGNO		0x08
+#define V_E_LO			0x10
+#define V_B12_SWAP		0x80
+/* A_ST_CTRL2 */
+#define V_B1_RX_EN		0x01
+#define V_B2_RX_EN		0x02
+#define V_ST_TRIS		0x40
+/* A_ST_CLK_DLY */
+#define V_ST_CK_DLY		0x01
+#define V_ST_SMPL		0x10
+/* A_ST_D_TX */
+#define V_ST_D_TX		0x40
+/* R_IRQ_STATECH */
+#define V_SCI_ST0		0x01
+#define V_SCI_ST1		0x02
+#define V_SCI_ST2		0x04
+#define V_SCI_ST3		0x08
+#define V_SCI_ST4		0x10
+#define V_SCI_ST5		0x20
+#define V_SCI_ST6		0x40
+#define V_SCI_ST7		0x80
+/* A_ST_RD_STA */
+#define V_ST_STA		0x01
+#define V_FR_SYNC_ST		0x10
+#define V_TI2_EXP		0x20
+#define V_INFO0			0x40
+#define V_G2_G3			0x80
+/* A_ST_SQ_RD */
+#define V_ST_SQ			0x01
+#define V_MF_RX_RDY		0x10
+#define V_MF_TX_RDY		0x80
+/* A_ST_D_RX */
+#define V_ST_D_RX		0x40
+/* A_ST_E_RX */
+#define V_ST_E_RX		0x40
+
+/* chapter 5: E1 interface */
+/* R_E1_WR_STA */
+/* R_E1_RD_STA */
+#define V_E1_SET_STA		0x01
+#define V_E1_LD_STA		0x10
+/* R_RX0 */
+#define V_RX_CODE		0x01
+#define V_RX_FBAUD		0x04
+#define V_RX_CMI		0x08
+#define V_RX_INV_CMI		0x10
+#define V_RX_INV_CLK		0x20
+#define V_RX_INV_DATA		0x40
+#define V_AIS_ITU		0x80
+/* R_RX_FR0 */
+#define V_NO_INSYNC		0x01
+#define V_AUTO_RESYNC		0x02
+#define V_AUTO_RECO		0x04
+#define V_SWORD_COND		0x08
+#define V_SYNC_LOSS		0x10
+#define V_XCRC_SYNC		0x20
+#define V_MF_RESYNC		0x40
+#define V_RESYNC		0x80
+/* R_RX_FR1 */
+#define V_RX_MF			0x01
+#define V_RX_MF_SYNC		0x02
+#define V_RX_SL0_RAM		0x04
+#define V_ERR_SIM		0x20
+#define V_RES_NMF		0x40
+/* R_TX0 */
+#define V_TX_CODE		0x01
+#define V_TX_FBAUD		0x04
+#define V_TX_CMI_CODE		0x08
+#define V_TX_INV_CMI_CODE	0x10
+#define V_TX_INV_CLK		0x20
+#define V_TX_INV_DATA		0x40
+#define V_OUT_EN		0x80
+/* R_TX1 */
+#define V_INV_CLK		0x01
+#define V_EXCHG_DATA_LI		0x02
+#define V_AIS_OUT		0x04
+#define V_ATX			0x20
+#define V_NTRI			0x40
+#define V_AUTO_ERR_RES		0x80
+/* R_TX_FR0 */
+#define V_TRP_FAS		0x01
+#define V_TRP_NFAS		0x02
+#define V_TRP_RAL		0x04
+#define V_TRP_SA		0x08
+/* R_TX_FR1 */
+#define V_TX_FAS		0x01
+#define V_TX_NFAS		0x02
+#define V_TX_RAL		0x04
+#define V_TX_SA			0x08
+/* R_TX_FR2 */
+#define V_TX_MF			0x01
+#define V_TRP_SL0		0x02
+#define V_TX_SL0_RAM		0x04
+#define V_TX_E			0x10
+#define V_NEG_E			0x20
+#define V_XS12_ON		0x40
+#define V_XS15_ON		0x80
+/* R_RX_OFF */
+#define V_RX_SZ			0x01
+#define V_RX_INIT		0x04
+/* R_SYNC_OUT */
+#define V_SYNC_E1_RX		0x01
+#define V_IPATS0		0x20
+#define V_IPATS1		0x40
+#define V_IPATS2		0x80
+/* R_TX_OFF */
+#define V_TX_SZ			0x01
+#define V_TX_INIT		0x04
+/* R_SYNC_CTRL */
+#define V_EXT_CLK_SYNC		0x01
+#define V_SYNC_OFFS		0x02
+#define V_PCM_SYNC		0x04
+#define V_NEG_CLK		0x08
+#define V_HCLK			0x10
+//#define V_JATT_AUTO_DEL		0x20
+//#define V_JATT_AUTO		0x40
+#define V_JATT_OFF		0x80
+/* R_STATE */
+#define V_E1_STA		0x01
+#define V_ALT_FR_RX		0x40
+#define V_ALT_FR_TX		0x80
+/* R_RX_STA0 */
+#define V_RX_STA		0x01
+#define V_FR_SYNC_E1		0x04
+#define V_SIG_LOS		0x08
+#define V_MFA_STA		0x10
+#define V_AIS			0x40
+#define V_NO_MF_SYNC		0x80
+/* R_RX_STA1 */
+#define V_SI_FAS		0x01
+#define V_SI_NFAS		0x02
+#define V_A			0x04
+#define V_CRC_OK		0x08
+#define V_TX_E1			0x10
+#define V_TX_E2			0x20
+#define V_RX_E1			0x40
+#define V_RX_E2			0x80
+/* R_SLIP */
+#define V_SLIP_RX		0x01
+#define V_FOSLIP_RX		0x08
+#define V_SLIP_TX		0x10
+#define V_FOSLIP_TX		0x80
+
+/* chapter 6: PCM interface */
+/* R_PCM_MD0 */
+#define V_PCM_MD		0x01
+#define V_C4_POL		0x02
+#define V_F0_NEG		0x04
+#define V_F0_LEN		0x08
+#define V_PCM_ADDR		0x10
+/* R_SL_SEL0 */
+#define V_SL_SEL0		0x01
+#define V_SH_SEL0		0x80
+/* R_SL_SEL1 */
+#define V_SL_SEL1		0x01
+#define V_SH_SEL1		0x80
+/* R_SL_SEL2 */
+#define V_SL_SEL2		0x01
+#define V_SH_SEL2		0x80
+/* R_SL_SEL3 */
+#define V_SL_SEL3		0x01
+#define V_SH_SEL3		0x80
+/* R_SL_SEL4 */
+#define V_SL_SEL4		0x01
+#define V_SH_SEL4		0x80
+/* R_SL_SEL5 */
+#define V_SL_SEL5		0x01
+#define V_SH_SEL5		0x80
+/* R_SL_SEL6 */
+#define V_SL_SEL6		0x01
+#define V_SH_SEL6		0x80
+/* R_SL_SEL7 */
+#define V_SL_SEL7		0x01
+#define V_SH_SEL7		0x80
+/* R_PCM_MD1 */
+#define V_ODEC_CON		0x01
+#define V_PLL_ADJ		0x04
+#define V_PCM_DR		0x10
+#define V_PCM_LOOP		0x40
+/* R_PCM_MD2 */
+#define V_SYNC_PLL		0x02
+#define V_SYCN_SRC		0x04
+#define V_SYNC_OUT		0x08
+#define V_ICR_FR_TIME		0x40
+#define V_EN_PLL		0x80
+
+/* chapter 7: pulse width modulation */
+/* R_PWM_MD */
+#define V_EXT_IRQ_EN		0x08
+#define V_PWM0_MD		0x10
+#define V_PWM1_MD		0x40
+
+/* chapter 8: multiparty audio conferences */
+/* R_CONF_EN */
+#define V_CONF_EN		0x01
+#define V_ULAW			0x80
+/* A_CONF */
+#define V_CONF_NUM		0x01
+#define V_NOISE_SUPPR		0x08
+#define V_ATT_LEV		0x20
+#define V_CONF_SL		0x80
+/* R_CONF_OFLOW */
+#define V_CONF_OFLOW0		0x01
+#define V_CONF_OFLOW1		0x02
+#define V_CONF_OFLOW2		0x04
+#define V_CONF_OFLOW3		0x08
+#define V_CONF_OFLOW4		0x10
+#define V_CONF_OFLOW5		0x20
+#define V_CONF_OFLOW6		0x40
+#define V_CONF_OFLOW7		0x80
+
+/* chapter 9: DTMF contoller */
+/* R_DTMF0 */
+#define V_DTMF_EN		0x01
+#define V_HARM_SEL		0x02
+#define V_DTMF_RX_CH		0x04
+#define V_DTMF_STOP		0x08
+#define V_CHBL_SEL		0x10
+#define V_RST_DTMF		0x40
+#define V_ULAW_SEL		0x80
+
+/* chapter 10: BERT */
+/* R_BERT_WD_MD */
+#define V_PAT_SEQ		0x01
+#define V_BERT_ERR		0x08
+#define V_AUTO_WD_RES		0x20
+#define V_WD_RES		0x80
+/* R_BERT_STA */
+#define V_BERT_SYNC_SRC		0x01
+#define V_BERT_SYNC		0x10
+#define V_BERT_INV_DATA		0x20
+
+/* chapter 11: auxiliary interface */
+/* R_BRG_PCM_CFG */
+#define V_BRG_EN		0x01
+#define V_BRG_MD		0x02
+#define V_PCM_CLK		0x20
+#define V_ADDR_WRDLY		0x40
+/* R_BRG_CTRL */
+#define V_BRG_CS		0x01
+#define V_BRG_ADDR		0x08
+#define V_BRG_CS_SRC		0x80
+/* R_BRG_MD */
+#define V_BRG_MD0		0x01
+#define V_BRG_MD1		0x02
+#define V_BRG_MD2		0x04
+#define V_BRG_MD3		0x08
+#define V_BRG_MD4		0x10
+#define V_BRG_MD5		0x20
+#define V_BRG_MD6		0x40
+#define V_BRG_MD7		0x80
+/* R_BRG_TIM0 */
+#define V_BRG_TIM0_IDLE		0x01
+#define V_BRG_TIM0_CLK		0x10
+/* R_BRG_TIM1 */
+#define V_BRG_TIM1_IDLE		0x01
+#define V_BRG_TIM1_CLK		0x10
+/* R_BRG_TIM2 */
+#define V_BRG_TIM2_IDLE		0x01
+#define V_BRG_TIM2_CLK		0x10
+/* R_BRG_TIM3 */
+#define V_BRG_TIM3_IDLE		0x01
+#define V_BRG_TIM3_CLK		0x10
+/* R_BRG_TIM_SEL01 */
+#define V_BRG_WR_SEL0		0x01
+#define V_BRG_RD_SEL0		0x04
+#define V_BRG_WR_SEL1		0x10
+#define V_BRG_RD_SEL1		0x40
+/* R_BRG_TIM_SEL23 */
+#define V_BRG_WR_SEL2		0x01
+#define V_BRG_RD_SEL2		0x04
+#define V_BRG_WR_SEL3		0x10
+#define V_BRG_RD_SEL3		0x40
+/* R_BRG_TIM_SEL45 */
+#define V_BRG_WR_SEL4		0x01
+#define V_BRG_RD_SEL4		0x04
+#define V_BRG_WR_SEL5		0x10
+#define V_BRG_RD_SEL5		0x40
+/* R_BRG_TIM_SEL67 */
+#define V_BRG_WR_SEL6		0x01
+#define V_BRG_RD_SEL6		0x04
+#define V_BRG_WR_SEL7		0x10
+#define V_BRG_RD_SEL7		0x40
+
+/* chapter 12: clock, reset, interrupt, timer and watchdog */
+/* R_IRQMSK_MISC */
+#define V_STA_IRQMSK		0x01
+#define V_TI_IRQMSK		0x02
+#define V_PROC_IRQMSK		0x04
+#define V_DTMF_IRQMSK		0x08
+#define V_IRQ1S_MSK		0x10
+#define V_SA6_IRQMSK		0x20
+#define V_RX_EOMF_MSK		0x40
+#define V_TX_EOMF_MSK		0x80
+/* R_IRQ_CTRL */
+#define V_FIFO_IRQ		0x01
+#define V_GLOB_IRQ_EN		0x08
+#define V_IRQ_POL		0x10
+/* R_TI_WD */
+#define V_EV_TS			0x01
+#define V_WD_TS			0x10
+/* A_IRQ_MSK */
+#define V_IRQ			0x01
+#define V_BERT_EN		0x02
+#define V_MIX_IRQ		0x04
+/* R_IRQ_OVIEW */
+#define V_IRQ_FIFO_BL0		0x01
+#define V_IRQ_FIFO_BL1		0x02
+#define V_IRQ_FIFO_BL2		0x04
+#define V_IRQ_FIFO_BL3		0x08
+#define V_IRQ_FIFO_BL4		0x10
+#define V_IRQ_FIFO_BL5		0x20
+#define V_IRQ_FIFO_BL6		0x40
+#define V_IRQ_FIFO_BL7		0x80
+/* R_IRQ_MISC */
+#define V_STA_IRQ		0x01
+#define V_TI_IRQ		0x02
+#define V_IRQ_PROC		0x04
+#define V_DTMF_IRQ		0x08
+#define V_IRQ1S			0x10
+#define V_SA6_IRQ		0x20
+#define V_RX_EOMF		0x40
+#define V_TX_EOMF		0x80
+/* R_STATUS */
+#define V_BUSY			0x01
+#define V_PROC			0x02
+#define V_DTMF_STA		0x04
+#define V_LOST_STA		0x08
+#define V_SYNC_IN		0x10
+#define V_EXT_IRQSTA		0x20
+#define V_MISC_IRQSTA		0x40
+#define V_FR_IRQSTA		0x80
+/* R_IRQ_FIFO_BL0 */
+#define V_IRQ_FIFO0_TX		0x01
+#define V_IRQ_FIFO0_RX		0x02
+#define V_IRQ_FIFO1_TX		0x04
+#define V_IRQ_FIFO1_RX		0x08
+#define V_IRQ_FIFO2_TX		0x10
+#define V_IRQ_FIFO2_RX		0x20
+#define V_IRQ_FIFO3_TX		0x40
+#define V_IRQ_FIFO3_RX		0x80
+/* R_IRQ_FIFO_BL1 */
+#define V_IRQ_FIFO4_TX		0x01
+#define V_IRQ_FIFO4_RX		0x02
+#define V_IRQ_FIFO5_TX		0x04
+#define V_IRQ_FIFO5_RX		0x08
+#define V_IRQ_FIFO6_TX		0x10
+#define V_IRQ_FIFO6_RX		0x20
+#define V_IRQ_FIFO7_TX		0x40
+#define V_IRQ_FIFO7_RX		0x80
+/* R_IRQ_FIFO_BL2 */
+#define V_IRQ_FIFO8_TX		0x01
+#define V_IRQ_FIFO8_RX		0x02
+#define V_IRQ_FIFO9_TX		0x04
+#define V_IRQ_FIFO9_RX		0x08
+#define V_IRQ_FIFO10_TX		0x10
+#define V_IRQ_FIFO10_RX		0x20
+#define V_IRQ_FIFO11_TX		0x40
+#define V_IRQ_FIFO11_RX		0x80
+/* R_IRQ_FIFO_BL3 */
+#define V_IRQ_FIFO12_TX		0x01
+#define V_IRQ_FIFO12_RX		0x02
+#define V_IRQ_FIFO13_TX		0x04
+#define V_IRQ_FIFO13_RX		0x08
+#define V_IRQ_FIFO14_TX		0x10
+#define V_IRQ_FIFO14_RX		0x20
+#define V_IRQ_FIFO15_TX		0x40
+#define V_IRQ_FIFO15_RX		0x80
+/* R_IRQ_FIFO_BL4 */
+#define V_IRQ_FIFO16_TX		0x01
+#define V_IRQ_FIFO16_RX		0x02
+#define V_IRQ_FIFO17_TX		0x04
+#define V_IRQ_FIFO17_RX		0x08
+#define V_IRQ_FIFO18_TX		0x10
+#define V_IRQ_FIFO18_RX		0x20
+#define V_IRQ_FIFO19_TX		0x40
+#define V_IRQ_FIFO19_RX		0x80
+/* R_IRQ_FIFO_BL5 */
+#define V_IRQ_FIFO20_TX		0x01
+#define V_IRQ_FIFO20_RX		0x02
+#define V_IRQ_FIFO21_TX		0x04
+#define V_IRQ_FIFO21_RX		0x08
+#define V_IRQ_FIFO22_TX		0x10
+#define V_IRQ_FIFO22_RX		0x20
+#define V_IRQ_FIFO23_TX		0x40
+#define V_IRQ_FIFO23_RX		0x80
+/* R_IRQ_FIFO_BL6 */
+#define V_IRQ_FIFO24_TX		0x01
+#define V_IRQ_FIFO24_RX		0x02
+#define V_IRQ_FIFO25_TX		0x04
+#define V_IRQ_FIFO25_RX		0x08
+#define V_IRQ_FIFO26_TX		0x10
+#define V_IRQ_FIFO26_RX		0x20
+#define V_IRQ_FIFO27_TX		0x40
+#define V_IRQ_FIFO27_RX		0x80
+/* R_IRQ_FIFO_BL7 */
+#define V_IRQ_FIFO28_TX		0x01
+#define V_IRQ_FIFO28_RX		0x02
+#define V_IRQ_FIFO29_TX		0x04
+#define V_IRQ_FIFO29_RX		0x08
+#define V_IRQ_FIFO30_TX		0x10
+#define V_IRQ_FIFO30_RX		0x20
+#define V_IRQ_FIFO31_TX		0x40
+#define V_IRQ_FIFO31_RX		0x80
+
+/* chapter 13: general purpose I/O pins (GPIO) and input pins (GPI) */
+/* R_GPIO_OUT0 */
+#define V_GPIO_OUT0		0x01
+#define V_GPIO_OUT1		0x02
+#define V_GPIO_OUT2		0x04
+#define V_GPIO_OUT3		0x08
+#define V_GPIO_OUT4		0x10
+#define V_GPIO_OUT5		0x20
+#define V_GPIO_OUT6		0x40
+#define V_GPIO_OUT7		0x80
+/* R_GPIO_OUT1 */
+#define V_GPIO_OUT8		0x01
+#define V_GPIO_OUT9		0x02
+#define V_GPIO_OUT10		0x04
+#define V_GPIO_OUT11		0x08
+#define V_GPIO_OUT12		0x10
+#define V_GPIO_OUT13		0x20
+#define V_GPIO_OUT14		0x40
+#define V_GPIO_OUT15		0x80
+/* R_GPIO_EN0 */
+#define V_GPIO_EN0		0x01
+#define V_GPIO_EN1		0x02
+#define V_GPIO_EN2		0x04
+#define V_GPIO_EN3		0x08
+#define V_GPIO_EN4		0x10
+#define V_GPIO_EN5		0x20
+#define V_GPIO_EN6		0x40
+#define V_GPIO_EN7		0x80
+/* R_GPIO_EN1 */
+#define V_GPIO_EN8		0x01
+#define V_GPIO_EN9		0x02
+#define V_GPIO_EN10		0x04
+#define V_GPIO_EN11		0x08
+#define V_GPIO_EN12		0x10
+#define V_GPIO_EN13		0x20
+#define V_GPIO_EN14		0x40
+#define V_GPIO_EN15		0x80
+/* R_GPIO_SEL */
+#define V_GPIO_SEL0		0x01
+#define V_GPIO_SEL1		0x02
+#define V_GPIO_SEL2		0x04
+#define V_GPIO_SEL3		0x08
+#define V_GPIO_SEL4		0x10
+#define V_GPIO_SEL5		0x20
+#define V_GPIO_SEL6		0x40
+#define V_GPIO_SEL7		0x80
+/* R_GPIO_IN0 */
+#define V_GPIO_IN0		0x01
+#define V_GPIO_IN1		0x02
+#define V_GPIO_IN2		0x04
+#define V_GPIO_IN3		0x08
+#define V_GPIO_IN4		0x10
+#define V_GPIO_IN5		0x20
+#define V_GPIO_IN6		0x40
+#define V_GPIO_IN7		0x80
+/* R_GPIO_IN1 */
+#define V_GPIO_IN8		0x01
+#define V_GPIO_IN9		0x02
+#define V_GPIO_IN10		0x04
+#define V_GPIO_IN11		0x08
+#define V_GPIO_IN12		0x10
+#define V_GPIO_IN13		0x20
+#define V_GPIO_IN14		0x40
+#define V_GPIO_IN15		0x80
+/* R_GPI_IN0 */
+#define V_GPI_IN0		0x01
+#define V_GPI_IN1		0x02
+#define V_GPI_IN2		0x04
+#define V_GPI_IN3		0x08
+#define V_GPI_IN4		0x10
+#define V_GPI_IN5		0x20
+#define V_GPI_IN6		0x40
+#define V_GPI_IN7		0x80
+/* R_GPI_IN1 */
+#define V_GPI_IN8		0x01
+#define V_GPI_IN9		0x02
+#define V_GPI_IN10		0x04
+#define V_GPI_IN11		0x08
+#define V_GPI_IN12		0x10
+#define V_GPI_IN13		0x20
+#define V_GPI_IN14		0x40
+#define V_GPI_IN15		0x80
+/* R_GPI_IN2 */
+#define V_GPI_IN16		0x01
+#define V_GPI_IN17		0x02
+#define V_GPI_IN18		0x04
+#define V_GPI_IN19		0x08
+#define V_GPI_IN20		0x10
+#define V_GPI_IN21		0x20
+#define V_GPI_IN22		0x40
+#define V_GPI_IN23		0x80
+/* R_GPI_IN3 */
+#define V_GPI_IN24		0x01
+#define V_GPI_IN25		0x02
+#define V_GPI_IN26		0x04
+#define V_GPI_IN27		0x08
+#define V_GPI_IN28		0x10
+#define V_GPI_IN29		0x20
+#define V_GPI_IN30		0x40
+#define V_GPI_IN31		0x80
+
+/* map of all registers, used for debugging */
+
+#ifdef HFC_REGISTER_MAP
+struct hfc_register_names {
+	char *name;
+	u_char reg;
+} hfc_register_names[] = {
+	/* write registers */
+	{"R_CIRM",		0x00},
+	{"R_CTRL",		0x01},
+	{"R_BRG_PCM_CFG ",	0x02},
+	{"R_RAM_ADDR0",		0x08},
+	{"R_RAM_ADDR1",		0x09},
+	{"R_RAM_ADDR2",		0x0A},
+	{"R_FIRST_FIFO",	0x0B},
+	{"R_RAM_SZ",		0x0C},
+	{"R_FIFO_MD",		0x0D},
+	{"R_INC_RES_FIFO",	0x0E},
+	{"R_FIFO / R_FSM_IDX",	0x0F},
+	{"R_SLOT",		0x10},
+	{"R_IRQMSK_MISC",	0x11},
+	{"R_SCI_MSK",		0x12},
+	{"R_IRQ_CTRL",		0x13},
+	{"R_PCM_MD0",		0x14},
+	{"R_0x15",		0x15},
+	{"R_ST_SEL",		0x16},
+	{"R_ST_SYNC",		0x17},
+	{"R_CONF_EN",		0x18},
+	{"R_TI_WD",		0x1A},
+	{"R_BERT_WD_MD",	0x1B},
+	{"R_DTMF",		0x1C},
+	{"R_DTMF_N",		0x1D},
+	{"R_E1_XX_STA",		0x20},
+	{"R_LOS0",		0x22},
+	{"R_LOS1",		0x23},
+	{"R_RX0",		0x24},
+	{"R_RX_FR0",		0x25},
+	{"R_RX_FR1",		0x26},
+	{"R_TX0",		0x28},
+	{"R_TX1",		0x29},
+	{"R_TX_FR0",		0x2C},
+	{"R_TX_FR1",		0x2D},
+	{"R_TX_FR2",		0x2E},
+	{"R_JATT_ATT",		0x2F},
+	{"A_ST_xx_STA/R_RX_OFF",0x30},
+	{"A_ST_CTRL0",		0x31},
+	{"R_SYNC_OUT",		0x31},
+	{"A_ST_CTRL1",		0x32},
+	{"A_ST_CTRL2",		0x33},
+	{"A_ST_SQ_WR",		0x34},
+	{"R_TX_OFF",		0x34},
+	{"R_SYNC_CTRL",		0x35},
+	{"A_ST_CLK_DLY",	0x37},
+	{"R_PWM0",		0x38},
+	{"R_PWM1",		0x39},
+	{"A_ST_B1_TX",		0x3C},
+	{"A_ST_B2_TX",		0x3D},
+	{"A_ST_D_TX",		0x3E},
+	{"R_GPIO_OUT0",		0x40},
+	{"R_GPIO_OUT1",		0x41},
+	{"R_GPIO_EN0",		0x42},
+	{"R_GPIO_EN1",		0x43},
+	{"R_GPIO_SEL",		0x44},
+	{"R_BRG_CTRL",		0x45},
+	{"R_PWM_MD",		0x46},
+	{"R_BRG_MD",		0x47},
+	{"R_BRG_TIM0",		0x48},
+	{"R_BRG_TIM1",		0x49},
+	{"R_BRG_TIM2",		0x4A},
+	{"R_BRG_TIM3",		0x4B},
+	{"R_BRG_TIM_SEL01",	0x4C},
+	{"R_BRG_TIM_SEL23",	0x4D},
+	{"R_BRG_TIM_SEL45",	0x4E},
+	{"R_BRG_TIM_SEL67",	0x4F},
+	{"A_FIFO_DATA0-2",	0x80},
+	{"A_FIFO_DATA0-2_NOINC",0x84},
+	{"R_RAM_DATA",		0xC0},
+	{"A_SL_CFG",		0xD0},
+	{"A_CONF",		0xD1},
+	{"A_CH_MSK",		0xF4},
+	{"A_CON_HDLC",		0xFA},
+	{"A_SUBCH_CFG",		0xFB},
+	{"A_CHANNEL",		0xFC},
+	{"A_FIFO_SEQ",		0xFD},
+	{"A_IRQ_MSK",		0xFF},
+	{NULL, 0},
+
+	/* read registers */
+	{"A_Z1",		0x04},
+	{"A_Z1H",		0x05},
+	{"A_Z2",		0x06},
+	{"A_Z2H",		0x07},
+	{"A_F1",		0x0C},
+	{"A_F2",		0x0D},
+	{"R_IRQ_OVIEW",		0x10},
+	{"R_IRQ_MISC",		0x11},
+	{"R_IRQ_STATECH",	0x12},
+	{"R_CONF_OFLOW",	0x14},
+	{"R_RAM_USE",		0x15},
+	{"R_CHIP_ID",		0x16},
+	{"R_BERT_STA",		0x17},
+	{"R_F0_CNTL",		0x18},
+	{"R_F0_CNTH",		0x19},
+	{"R_BERT_ECL",		0x1A},
+	{"R_BERT_ECH",		0x1B},
+	{"R_STATUS",		0x1C},
+	{"R_CHIP_RV",		0x1F},
+	{"R_STATE",		0x20},
+	{"R_RX_STA0",		0x24},
+	{"R_RX_STA1",		0x25},
+	{"R_RX_STA2",		0x26},
+	{"R_RX_STA3",		0x27},
+	{"R_JATT_DIR",		0x2b},
+	{"R_SLIP",		0x2c},
+	{"A_ST_RD_STA",		0x30},
+	{"R_FAS_ECL",		0x30},
+	{"R_FAS_ECH",		0x31},
+	{"R_VIO_ECL",		0x32},
+	{"R_VIO_ECH",		0x33},
+	{"R_CRC_ECL / A_ST_SQ_RD",0x34},
+	{"R_CRC_ECH",		0x35},
+	{"R_E_ECL",		0x36},
+	{"R_E_ECH",		0x37},
+	{"R_SA6_SA13_ECL",	0x38},
+	{"R_SA6_SA13_ECH",	0x39},
+	{"R_SA6_SA23_ECL",	0x3A},
+	{"R_SA6_SA23_ECH",	0x3B},
+	{"A_ST_B1_RX",		0x3C},
+	{"A_ST_B2_RX",		0x3D},
+	{"A_ST_D_RX",		0x3E},
+	{"A_ST_E_RX",		0x3F},
+	{"R_GPIO_IN0",		0x40},
+	{"R_GPIO_IN1",		0x41},
+	{"R_GPI_IN0",		0x44},
+	{"R_GPI_IN1",		0x45},
+	{"R_GPI_IN2",		0x46},
+	{"R_GPI_IN3",		0x47},
+	{"A_FIFO_DATA0-2",	0x80},
+	{"A_FIFO_DATA0-2_NOINC",0x84},
+	{"R_INT_DATA",		0x88},
+	{"R_RAM_DATA",		0xC0},
+	{"R_IRQ_FIFO_BL0",	0xC8},
+	{"R_IRQ_FIFO_BL1",	0xC9},
+	{"R_IRQ_FIFO_BL2",	0xCA},
+	{"R_IRQ_FIFO_BL3",	0xCB},
+	{"R_IRQ_FIFO_BL4",	0xCC},
+	{"R_IRQ_FIFO_BL5",	0xCD},
+	{"R_IRQ_FIFO_BL6",	0xCE},
+	{"R_IRQ_FIFO_BL7",	0xCF},
+};
+#endif /* HFC_REGISTER_MAP */
+
+/* ACCESS TO PCI MEMORY MAPPED REGISTERS */
+
+#define ADDR_MULT 1   // can be defined to other values if there
+					  // is e.g. an offset in a bridge chip addressing
+
+#ifdef CONFIG_HFCMULTI_PCIMEM
+
+#define HFC_outl(a,b,c) (*((volatile u_long *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
+#define HFC_inl(a,b) (*((volatile u_long *)((a->pci_membase)+((b)*ADDR_MULT))))
+#define HFC_outl_(a,b,c) (*((volatile u_long *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
+#define HFC_inl_(a,b) (*((volatile u_long *)((a->pci_membase)+((b)*ADDR_MULT))))
+#define HFC_outw_(a,b,c) (*((volatile u_short *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
+#define HFC_inw_(a,b) (*((volatile u_short *)((a->pci_membase)+((b)*ADDR_MULT))))
+/*
+// version of HFC_inw_(a,b) that makes 8bit access instead of 16bit
+// only for test purposes
+u_short HFC_inw_(hfc_multi_t *a, int b)
+{
+	u_short zl,zh;
+
+	zl=(*((volatile u_char *)((a->pci_membase)+(b*4))));
+	zh=(*((volatile u_char *)((a->pci_membase)+((b+1)*4))));
+	return(zl|(zh<<8));
+
+}
+*/
+
+#define HFC_outb_(a,b,c) (*((volatile u_char *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
+#define HFC_inb_(a,b) (*((volatile u_char *)((a->pci_membase)+((b)*ADDR_MULT))))
+#define HFC_wait_(a) while((*((volatile u_char *)((a->pci_membase)+(R_STATUS*ADDR_MULT)))) & V_BUSY)
+
+
+
+/* macros */
+#ifndef HFC_REGISTER_MAP
+
+/* usage: HFC_outX(card,register,value); */
+#define HFC_outb(a,b,c) (*((volatile u_char *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
+#define HFC_outw(a,b,c) (*((volatile u_short *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
+/* usage: register=HFC_inX(card,register); */
+#define HFC_inb(a,b) (*((volatile u_char *)((a->pci_membase)+((b)*ADDR_MULT))))
+#define HFC_inw(a,b) (*((volatile u_short *)((a->pci_membase)+((b)*ADDR_MULT))))
+/* usage: HFC_wait(card); */
+#define HFC_wait(a) while((*((volatile u_char *)((a->pci_membase)+(R_STATUS*ADDR_MULT)))) & V_BUSY)
+
+#else /* HFC_REGISTER_MAP */
+
+#define HFC_outb(a,b,c) _HFC_outb(a, b, c, __FUNCTION__, __LINE__)
+static BYTE _HFC_outb(hfc_multi_t *a, BYTE b, BYTE c, char *function, int line)
+{
+	char regname[256]="", bits[9]="xxxxxxxx";
+	int i;
+
+	i = -1;
+	while(hfc_register_names[++i].name) {
+		if (hfc_register_names[i].reg == b)
+			strcat(regname, hfc_register_names[i].name);
+	}
+	if (regname[0] == '\0')
+		strcpy(regname, "register");
+
+	bits[7] = '0'+(!!(c&1));
+	bits[6] = '0'+(!!(c&2));
+	bits[5] = '0'+(!!(c&4));
+	bits[4] = '0'+(!!(c&8));
+	bits[3] = '0'+(!!(c&16));
+	bits[2] = '0'+(!!(c&32));
+	bits[1] = '0'+(!!(c&64));
+	bits[0] = '0'+(!!(c&128));
+	printk(KERN_DEBUG "HFC_outb(\"%s\", %02x=%s, 0x%02x=%s); in %s() line %d\n", a->name, b, regname, c, bits, function, line);
+	return(*(((volatile u_char *)a->pci_membase)+b) = c);
+}
+#define HFC_inb(a,b) _HFC_inb(a, b, __FUNCTION__, __LINE__)
+static BYTE _HFC_inb(hfc_multi_t *a, BYTE b, char *function, int line)
+{
+	char regname[256]="", bits[9]="xxxxxxxx";
+	u_char c = (*(((volatile u_char *)a->pci_membase)+((b)*ADDR_MULT));
+	int i;
+
+	i = 0;
+	while(hfc_register_names[i++].name)
+		;
+	while(hfc_register_names[++i].name) {
+		if (hfc_register_names[i].reg == b)
+			strcat(regname, hfc_register_names[i].name);
+	}
+	if (regname[0] == '\0')
+		strcpy(regname, "register");
+
+	bits[7] = '0'+(!!(c&1));
+	bits[6] = '0'+(!!(c&2));
+	bits[5] = '0'+(!!(c&4));
+	bits[4] = '0'+(!!(c&8));
+	bits[3] = '0'+(!!(c&16));
+	bits[2] = '0'+(!!(c&32));
+	bits[1] = '0'+(!!(c&64));
+	bits[0] = '0'+(!!(c&128));
+	printk(KERN_DEBUG "HFC_inb(\"%s\", %02x=%s) = 0x%02x=%s; in %s() line %d\n", a->name, b, regname, c, bits, function, line);
+	return(c);
+}
+#define HFC_inw(a,b) _HFC_inw(a, b, __FUNCTION__, __LINE__)
+static WORD _HFC_inw(hfc_multi_t *a, BYTE b, char *function, int line)
+{
+	char regname[256]="";
+	u_short c = (*(((volatile u_short *)a->pci_membase)+((b)*ADDR_MULT)));
+	int i;
+
+	i = 0;
+	while(hfc_register_names[i++].name)
+		;
+	while(hfc_register_names[++i].name) {
+		if (hfc_register_names[i].reg == b)
+			strcat(regname, hfc_register_names[i].name);
+	}
+	if (regname[0] == '\0')
+		strcpy(regname, "register");
+
+	printk(KERN_DEBUG "HFC_inw(\"%s\", %02x=%s) = 0x%04x; in %s() line %d\n", a->name, b, regname, c, function, line);
+	return(c);
+}
+#define HFC_wait(a) _HFC_wait(a, __FUNCTION__, __LINE__)
+static void _HFC_wait(hfc_multi_t *a, char *function, int line)
+{
+	printk(KERN_DEBUG "HFC_wait(\"%s\"); in %s() line %d\n", a->name, function, line);
+	while((*(((volatile u_char *)a->pci_membase)+R_STATUS)) & V_BUSY);
+}
+
+#endif /* else HFC_REGISTER_MAP */
+
+#else /* CONFIG_HFCMULTI_PCIMEM */
+
+/* ACCESS TO PCI IO REGISTERS */
+
+#ifdef HFC_REGISTER_MAP
+#error Please use "HFC_REGISTER_MAP" debugging only in conjuction with PCIMEM access.
+#endif
+
+/* usage: HFC_outX(card,register,value); */
+static inline void HFC_outb(hfc_multi_t *a, unsigned short b, u_char c)
+{
+	outw(b,(a->pci_iobase)+4);
+	outb(c,a->pci_iobase);
+}
+static inline void HFC_outl(hfc_multi_t *a, unsigned short b, u_long c)
+{
+	outw(b,(a->pci_iobase)+4);
+	outl(c,a->pci_iobase);
+}
+
+static inline void HFC_outw(hfc_multi_t *a, unsigned short b, u_long c)
+{
+	outw(b,(a->pci_iobase)+4);
+	outw(c,a->pci_iobase);
+}
+
+/* usage: value=HFC_inX(card,register); */
+static inline u_char HFC_inb(hfc_multi_t *a, unsigned short b)
+{
+	outw(b,(a->pci_iobase)+4);
+	return (inb((volatile u_int)a->pci_iobase));
+}
+static inline u_short HFC_inw(hfc_multi_t *a, unsigned short b)
+{
+	outw(b,(a->pci_iobase)+4);
+	return (inw((volatile u_int)a->pci_iobase));
+}
+static inline u_long HFC_inl(hfc_multi_t *a, unsigned short b)
+{
+	outw(b,(a->pci_iobase)+4);
+	return (inl((volatile u_int)a->pci_iobase));
+}
+
+/* usage: HFC_wait(card); */
+static inline void HFC_wait(hfc_multi_t *a)
+{
+	outb(R_STATUS,(a->pci_iobase)+4);
+	while(inb((volatile u_int)a->pci_iobase) & V_BUSY);
+}
+
+/* usage: HFC_set(card,register); */
+#define HFC_set(a, b) outb(b,(a->pci_iobase)+4)
+
+/* usage: HFC_putX(card,value); */
+#define HFC_putb(a,b) outb(b,a->pci_iobase)
+#define HFC_putl(a,b) outl(b,a->pci_iobase)
+#define HFC_putw(a,b) outw(b,a->pci_iobase)
+
+/* usage: value=HFC_getX(card); */
+#define HFC_getb(a) inb((volatile u_int)a->pci_iobase)
+#define HFC_getl(a) inl((volatile u_int)a->pci_iobase)
+#define HFC_getw(a) inw((volatile u_int)a->pci_iobase)
+
+/* no debug */
+#define HFC_outl_(a,b,c) HFC_outl(a,b,c)
+#define HFC_inl_(a,b) HFC_inl(a,b)
+#define HFC_inw_(a,b) HFC_inw(a,b)
+#define HFC_outb_(a,b,c) HFC_outb(a,b,c)
+#define HFC_inb_(a,b) HFC_inb(a,b)
+#define HFC_wait_(a) HFC_wait(a)
+
+#endif /* else CONFIG_HFCMULTI_PCIMEM */
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_pci.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_pci.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_pci.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,2297 @@
+/* $Id: hfc_pci.c,v 1.49 2006/12/21 15:25:06 nadi Exp $
+
+ * hfc_pci.c     low level driver for CCD's hfc-pci based cards
+ *
+ * Author     Werner Cornelius (werner at isdn4linux.de)
+ *            based on existing driver for CCD hfc ISA cards
+ *            type approval valid for HFC-S PCI A based card 
+ *
+ * Copyright 1999  by Werner Cornelius (werner at isdn-development.de)
+ * Copyright 2001  by Karsten Keil (keil at 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "core.h"
+#include "channel.h"
+#include "hfc_pci.h"
+#include "layer1.h"
+#include "debug.h"
+#include <linux/isdn_compat.h>
+
+#define HFC_INFO(txt)	printk(KERN_DEBUG txt)
+
+extern const char *CardType[];
+
+static const char *hfcpci_revision = "$Revision: 1.49 $";
+
+/* table entry in the PCI devices list */
+typedef struct {
+	int vendor_id;
+	int device_id;
+	char *vendor_name;
+	char *card_name;
+} PCI_ENTRY;
+
+#define NT_T1_COUNT	20	/* number of 3.125ms interrupts for G2 timeout */
+#define CLKDEL_TE	0x0e	/* CLKDEL in TE mode */
+#define CLKDEL_NT	0x6c	/* CLKDEL in NT mode */
+
+#ifndef PCI_VENDOR_ID_CCD
+#define PCI_VENDOR_ID_CCD		0x1397
+#define PCI_DEVICE_ID_CCD_2BD0		0x2BD0
+#define PCI_DEVICE_ID_CCD_B000		0xB000
+#define PCI_DEVICE_ID_CCD_B006		0xB006
+#define PCI_DEVICE_ID_CCD_B007		0xB007
+#define PCI_DEVICE_ID_CCD_B008		0xB008
+#define PCI_DEVICE_ID_CCD_B009		0xB009
+#define PCI_DEVICE_ID_CCD_B00A		0xB00A
+#define PCI_DEVICE_ID_CCD_B00B		0xB00B
+#define PCI_DEVICE_ID_CCD_B00C		0xB00C
+#define PCI_DEVICE_ID_CCD_B100		0xB100
+
+#define PCI_VENDOR_ID_ASUSTEK		0x1043
+#define PCI_DEVICE_ID_ASUSTEK_0675	0x0675
+
+#define PCI_VENDOR_ID_BERKOM		0x0871
+#define PCI_DEVICE_ID_BERKOM_A1T	0xFFA1
+#define PCI_DEVICE_ID_BERKOM_T_CONCEPT	0xFFA2
+
+#define PCI_VENDOR_ID_ANIGMA		0x1051
+#define PCI_DEVICE_ID_ANIGMA_MC145575	0x0100
+
+#define PCI_VENDOR_ID_ZOLTRIX		0x15b0
+#define PCI_DEVICE_ID_ZOLTRIX_2BD0	0x2BD0
+
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E	0x0070
+#define PCI_DEVICE_ID_DIGI_DF_M_E	0x0071
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A	0x0072
+#define PCI_DEVICE_ID_DIGI_DF_M_A	0x0073
+
+#define PCI_VENDOR_ID_ABOCOM		0x13D1
+#define PCI_DEVICE_ID_ABOCOM_2BD1	0x2BD1
+#endif
+
+#ifndef PCI_VENDOR_ID_SITECOM
+#define PCI_VENDOR_ID_SITECOM		0x182D
+#define PCI_DEVICE_ID_SITECOM_DC105V2	0x3069
+#endif
+
+/* new device IDs, obsolete when include/linux/pci_ids.h will be updated */
+#ifndef PCI_DEVICE_ID_CCD_B700
+#define PCI_DEVICE_ID_CCD_B700		0xb700
+#endif
+#ifndef PCI_DEVICE_ID_CCD_B701
+#define PCI_DEVICE_ID_CCD_B701          0xb701
+#endif
+
+ 
+static const PCI_ENTRY id_list[] =
+{
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, "Billion", "B000"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, "Billion", "B006"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, "Billion", "B007"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, "Billion", "B008"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, "Billion", "B009"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, "Billion", "B00A"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B700, "Primux II S0", "B700"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B701, "Primux II S0 NT", "B701"},
+	{PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"},
+	{PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"},
+	{PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"},
+	{PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, "German telekom", "A1T"},
+	{PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, "Motorola MC145575", "MC145575"},
+	{PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, "Zoltrix", "2BD0"},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,"Digi International", "Digi DataFire Micro V (Europe)"},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,"Digi International", "Digi DataFire Micro V IOM2 (North America)"},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,"Digi International", "Digi DataFire Micro V (North America)"},
+	{PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2,"Sitecom Connectivity", "DC-105 ISDN TA"},
+	{0, 0, NULL, NULL},
+};
+
+
+struct hfcPCI_hw {
+	unsigned char		cirm;
+	unsigned char		ctmt;
+	unsigned char		clkdel;
+	unsigned char		states;
+	unsigned char		conn;
+	unsigned char		mst_m;
+	unsigned char		int_m1;
+	unsigned char		int_m2;
+	unsigned char		sctrl;
+	unsigned char		sctrl_r;
+	unsigned char		sctrl_e;
+	unsigned char		trm;
+	unsigned char		fifo_en;
+	unsigned char		bswapped;
+	unsigned char		nt_mode;
+	int			nt_timer;
+	struct pci_dev		*dev;
+	unsigned char		*pci_io; /* start of PCI IO memory */
+	dma_addr_t		dmahandle;
+	void			*fifos; /* FIFO memory */ 
+	int			last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
+	struct timer_list	timer;
+};
+
+typedef struct hfcPCI_hw	hfcPCI_hw_t;
+
+#define SPIN_DEBUG
+#define	HFC_CFG_MASTER		1
+#define HFC_CFG_SLAVE		2
+#define	HFC_CFG_PCM		3
+#define HFC_CFG_2HFC		4
+#define HFC_CFG_SLAVEHFC	5
+#define HFC_CFG_NEG_F0		6
+#define HFC_CFG_SW_DD_DU	7
+
+typedef struct _hfc_pci {
+	struct list_head	list;
+	u_char			subtyp;
+	u_char			chanlimit;
+	u_long			cfg;
+	u_int			irq;
+	u_int			irqcnt;
+	hfcPCI_hw_t		hw;
+	spinlock_t		lock;
+	channel_t		dch;
+	channel_t		bch[2];
+} hfc_pci_t;
+
+/* Interface functions */
+static void
+enable_hwirq(hfc_pci_t *hc)
+{
+	hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE;
+	Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
+}
+
+static void
+disable_hwirq(hfc_pci_t *hc)
+{
+	hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE);
+	Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
+}
+
+/******************************************/
+/* free hardware resources used by driver */
+/******************************************/
+void
+release_io_hfcpci(hfc_pci_t *hc)
+{
+	hc->hw.int_m2 = 0; /* interrupt output off ! */
+	disable_hwirq(hc);
+	Write_hfc(hc, HFCPCI_CIRM, HFCPCI_RESET);		/* Reset On */
+	mdelay(10);						/* Timeout 10ms */
+	hc->hw.cirm = 0; /* Reset Off */
+	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
+	pci_write_config_word(hc->hw.dev, PCI_COMMAND, 0);	/* disable memory mapped ports + busmaster */
+	del_timer(&hc->hw.timer);
+	pci_free_consistent(hc->hw.dev, 0x8000, hc->hw.fifos, hc->hw.dmahandle);
+	iounmap((void *)hc->hw.pci_io);
+}
+
+
+/********************************************************************************/
+/* function called to reset the HFC PCI chip. A complete software reset of chip */
+/* and fifos is done.                                                           */
+/********************************************************************************/
+static void
+reset_hfcpci(hfc_pci_t *hc)
+{
+	u_char	val;
+	int	cnt = 0;
+
+	HFC_INFO("reset_hfcpci: entered\n");
+	val = Read_hfc(hc, HFCPCI_CHIP_ID);
+	printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val);
+	pci_write_config_word(hc->hw.dev, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */
+	disable_hwirq(hc);
+	pci_write_config_word(hc->hw.dev, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER);	/* enable memory ports + busmaster */
+	val = Read_hfc(hc, HFCPCI_STATUS);
+	printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val);
+	hc->hw.cirm = HFCPCI_RESET;	/* Reset On */
+	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	mdelay(10);			/* Timeout 10ms */
+	hc->hw.cirm = 0;		/* Reset Off */
+	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
+	val = Read_hfc(hc, HFCPCI_STATUS);
+	printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val);
+	while (cnt < 50000) { /* max 50000 us */
+ 		udelay(5);
+		cnt += 5;
+		val = Read_hfc(hc, HFCPCI_STATUS);
+		if (!(val & 2))
+			break;
+	}
+	printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt);
+
+	hc->hw.fifo_en = 0x30;	/* only D fifos enabled */
+
+	hc->hw.bswapped = 0;	/* no exchange */
+	hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
+	hc->hw.trm = HFCPCI_BTRANS_THRESMASK;	/* no echo connect , threshold */
+	hc->hw.sctrl = 0x40;	/* set tx_lo mode, error in datasheet ! */
+	hc->hw.sctrl_r = 0;
+	hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE;	/* S/T Auto awake */
+	hc->hw.mst_m = 0;
+	if (test_bit(HFC_CFG_MASTER, &hc->cfg))
+		hc->hw.mst_m |= HFCPCI_MASTER;	/* HFC Master Mode */
+	if (test_bit(HFC_CFG_NEG_F0, &hc->cfg))
+		hc->hw.mst_m |= HFCPCI_F0_NEGATIV;
+	if (hc->hw.nt_mode) {
+		hc->hw.clkdel = CLKDEL_NT;	/* ST-Bit delay for NT-Mode */
+		hc->hw.sctrl |= SCTRL_MODE_NT;	/* NT-MODE */
+		hc->hw.states = 1;		/* G1 */
+	} else {
+		hc->hw.clkdel = CLKDEL_TE;	/* ST-Bit delay for TE-Mode */
+		hc->hw.states = 2;		/* F2 */
+	}
+	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
+	Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
+	Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel);
+	Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
+	Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
+
+	hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
+	    HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;
+	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
+
+	/* Clear already pending ints */
+	if (Read_hfc(hc, HFCPCI_INT_S1));
+
+	Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states);
+	udelay(10);
+	Write_hfc(hc, HFCPCI_STATES, hc->hw.states);
+
+	Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
+	Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
+	Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.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 */
+	if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
+		/* set data flow directions: connect B1,B2: HFC to/from PCM */
+		hc->hw.conn = 0x09;
+	} else {
+		hc->hw.conn = 0x36;	/* set data flow directions */ 
+		if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) {
+			Write_hfc(hc, HFCPCI_B1_SSL, 0xC0);
+			Write_hfc(hc, HFCPCI_B2_SSL, 0xC1);
+			Write_hfc(hc, HFCPCI_B1_RSL, 0xC0);
+			Write_hfc(hc, HFCPCI_B2_RSL, 0xC1);
+		} else {
+			Write_hfc(hc, HFCPCI_B1_SSL, 0x80);
+			Write_hfc(hc, HFCPCI_B2_SSL, 0x81);
+			Write_hfc(hc, HFCPCI_B1_RSL, 0x80);
+			Write_hfc(hc, HFCPCI_B2_RSL, 0x81);
+		}
+	}
+	Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
+	val = Read_hfc(hc, HFCPCI_INT_S2);
+}
+
+/***************************************************/
+/* Timer function called when kernel timer expires */
+/***************************************************/
+static void
+hfcpci_Timer(hfc_pci_t *hc)
+{
+	hc->hw.timer.expires = jiffies + 75;
+	/* WD RESET */
+/*      WriteReg(hc, HFCD_DATA, HFCD_CTMT, hc->hw.ctmt | 0x80);
+   add_timer(&hc->hw.timer);
+ */
+}
+
+
+/************************************************/
+/* select a b-channel entry matching and active */
+/************************************************/
+static channel_t *
+Sel_BCS(hfc_pci_t *hc, int channel)
+{
+	if (test_bit(FLG_ACTIVE, &hc->bch[0].Flags) &&
+		(hc->bch[0].channel & channel))
+		return (&hc->bch[0]);
+	else if (test_bit(FLG_ACTIVE, &hc->bch[1].Flags) &&
+		(hc->bch[1].channel & channel))
+		return (&hc->bch[1]);
+	else
+		return (NULL);
+}
+
+/***************************************/
+/* clear the desired B-channel rx fifo */
+/***************************************/
+static void hfcpci_clear_fifo_rx(hfc_pci_t *hc, int fifo)
+{       u_char fifo_state;
+        bzfifo_type *bzr;
+
+	if (fifo) {
+	        bzr = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b2;
+		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2RX;
+	} else {
+	        bzr = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b1;
+		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1RX;
+	}
+	if (fifo_state)
+	        hc->hw.fifo_en ^= fifo_state;
+	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
+	hc->hw.last_bfifo_cnt[fifo] = 0;
+	bzr->f1 = MAX_B_FRAMES;
+	bzr->f2 = bzr->f1;	/* init F pointers to remain constant */
+	bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
+	bzr->za[MAX_B_FRAMES].z2 = cpu_to_le16(le16_to_cpu(bzr->za[MAX_B_FRAMES].z1));
+	if (fifo_state)
+	        hc->hw.fifo_en |= fifo_state;
+	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
+}   
+
+/***************************************/
+/* clear the desired B-channel tx fifo */
+/***************************************/
+static void hfcpci_clear_fifo_tx(hfc_pci_t *hc, int fifo)
+{       u_char fifo_state;
+        bzfifo_type *bzt;
+
+	if (fifo) {
+	        bzt = &((fifo_area *) (hc->hw.fifos))->b_chans.txbz_b2;
+		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2TX;
+	} else {
+	        bzt = &((fifo_area *) (hc->hw.fifos))->b_chans.txbz_b1;
+		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1TX;
+	}
+	if (fifo_state)
+	        hc->hw.fifo_en ^= fifo_state;
+	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
+	if (hc->bch[fifo].debug & L1_DEB_HSCX)
+		mISDN_debugprint(&hc->bch[fifo].inst,
+				"hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x) state(%x)",
+				fifo, bzt->f1, bzt->f2,
+				le16_to_cpu(bzt->za[MAX_B_FRAMES].z1),
+				le16_to_cpu(bzt->za[MAX_B_FRAMES].z2),
+				fifo_state);
+	bzt->f2 = MAX_B_FRAMES;
+	bzt->f1 = bzt->f2;	/* init F pointers to remain constant */
+	bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
+	bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16(le16_to_cpu(bzt->za[MAX_B_FRAMES].z1 - 1));
+	if (fifo_state)
+	        hc->hw.fifo_en |= fifo_state;
+	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
+	if (hc->bch[fifo].debug & L1_DEB_HSCX)
+		mISDN_debugprint(&hc->bch[fifo].inst,
+				"hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x)",
+				fifo, bzt->f1, bzt->f2,
+				le16_to_cpu(bzt->za[MAX_B_FRAMES].z1),
+				le16_to_cpu(bzt->za[MAX_B_FRAMES].z2));
+}   
+
+/*********************************************/
+/* read a complete B-frame out of the buffer */
+/*********************************************/
+static void
+hfcpci_empty_fifo(channel_t *bch, bzfifo_type * bz, u_char * bdata, int count)
+{
+	u_char		*ptr, *ptr1, new_f2;
+	int		total, maxlen, new_z2;
+	z_type		*zp;
+
+	if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
+		mISDN_debugprint(&bch->inst, "hfcpci_empty_fifo");
+	zp = &bz->za[bz->f2];	/* point to Z-Regs */
+	new_z2 = le16_to_cpu(zp->z2) + count;	/* new position in fifo */
+	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
+		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
+	new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
+	if ((count > MAX_DATA_SIZE + 3) || (count < 4) ||
+	    (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) {
+		if (bch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&bch->inst, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count);
+#ifdef ERROR_STATISTIC
+		bch->err_inv++;
+#endif
+		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
+		bz->f2 = new_f2;	/* next buffer */
+	} else if (!(bch->rx_skb = alloc_stack_skb(count - 3, bch->up_headerlen)))
+		printk(KERN_WARNING "HFCPCI: receive out of memory\n");
+	else {
+		total = count;
+		count -= 3;
+		ptr = skb_put(bch->rx_skb, count);
+
+		if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL)
+			maxlen = count;		/* complete transfer */
+		else
+			maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(zp->z2);	/* maximum */
+
+		ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL);	/* start of data */
+		memcpy(ptr, ptr1, maxlen);	/* copy data */
+		count -= maxlen;
+
+		if (count) {	/* rest remaining */
+			ptr += maxlen;
+			ptr1 = bdata;	/* start of buffer */
+			memcpy(ptr, ptr1, count);	/* rest */
+		}
+		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
+		bz->f2 = new_f2;	/* next buffer */
+		queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, bch->rx_skb);
+		bch->rx_skb = NULL;
+	}
+}
+
+/*******************************/
+/* D-channel receive procedure */
+/*******************************/
+static
+int
+receive_dmsg(hfc_pci_t *hc)
+{
+	channel_t	*dch = &hc->dch;
+	int		maxlen;
+	int		rcnt, total;
+	int		count = 5;
+	u_char		*ptr, *ptr1;
+	dfifo_type	*df;
+	z_type		*zp;
+
+	df = &((fifo_area *) (hc->hw.fifos))->d_chan.d_rx;
+	while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {
+		zp = &df->za[df->f2 & D_FREG_MASK];
+		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
+		if (rcnt < 0)
+			rcnt += D_FIFO_SIZE;
+		rcnt++;
+		if (dch->debug & L1_DEB_ISAC)
+			mISDN_debugprint(&dch->inst, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",
+				df->f1, df->f2,
+				le16_to_cpu(zp->z1),
+				le16_to_cpu(zp->z2),
+				rcnt);
+
+		if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) ||
+		    (df->data[le16_to_cpu(zp->z1)])) {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst,
+						"empty_fifo hfcpci paket inv. len %d or crc %d",
+						rcnt,
+						df->data[le16_to_cpu(zp->z1)]);
+#ifdef ERROR_STATISTIC
+			cs->err_rx++;
+#endif
+			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1);	/* next buffer */
+			df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((zp->z2 + rcnt) & (D_FIFO_SIZE - 1));
+		} else if ((dch->rx_skb = alloc_stack_skb(rcnt - 3, dch->up_headerlen))) {
+			total = rcnt;
+			rcnt -= 3;
+			ptr = skb_put(dch->rx_skb, rcnt);
+
+			if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE)
+				maxlen = rcnt;	/* complete transfer */
+			else
+				maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2);	/* maximum */
+
+			ptr1 = df->data + le16_to_cpu(zp->z2);	/* start of data */
+			memcpy(ptr, ptr1, maxlen);	/* copy data */
+			rcnt -= maxlen;
+
+			if (rcnt) {	/* rest remaining */
+				ptr += maxlen;
+				ptr1 = df->data;	/* start of buffer */
+				memcpy(ptr, ptr1, rcnt);	/* rest */
+			}
+			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1);	/* next buffer */
+			df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1));
+
+			if (dch->debug & L1_DEB_ISAC_FIFO) {
+				char *t = dch->log;
+
+				count = dch->rx_skb->len;
+				ptr = dch->rx_skb->data;
+				t += sprintf(t, "hfcD_empty_fifo cnt %d", count);
+				mISDN_QuickHex(t, ptr, count);
+				mISDN_debugprint(&dch->inst, dch->log);
+			}
+			mISDN_queueup_newhead(&dch->inst, 0, PH_DATA_IND, MISDN_ID_ANY, dch->rx_skb);
+			dch->rx_skb = NULL;
+		} else
+			printk(KERN_WARNING "HFC-PCI: D receive out of memory\n");
+	}
+	return (1);
+}
+
+/*******************************************************************************/
+/* check for transparent receive data and read max one threshold size if avail */
+/*******************************************************************************/
+int
+hfcpci_empty_fifo_trans(channel_t *bch, bzfifo_type * bz, u_char * bdata)
+{
+	unsigned short	*z1r, *z2r;
+	int		new_z2, fcnt, maxlen;
+	u_char		*ptr, *ptr1;
+
+	z1r = &bz->za[MAX_B_FRAMES].z1;		/* pointer to z reg */
+	z2r = z1r + 1;
+
+	if (!(fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r)))
+		return (0);	/* no data avail */
+
+	if (fcnt <= 0)
+		fcnt += B_FIFO_SIZE;	/* bytes actually buffered */
+	if (fcnt > HFCPCI_BTRANS_THRESHOLD)
+		fcnt = HFCPCI_BTRANS_THRESHOLD;		/* limit size */
+
+	new_z2 = le16_to_cpu(*z2r) + fcnt;	/* new position in fifo */
+	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
+		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
+
+	if (!(bch->rx_skb = alloc_stack_skb(fcnt, bch->up_headerlen)))
+		printk(KERN_WARNING "HFCPCI: receive out of memory\n");
+	else {
+		ptr = skb_put(bch->rx_skb, fcnt);
+		if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
+			maxlen = fcnt;	/* complete transfer */
+		else
+			maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r);	/* maximum */
+
+		ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL);	/* start of data */
+		memcpy(ptr, ptr1, maxlen);	/* copy data */
+		fcnt -= maxlen;
+
+		if (fcnt) {	/* rest remaining */
+			ptr += maxlen;
+			ptr1 = bdata;	/* start of buffer */
+			memcpy(ptr, ptr1, fcnt);	/* rest */
+		}
+		queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, bch->rx_skb);
+		bch->rx_skb = NULL;
+	}
+
+	*z2r = cpu_to_le16(new_z2);		/* new position */
+	return (1);
+}				/* hfcpci_empty_fifo_trans */
+
+/**********************************/
+/* B-channel main receive routine */
+/**********************************/
+void
+main_rec_hfcpci(channel_t *bch)
+{
+	hfc_pci_t	*hc = bch->hw;
+	int		rcnt, real_fifo;
+	int		receive, count = 5;
+	bzfifo_type	*bz;
+	u_char		*bdata;
+	z_type		*zp;
+
+
+	if ((bch->channel & 2) && (!hc->hw.bswapped)) {
+		bz = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b2;
+		bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.rxdat_b2;
+		real_fifo = 1;
+	} else {
+		bz = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b1;
+		bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.rxdat_b1;
+		real_fifo = 0;
+	}
+      Begin:
+	count--;
+	if (bz->f1 != bz->f2) {
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst, "hfcpci rec ch(%x) f1(%d) f2(%d)",
+				bch->channel, bz->f1, bz->f2);
+		zp = &bz->za[bz->f2];
+
+		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
+		if (rcnt < 0)
+			rcnt += B_FIFO_SIZE;
+		rcnt++;
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst, "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)",
+				bch->channel, le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt);
+		hfcpci_empty_fifo(bch, bz, bdata, rcnt);
+		rcnt = bz->f1 - bz->f2;
+		if (rcnt < 0)
+			rcnt += MAX_B_FRAMES + 1;
+		if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) {
+		        rcnt = 0;
+			hfcpci_clear_fifo_rx(hc, real_fifo);
+		}
+		hc->hw.last_bfifo_cnt[real_fifo] = rcnt;
+		if (rcnt > 1)
+			receive = 1;
+		else
+			receive = 0;
+	} else if (test_bit(FLG_TRANSPARENT, &bch->Flags))
+		receive = hfcpci_empty_fifo_trans(bch, bz, bdata);
+	else
+		receive = 0;
+	if (count && receive)
+		goto Begin;
+	return;
+}
+
+/**************************/
+/* D-channel send routine */
+/**************************/
+static void
+hfcpci_fill_dfifo(hfc_pci_t *hc)
+{
+	channel_t	*dch = &hc->dch;
+	int		fcnt;
+	int		count, new_z1, maxlen;
+	dfifo_type	*df;
+	u_char		*src, *dst, new_f1;
+
+	if ((dch->debug & L1_DEB_ISAC) && !(dch->debug & L1_DEB_ISAC_FIFO))
+		mISDN_debugprint(&dch->inst, "hfcpci_fill_dfifo");
+
+	if (!dch->tx_skb)
+		return;
+	count = dch->tx_skb->len - dch->tx_idx;
+	if (count <= 0)
+		return;
+	df = &((fifo_area *) (hc->hw.fifos))->d_chan.d_tx;
+
+	if (dch->debug & L1_DEB_ISAC_FIFO)
+		mISDN_debugprint(&dch->inst, "hfcpci_fill_Dfifo f1(%d) f2(%d) z1(f1)(%x)",
+			df->f1, df->f2,
+			le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1));
+	fcnt = df->f1 - df->f2;	/* frame count actually buffered */
+	if (fcnt < 0)
+		fcnt += (MAX_D_FRAMES + 1);	/* if wrap around */
+	if (fcnt > (MAX_D_FRAMES - 1)) {
+		if (dch->debug & L1_DEB_ISAC)
+			mISDN_debugprint(&dch->inst, "hfcpci_fill_Dfifo more as 14 frames");
+#ifdef ERROR_STATISTIC
+		cs->err_tx++;
+#endif
+		return;
+	}
+	/* now determine free bytes in FIFO buffer */
+	maxlen = le16_to_cpu(df->za[df->f2 & D_FREG_MASK].z2) - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) - 1;
+	if (maxlen <= 0)
+		maxlen += D_FIFO_SIZE;	/* count now contains available bytes */
+
+	if (dch->debug & L1_DEB_ISAC)
+		mISDN_debugprint(&dch->inst, "hfcpci_fill_Dfifo count(%ld/%d)",
+			count, maxlen);
+	if (count > maxlen) {
+		if (dch->debug & L1_DEB_ISAC)
+			mISDN_debugprint(&dch->inst, "hfcpci_fill_Dfifo no fifo mem");
+		return;
+	}
+	new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) & (D_FIFO_SIZE - 1);
+	new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1);
+	src = dch->tx_skb->data + dch->tx_idx;	/* source pointer */
+	dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
+	maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);		/* end fifo */
+	if (maxlen > count)
+		maxlen = count;	/* limit size */
+	memcpy(dst, src, maxlen);	/* first copy */
+
+	count -= maxlen;	/* remaining bytes */
+	if (count) {
+		dst = df->data;	/* start of buffer */
+		src += maxlen;	/* new position */
+		memcpy(dst, src, count);
+	}
+	df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);	/* for next buffer */
+	df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);	/* new pos actual buffer */
+	df->f1 = new_f1;	/* next frame */
+	if (dch->debug & L1_DEB_ISAC_FIFO) {
+		char *t = dch->log;
+
+		count = dch->tx_skb->len - dch->tx_idx;
+		src = dch->tx_skb->data + dch->tx_idx;
+		t += sprintf(t, "hfcD_fill_fifo cnt %d", count);
+		mISDN_QuickHex(t, src, count);
+		mISDN_debugprint(&dch->inst, dch->log);
+	}
+	dch->tx_idx = dch->tx_skb->len;
+	return;
+}
+
+/**************************/
+/* B-channel send routine */
+/**************************/
+static void
+hfcpci_fill_fifo(channel_t *bch)
+{
+	hfc_pci_t 	*hc = bch->hw;
+	int		maxlen, fcnt;
+	int		count, new_z1;
+	bzfifo_type	*bz;
+	u_char		*bdata;
+	u_char		new_f1, *src, *dst;
+	unsigned short	*z1t, *z2t;
+
+	if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
+		mISDN_debugprint(&bch->inst, "%s", __FUNCTION__);
+	if ((!bch->tx_skb) || bch->tx_skb->len <= 0)
+		return;
+	count = bch->tx_skb->len - bch->tx_idx;
+	if ((bch->channel & 2) && (!hc->hw.bswapped)) {
+		bz = &((fifo_area *) (hc->hw.fifos))->b_chans.txbz_b2;
+		bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.txdat_b2;
+	} else {
+		bz = &((fifo_area *) (hc->hw.fifos))->b_chans.txbz_b1;
+		bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.txdat_b1;
+	}
+
+	if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+		z1t = &bz->za[MAX_B_FRAMES].z1;
+		z2t = z1t + 1;
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst, "hfcpci_fill_fifo_trans ch(%x) cnt(%d) z1(%x) z2(%x)",
+				bch->channel, count, le16_to_cpu(*z1t), le16_to_cpu(*z2t));
+		fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
+		if (fcnt <= 0)
+			fcnt += B_FIFO_SIZE;	/* fcnt contains available bytes in fifo */
+		fcnt = B_FIFO_SIZE - fcnt;	/* remaining bytes to send */
+next_t_frame:
+		if (fcnt < (2 * HFCPCI_BTRANS_THRESHOLD)) {
+			count = bch->tx_skb->len - bch->tx_idx;
+			if (count >= B_FIFO_SIZE - fcnt)
+				count = B_FIFO_SIZE - fcnt -1;
+			if (count <= 0)
+				return;
+			/* data is suitable for fifo */
+			new_z1 = le16_to_cpu(*z1t) + count;	/* new buffer Position */
+			if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
+				new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
+			src = bch->tx_skb->data + bch->tx_idx;	/* source pointer */
+			dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL);
+			maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t);	/* end of fifo */
+			if (bch->debug & L1_DEB_HSCX_FIFO)
+				mISDN_debugprint(&bch->inst, "hfcpci_FFt fcnt(%d) maxl(%d) nz1(%x) dst(%p)",
+					fcnt, maxlen, new_z1, dst);
+			fcnt += count;
+			bch->tx_idx += count;
+			if (maxlen > count)
+				maxlen = count;		/* limit size */
+			memcpy(dst, src, maxlen);	/* first copy */
+			count -= maxlen;	/* remaining bytes */
+			if (count) {
+				dst = bdata;	/* start of buffer */
+				src += maxlen;	/* new position */
+				memcpy(dst, src, count);
+			}
+			*z1t = cpu_to_le16(new_z1);	/* now send data */
+			if (bch->tx_idx < bch->tx_skb->len)
+				return;
+			dev_kfree_skb(bch->tx_skb);
+			bch->tx_idx = 0;
+			if (test_bit(FLG_TX_NEXT, &bch->Flags)) {
+				bch->tx_skb = bch->next_skb;
+				if (bch->tx_skb) {
+					mISDN_head_t	*hh = mISDN_HEAD_P(bch->tx_skb);
+					bch->next_skb = NULL;
+					test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+					queue_ch_frame(bch, CONFIRM, hh->dinfo, NULL);
+					goto next_t_frame;
+				} else {
+					test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+					printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n");
+				}
+			}
+			bch->tx_skb = NULL;
+			test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		}
+		return;
+	}
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "%s: ch(%x) f1(%d) f2(%d) z1(f1)(%x)",
+			__FUNCTION__, bch->channel, bz->f1, bz->f2, bz->za[bz->f1].z1);
+	fcnt = bz->f1 - bz->f2;	/* frame count actually buffered */
+	if (fcnt < 0)
+		fcnt += (MAX_B_FRAMES + 1);	/* if wrap around */
+	if (fcnt > (MAX_B_FRAMES - 1)) {
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst, "hfcpci_fill_Bfifo more as 14 frames");
+		return;
+	}
+	/* now determine free bytes in FIFO buffer */
+	maxlen = le16_to_cpu(bz->za[bz->f2].z2) - le16_to_cpu(bz->za[bz->f1].z1) - 1;
+	if (maxlen <= 0)
+		maxlen += B_FIFO_SIZE;	/* count now contains available bytes */
+
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "hfcpci_fill_fifo ch(%x) count(%ld/%d),%lx",
+			bch->channel, count,
+			maxlen, current->state);
+
+	if (maxlen < count) {
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst, "hfcpci_fill_fifo no fifo mem");
+		return;
+	}
+	new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count;	/* new buffer Position */
+	if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
+		new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
+
+	new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES);
+	src = bch->tx_skb->data + bch->tx_idx;	/* source pointer */
+	dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL);
+	maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1);		/* end fifo */
+	if (maxlen > count)
+		maxlen = count;	/* limit size */
+	memcpy(dst, src, maxlen);	/* first copy */
+
+	count -= maxlen;	/* remaining bytes */
+	if (count) {
+		dst = bdata;	/* start of buffer */
+		src += maxlen;	/* new position */
+		memcpy(dst, src, count);
+	}
+	bz->za[new_f1].z1 = cpu_to_le16(new_z1);	/* for next buffer */
+	bz->f1 = new_f1;	/* next frame */
+	dev_kfree_skb(bch->tx_skb);
+	bch->tx_idx = 0;
+	if (test_bit(FLG_TX_NEXT, &bch->Flags)) {
+		bch->tx_skb = bch->next_skb;
+		if (bch->tx_skb) {
+			mISDN_head_t	*hh = mISDN_HEAD_P(bch->tx_skb);
+			bch->next_skb = NULL;
+			test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+			queue_ch_frame(bch, CONFIRM, hh->dinfo, NULL);
+		} else {
+			test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+			test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+			printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n");
+		}
+	} else {
+		bch->tx_skb = NULL;
+		test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+	}
+}
+
+
+
+/***************************/
+/* handle L1 state changes */
+/***************************/
+
+static void
+ph_state_change(channel_t *dch)
+{
+	hfc_pci_t	*hc = dch->inst.privat;
+	u_int		prim = PH_SIGNAL | INDICATION;
+	u_int		para = 0;
+
+	if (!hc->hw.nt_mode) {
+		if (dch->debug)
+			printk(KERN_DEBUG "%s: TE newstate %x\n",
+				__FUNCTION__, dch->state);
+		switch (dch->state) {
+			case (0):
+				prim = PH_CONTROL | INDICATION;
+				para = HW_RESET;
+				break;
+			case (3):
+				prim = PH_CONTROL | INDICATION;
+				para = HW_DEACTIVATE;
+				break;
+			case (5):
+			case (8):
+				para = ANYSIGNAL;
+				break;
+			case (6):
+				para = INFO2;
+				break;
+			case (7):
+				para = INFO4_P8;
+				break;
+			default:
+				return;
+		}
+	} else {
+		if (dch->debug)
+			printk(KERN_DEBUG "%s: NT newstate %x\n",
+				__FUNCTION__, dch->state);
+		switch (dch->state) {
+			case (2):
+				if (hc->hw.nt_timer < 0) {
+					hc->hw.nt_timer = 0;
+					hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
+					Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
+					/* Clear already pending ints */
+					if (Read_hfc(hc, HFCPCI_INT_S1));
+
+					Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
+					udelay(10);
+					Write_hfc(hc, HFCPCI_STATES, 4);
+					dch->state = 4;
+				} else {
+					hc->hw.int_m1 |= HFCPCI_INTS_TIMER;
+					Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
+					hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER;
+					hc->hw.ctmt |= HFCPCI_TIM3_125;
+					Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
+					Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
+					hc->hw.nt_timer = NT_T1_COUNT;
+					Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3);	/* allow G2 -> G3 transition */
+				}
+				return;
+			case (1):
+				prim = PH_DEACTIVATE | INDICATION;
+				para = 0;
+				hc->hw.nt_timer = 0;
+				hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
+				Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
+				test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+				break;
+			case (4):
+				hc->hw.nt_timer = 0;
+				hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
+				Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
+				return;
+			case (3):
+				prim = PH_ACTIVATE | INDICATION;
+				para = 0;
+				hc->hw.nt_timer = 0;
+				hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
+				Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
+				test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+				break;
+			default:
+				return;
+		}
+		mISDN_queue_data(&dch->inst, dch->inst.id | MSG_BROADCAST,
+			MGR_SHORTSTATUS | INDICATION, test_bit(FLG_ACTIVE, &dch->Flags) ?
+			SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED,
+			0, NULL, 0);
+	}
+	mISDN_queue_data(&dch->inst, FLG_MSG_UP, prim, para, 0, NULL, 0);
+}
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static inline void
+tx_irq(channel_t *chan)
+{
+	if (chan->tx_skb && chan->tx_idx < chan->tx_skb->len) {
+		if (test_bit(FLG_DCHANNEL, &chan->Flags))
+			hfcpci_fill_dfifo(chan->hw);
+		if (test_bit(FLG_BCHANNEL, &chan->Flags))
+			hfcpci_fill_fifo(chan);
+	} else {
+		if (chan->tx_skb)
+			dev_kfree_skb(chan->tx_skb);
+		chan->tx_idx = 0;
+		if (test_bit(FLG_TX_NEXT, &chan->Flags)) {
+			chan->tx_skb = chan->next_skb;
+			if (chan->tx_skb) {
+				mISDN_head_t	*hh = mISDN_HEAD_P(chan->tx_skb);
+				chan->next_skb = NULL;
+				test_and_clear_bit(FLG_TX_NEXT, &chan->Flags);
+				queue_ch_frame(chan, CONFIRM, hh->dinfo, NULL);
+				if (test_bit(FLG_DCHANNEL, &chan->Flags))
+					hfcpci_fill_dfifo(chan->hw);
+				if (test_bit(FLG_BCHANNEL, &chan->Flags))
+					hfcpci_fill_fifo(chan);
+			} else {
+				printk(KERN_WARNING "hfc tx irq TX_NEXT without skb\n");
+				test_and_clear_bit(FLG_TX_NEXT, &chan->Flags);
+				test_and_clear_bit(FLG_TX_BUSY, &chan->Flags);
+			}
+		} else {
+			test_and_clear_bit(FLG_TX_BUSY, &chan->Flags);
+			chan->tx_skb = NULL;
+		}
+	}
+}
+
+static irqreturn_t
+hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	hfc_pci_t	*hc = dev_id;
+	u_char		exval;
+	channel_t	*bch;
+	u_char		val, stat;
+
+	spin_lock(&hc->lock);
+	if (!(hc->hw.int_m2 & 0x08)) {
+		spin_unlock(&hc->lock);
+		return IRQ_NONE; /* not initialised */
+	}
+
+	if (HFCPCI_ANYINT & (stat = Read_hfc(hc, HFCPCI_STATUS))) {
+		val = Read_hfc(hc, HFCPCI_INT_S1);
+		if (hc->dch.debug & L1_DEB_ISAC)
+			mISDN_debugprint(&hc->dch.inst, "HFC-PCI: stat(%02x) s1(%02x)",
+				stat, val);
+	} else {
+		/* shared */
+		spin_unlock(&hc->lock);
+		return IRQ_NONE;
+	}
+	hc->irqcnt++;
+
+	if (hc->dch.debug & L1_DEB_ISAC)
+		mISDN_debugprint(&hc->dch.inst, "HFC-PCI irq %x", val);
+	val &= hc->hw.int_m1;
+	if (val & 0x40) {	/* state machine irq */
+		exval = Read_hfc(hc, HFCPCI_STATES) & 0xf;
+		if (hc->dch.debug & L1_DEB_ISAC)
+			mISDN_debugprint(&hc->dch.inst, "ph_state chg %d->%d",
+				hc->dch.state, exval);
+		hc->dch.state = exval;
+		ph_state_change(&hc->dch);
+		val &= ~0x40;
+	}
+	if (val & 0x80) {	/* timer irq */
+		if (hc->hw.nt_mode) {
+			if ((--hc->hw.nt_timer) < 0)
+				ph_state_change(&hc->dch);
+		}
+		val &= ~0x80;
+		Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
+	}
+	if (val & 0x08) {
+		if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) {
+			if (hc->dch.debug)
+				mISDN_debugprint(&hc->dch.inst, "hfcpci spurious 0x08 IRQ");
+		} else
+			main_rec_hfcpci(bch);
+	}
+	if (val & 0x10) {
+//		if (hc->logecho)
+//			receive_emsg(hc);
+//		else 
+		if (!(bch = Sel_BCS(hc, 2))) {
+			if (hc->dch.debug)
+				mISDN_debugprint(&hc->dch.inst, "hfcpci spurious 0x10 IRQ");
+		} else
+			main_rec_hfcpci(bch);
+	}
+	if (val & 0x01) {
+		if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) {
+			if (hc->dch.debug)
+				mISDN_debugprint(&hc->dch.inst, "hfcpci spurious 0x01 IRQ");
+		} else
+			tx_irq(bch);
+	}
+	if (val & 0x02) {
+		if (!(bch = Sel_BCS(hc, 2))) {
+			if (hc->dch.debug)
+				mISDN_debugprint(&hc->dch.inst, "hfcpci spurious 0x02 IRQ");
+		} else
+			tx_irq(bch);
+	}
+	if (val & 0x20) {	/* receive dframe */
+		receive_dmsg(hc);
+	}
+	if (val & 0x04) {	/* dframe transmitted */
+		if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags))
+			del_timer(&hc->dch.timer);
+		tx_irq(&hc->dch);
+	}
+	spin_unlock(&hc->lock);
+	return IRQ_HANDLED;
+}
+
+/********************************************************************/
+/* timer callback for D-chan busy resolution. Currently no function */
+/********************************************************************/
+static void
+hfcpci_dbusy_timer(hfc_pci_t *hc)
+{
+}
+
+/***************************************************************/
+/* activate/deactivate hardware for selected channels and mode */
+/***************************************************************/
+static int
+mode_hfcpci(channel_t *bch, int bc, int protocol)
+{
+	hfc_pci_t	*hc = bch->hw;
+	int		fifo2;
+	u_char		rx_slot = 0, tx_slot = 0, pcm_mode;
+
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "HFCPCI bchannel protocol %x-->%x ch %x-->%x",
+			bch->state, protocol, bch->channel, bc);
+	
+	fifo2 = bc;
+	pcm_mode = (bc>>24) & 0xff;
+	if (pcm_mode) { /* PCM SLOT USE */
+		if (!test_bit(HFC_CFG_PCM, &hc->cfg))
+			printk(KERN_WARNING "%s: pcm channel id without HFC_CFG_PCM\n",
+				__FUNCTION__);
+		rx_slot = (bc>>8) & 0xff;
+		tx_slot = (bc>>16) & 0xff;
+		bc = bc & 0xff;
+	} else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_PID_NONE))
+		printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n",
+				__FUNCTION__);
+	if (hc->chanlimit > 1) {
+		hc->hw.bswapped = 0;	/* B1 and B2 normal mode */
+		hc->hw.sctrl_e &= ~0x80;
+	} else {
+		if (bc & 2) {
+			if (protocol != ISDN_PID_NONE) {
+				hc->hw.bswapped = 1;	/* B1 and B2 exchanged */
+				hc->hw.sctrl_e |= 0x80;
+			} else {
+				hc->hw.bswapped = 0;	/* B1 and B2 normal mode */
+				hc->hw.sctrl_e &= ~0x80;
+			}
+			fifo2 = 1;
+		} else {
+			hc->hw.bswapped = 0;	/* B1 and B2 normal mode */
+			hc->hw.sctrl_e &= ~0x80;
+		}
+	}
+	switch (protocol) {
+		case (-1): /* used for init */
+			bch->state = -1;
+			bch->channel = bc;
+		case (ISDN_PID_NONE):
+			if (bch->state == ISDN_PID_NONE) {
+				return(0);
+			}
+			if (bc & 2) {
+				hc->hw.sctrl &= ~SCTRL_B2_ENA;
+				hc->hw.sctrl_r &= ~SCTRL_B2_ENA;
+			} else {
+				hc->hw.sctrl &= ~SCTRL_B1_ENA;
+				hc->hw.sctrl_r &= ~SCTRL_B1_ENA;
+			}
+			if (fifo2 & 2) {
+				hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2;
+				hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+			} else {
+				hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1;
+				hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
+			}
+#ifdef REVERSE_BITORDER
+			if (bch->channel & 2)
+				hc->hw.cirm &= 0x7f;
+			else
+				hc->hw.cirm &= 0xbf;
+#endif
+			bch->state = ISDN_PID_NONE;
+			bch->channel = bc;
+			test_and_clear_bit(FLG_HDLC, &bch->Flags);
+			test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
+			break;
+		case (ISDN_PID_L1_B_64TRANS):
+			bch->state = protocol;
+			bch->channel = bc;
+		        hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0);
+		        hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0);
+			if (bc & 2) {
+				hc->hw.sctrl |= SCTRL_B2_ENA;
+				hc->hw.sctrl_r |= SCTRL_B2_ENA;
+#ifdef REVERSE_BITORDER
+				hc->hw.cirm |= 0x80;
+#endif
+			} else {
+				hc->hw.sctrl |= SCTRL_B1_ENA;
+				hc->hw.sctrl_r |= SCTRL_B1_ENA;
+#ifdef REVERSE_BITORDER
+				hc->hw.cirm |= 0x40;
+#endif
+			}
+			if (fifo2 & 2) {
+				hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
+				hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+				hc->hw.ctmt |= 2;
+				hc->hw.conn &= ~0x18;
+			} else {
+				hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
+				hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
+				hc->hw.ctmt |= 1;
+				hc->hw.conn &= ~0x03;
+			}
+			test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
+			break;
+		case (ISDN_PID_L1_B_64HDLC):
+			bch->state = protocol;
+			bch->channel = bc;
+		        hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0);
+		        hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0);
+			if (bc & 2) {
+				hc->hw.sctrl |= SCTRL_B2_ENA;
+				hc->hw.sctrl_r |= SCTRL_B2_ENA;
+			} else {
+				hc->hw.sctrl |= SCTRL_B1_ENA;
+				hc->hw.sctrl_r |= SCTRL_B1_ENA;
+			}
+			if (fifo2 & 2) {
+			        hc->hw.last_bfifo_cnt[1] = 0;  
+				hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
+				hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+				hc->hw.ctmt &= ~2;
+				hc->hw.conn &= ~0x18;
+			} else {
+			        hc->hw.last_bfifo_cnt[0] = 0;  
+				hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
+				hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
+				hc->hw.ctmt &= ~1;
+				hc->hw.conn &= ~0x03;
+			}
+			test_and_set_bit(FLG_HDLC, &bch->Flags);
+			break;
+		default:
+			mISDN_debugprint(&bch->inst, "prot not known %x", protocol);
+			return(-ENOPROTOOPT);
+	}
+	if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
+		if ((protocol == ISDN_PID_NONE) ||
+			(protocol == -1)) {	/* init case */
+			rx_slot = 0;
+			tx_slot = 0;
+		} else {
+			if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) {
+				rx_slot |= 0xC0;
+				tx_slot |= 0xC0;
+			} else {
+				rx_slot |= 0x80;
+				tx_slot |= 0x80;
+			}
+		}
+		if (bc & 2) {
+			hc->hw.conn &= 0xc7;
+			hc->hw.conn |= 0x08;
+			printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n",
+				__FUNCTION__, tx_slot);
+			printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n",
+				__FUNCTION__, rx_slot);
+			Write_hfc(hc, HFCPCI_B2_SSL, tx_slot);
+			Write_hfc(hc, HFCPCI_B2_RSL, rx_slot);
+		} else {
+			hc->hw.conn &= 0xf8;
+			hc->hw.conn |= 0x01;
+			printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n",
+				__FUNCTION__, tx_slot);
+			printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n",
+				__FUNCTION__, rx_slot);
+			Write_hfc(hc, HFCPCI_B1_SSL, tx_slot);
+			Write_hfc(hc, HFCPCI_B1_RSL, rx_slot);
+		}
+	}
+	Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
+	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
+	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
+	Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
+	Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
+	Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
+	Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
+#ifdef REVERSE_BITORDER
+	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
+#endif
+	return(0);
+}
+
+static int
+set_hfcpci_rxtest(channel_t *bch, int protocol, struct sk_buff *skb)
+{
+	hfc_pci_t	*hc = bch->hw;
+	int		*chan = (int *)skb->data;
+
+	if (skb->len <4) {
+		mISDN_debugprint(&bch->inst, "HFCPCI rxtest no channel parameter");
+		return(-EINVAL);
+	}
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x",
+			bch->state, protocol, bch->channel, *chan);
+	if (bch->channel != *chan) {
+		mISDN_debugprint(&bch->inst, "HFCPCI rxtest wrong channel parameter %x/%x",
+			bch->channel, *chan);
+		return(-EINVAL);
+	}
+	switch (protocol) {
+		case (ISDN_PID_L1_B_64TRANS):
+			bch->state = protocol;
+		        hfcpci_clear_fifo_rx(hc, (*chan & 2)?1:0);
+			if (*chan & 2) {
+				hc->hw.sctrl_r |= SCTRL_B2_ENA;
+				hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
+				hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
+				hc->hw.ctmt |= 2;
+				hc->hw.conn &= ~0x18;
+#ifdef REVERSE_BITORDER
+				hc->hw.cirm |= 0x80;
+#endif
+			} else {
+				hc->hw.sctrl_r |= SCTRL_B1_ENA;
+				hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX;
+				hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
+				hc->hw.ctmt |= 1;
+				hc->hw.conn &= ~0x03;
+#ifdef REVERSE_BITORDER
+				hc->hw.cirm |= 0x40;
+#endif
+			}
+			break;
+		case (ISDN_PID_L1_B_64HDLC):
+			bch->state = protocol;
+		        hfcpci_clear_fifo_rx(hc, (*chan & 2)?1:0);
+			if (*chan & 2) {
+				hc->hw.sctrl_r |= SCTRL_B2_ENA;
+				hc->hw.last_bfifo_cnt[1] = 0;
+				hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
+				hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
+				hc->hw.ctmt &= ~2;
+				hc->hw.conn &= ~0x18;
+			} else {
+				hc->hw.sctrl_r |= SCTRL_B1_ENA;
+			        hc->hw.last_bfifo_cnt[0] = 0;  
+				hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX;
+				hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
+				hc->hw.ctmt &= ~1;
+				hc->hw.conn &= ~0x03;
+			}
+			break;
+		default:
+			mISDN_debugprint(&bch->inst, "prot not known %x", protocol);
+			return(-ENOPROTOOPT);
+	}
+	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
+	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
+	Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
+	Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
+	Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
+#ifdef REVERSE_BITORDER
+	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
+#endif
+	return(0);
+}
+
+/*************************************/
+/* Layer 1 D-channel hardware access */
+/*************************************/
+static int
+hfc_dmsg(channel_t *dch, struct sk_buff *skb)
+{
+	hfc_pci_t	*hc = dch->hw;
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	if (hh->prim == (PH_SIGNAL | REQUEST)) {
+		spin_lock_irqsave(dch->inst.hwlock, flags);
+		if ((hh->dinfo == INFO3_P8) || (hh->dinfo == INFO3_P10)) {
+			if (test_bit(HFC_CFG_MASTER, &hc->cfg))
+				hc->hw.mst_m |= HFCPCI_MASTER;
+			Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
+		} else
+			ret = -EINVAL;
+		spin_unlock_irqrestore(dch->inst.hwlock, flags);
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		spin_lock_irqsave(dch->inst.hwlock, flags);
+		if (hh->dinfo == HW_RESET) {
+			Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3);	/* HFC ST 3 */
+			udelay(6);
+			Write_hfc(hc, HFCPCI_STATES, 3);	/* HFC ST 2 */
+			if (test_bit(HFC_CFG_MASTER, &hc->cfg))
+				hc->hw.mst_m |= HFCPCI_MASTER;
+			Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
+			Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
+			spin_unlock_irqrestore(dch->inst.hwlock, flags);
+			skb_trim(skb, 0);
+			return(mISDN_queueup_newhead(&dch->inst, 0, PH_CONTROL | INDICATION,
+				HW_POWERUP, skb));
+//			l1_msg(hc, HW_POWERUP | CONFIRM, NULL);
+		} else if (hh->dinfo == HW_DEACTIVATE) {
+			hc->hw.mst_m &= ~HFCPCI_MASTER;
+			Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
+			if (dch->next_skb) {
+				dev_kfree_skb(dch->next_skb);
+				dch->next_skb = NULL;
+			}
+			test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+			if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+				del_timer(&dch->timer);
+		} else if (hh->dinfo == HW_POWERUP) {
+			Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION);
+		} else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) {
+			u_char	slot;
+			if (1 & hh->dinfo) {
+				if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
+					slot = 0xC0;
+				else
+					slot = 0x80;
+				printk(KERN_DEBUG  "%s: Write_hfc: B1_SSL/RSL 0x%x\n",
+					__FUNCTION__, slot);
+				Write_hfc(hc, HFCPCI_B1_SSL, slot);
+				Write_hfc(hc, HFCPCI_B1_RSL, slot);
+				hc->hw.conn = (hc->hw.conn & ~7) | 1;
+				Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
+			}
+			if (2 & hh->dinfo) {
+				if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
+					slot = 0xC1;
+				else
+					slot = 0x81;
+				printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n",
+					__FUNCTION__, slot);
+				Write_hfc(hc, HFCPCI_B2_SSL, slot);
+				Write_hfc(hc, HFCPCI_B2_RSL, slot);
+				hc->hw.conn = (hc->hw.conn & ~0x38) | 0x08;
+				Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
+			}
+			if (3 & hh->dinfo)
+				hc->hw.trm |= 0x80;	/* enable IOM-loop */
+			else
+				hc->hw.trm &= 0x7f;	/* disable IOM-loop */
+			Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "%s: unknown ctrl %x",
+					__FUNCTION__, hh->dinfo);
+			ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(dch->inst.hwlock, flags);
+	} else if (hh->prim == (PH_ACTIVATE | REQUEST)) {
+		if (hc->hw.nt_mode) {
+			spin_lock_irqsave(dch->inst.hwlock, flags);
+			Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* G0 */
+			udelay(6);
+			Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* G1 */
+			udelay(6);
+			if (test_bit(HFC_CFG_MASTER, &hc->cfg))
+				hc->hw.mst_m |= HFCPCI_MASTER;
+			Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
+			udelay(6);
+			Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION | 1);
+			spin_unlock_irqrestore(dch->inst.hwlock, flags);
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "%s: PH_ACTIVATE none NT mode",
+					__FUNCTION__);
+			ret = -EINVAL;
+		}
+	} else if (hh->prim == (PH_DEACTIVATE | REQUEST)) {
+		if (hc->hw.nt_mode) {
+			spin_lock_irqsave(dch->inst.hwlock, flags);
+			hc->hw.mst_m &= ~HFCPCI_MASTER;
+			Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
+			if (dch->next_skb) {
+				dev_kfree_skb(dch->next_skb);
+				dch->next_skb = NULL;
+			}
+			test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+			if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+				del_timer(&dch->timer);
+#ifdef FIXME
+			if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
+				dchannel_sched_event(&hc->dch, D_CLEARBUSY);
+#endif
+			spin_unlock_irqrestore(dch->inst.hwlock, flags);
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "%s: PH_DEACTIVATE none NT mode",
+					__FUNCTION__);
+			ret = -EINVAL;
+		}
+	} else if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS) {
+		u_int	temp = hh->dinfo & SSTATUS_ALL;
+		if (hc->hw.nt_mode && /* if TE mode ignore */
+			(temp == SSTATUS_ALL || temp == SSTATUS_L1)) {
+			if (hh->dinfo & SSTATUS_BROADCAST_BIT)
+				temp = dch->inst.id | MSG_BROADCAST;
+			else
+				temp = hh->addr | FLG_MSG_TARGET;
+			skb_trim(skb, 0);
+			hh->dinfo = test_bit(FLG_ACTIVE, &dch->Flags) ?
+				SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED;
+			hh->prim = MGR_SHORTSTATUS | CONFIRM;
+			return(mISDN_queue_message(&dch->inst, temp, skb));
+		}
+		ret = -EOPNOTSUPP;
+	} else {
+		if (dch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&dch->inst, "%s: unknown prim %x",
+				__FUNCTION__, hh->prim);
+		ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+/*************************************/
+/* Layer 1 B-channel hardware access */
+/*************************************/
+static int
+hfc_bmsg(channel_t *bch, struct sk_buff *skb)
+{
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	int		ret = -EINVAL;
+	u_long		flags;
+
+	if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_ESTABLISH  | REQUEST))) {
+		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
+			spin_lock_irqsave(bch->inst.hwlock, flags);
+			ret = mode_hfcpci(bch, bch->channel,
+				bch->inst.pid.protocol[1]);
+			if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				test_and_set_bit(FLG_L2DATA, &bch->Flags);
+			spin_unlock_irqrestore(bch->inst.hwlock, flags);
+		} else
+			ret = 0;
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, ret, skb));
+	} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_RELEASE | REQUEST)) ||
+		((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
+		spin_lock_irqsave(bch->inst.hwlock, flags);
+		if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+			dev_kfree_skb(bch->next_skb);
+			bch->next_skb = NULL;
+		}
+		if (bch->tx_skb) {
+			dev_kfree_skb(bch->tx_skb);
+			bch->tx_skb = NULL;
+		}
+		bch->tx_idx = 0;
+		if (bch->rx_skb) {
+			dev_kfree_skb(bch->rx_skb);
+			bch->rx_skb = NULL;
+		}
+		test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		mode_hfcpci(bch, bch->channel, ISDN_PID_NONE);
+		test_and_clear_bit(FLG_L2DATA, &bch->Flags);
+		test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+		spin_unlock_irqrestore(bch->inst.hwlock, flags);
+		skb_trim(skb, 0);
+		if (hh->prim != (PH_CONTROL | REQUEST))
+			if (!mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, 0, skb))
+				return(0);
+		ret = 0;
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		spin_lock_irqsave(bch->inst.hwlock, flags);
+		if (hh->dinfo == HW_TESTRX_RAW) {
+			ret = set_hfcpci_rxtest(bch, ISDN_PID_L1_B_64TRANS, skb);
+		} else if (hh->dinfo == HW_TESTRX_HDLC) {
+			ret = set_hfcpci_rxtest(bch, ISDN_PID_L1_B_64HDLC, skb);
+		} else if (hh->dinfo == HW_TESTRX_OFF) {
+			mode_hfcpci(bch, bch->channel, ISDN_PID_NONE);
+			ret = 0;
+		} else
+			ret = -EINVAL;
+		spin_unlock_irqrestore(bch->inst.hwlock, flags);
+		if (!ret) {
+			skb_trim(skb, 0);
+			if (!mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, hh->dinfo, skb))
+				return(0);
+		}
+	} else {
+		printk(KERN_WARNING "%s: unknown prim(%x)\n",
+			__FUNCTION__, hh->prim);
+		ret = -EAGAIN;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+static int
+hfcpci_l2l1(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*chan = container_of(inst, channel_t, inst);
+	int		ret = -EINVAL;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	if ((hh->prim == PH_DATA_REQ) ||
+		(hh->prim == (DL_DATA | REQUEST))) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		ret = channel_senddata(chan, hh->dinfo, skb);
+		if (ret > 0) { /* direct TX */
+			if (test_bit(FLG_DCHANNEL, &chan->Flags))
+				hfcpci_fill_dfifo(chan->hw);
+			if (test_bit(FLG_BCHANNEL, &chan->Flags))
+				hfcpci_fill_fifo(chan);
+			ret = 0;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		return(ret);
+	}
+	if (test_bit(FLG_DCHANNEL, &chan->Flags)) {
+		ret = hfc_dmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (test_bit(FLG_BCHANNEL, &chan->Flags)) {
+		ret = hfc_bmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+/********************************/
+/* called for card init message */
+/********************************/
+
+void
+inithfcpci(hfc_pci_t *hc)
+{
+	HFC_INFO("inithfcpci: entered\n");
+	hc->dch.timer.function = (void *) hfcpci_dbusy_timer;
+	hc->dch.timer.data = (long) &hc->dch;
+	init_timer(&hc->dch.timer);
+	hc->chanlimit = 2;
+	mode_hfcpci(&hc->bch[0], 1, -1);
+	mode_hfcpci(&hc->bch[1], 2, -1);
+}
+
+
+static int init_card(hfc_pci_t *hc)
+{
+	int	cnt = 3;
+	u_long	flags;
+
+	HFC_INFO("init_card: entered\n");
+
+
+	spin_lock_irqsave(&hc->lock, flags);
+	disable_hwirq(hc);
+	spin_unlock_irqrestore(&hc->lock, flags);
+	if (request_irq(hc->irq, hfcpci_interrupt, SA_SHIRQ, "HFC PCI", hc)) {
+		printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n", hc->irq);
+		return(-EIO);
+	}
+	spin_lock_irqsave(&hc->lock, flags);
+	while (cnt) {
+		inithfcpci(hc);
+		/* Finally enable IRQ output 
+		 * this is only allowed, if an IRQ routine is allready
+		 * established for this HFC, so don't do that earlier
+		 */
+		enable_hwirq(hc);
+		spin_unlock_irqrestore(&hc->lock, flags);
+		/* Timeout 80ms */
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout((80*HZ)/1000);
+		printk(KERN_INFO "HFC PCI: IRQ %d count %d\n",
+			hc->irq, hc->irqcnt);
+		/* now switch timer interrupt off */
+		spin_lock_irqsave(&hc->lock, flags);
+		hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
+		Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
+		/* reinit mode reg */
+		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
+		if (!hc->irqcnt) {
+			printk(KERN_WARNING
+			       "HFC PCI: IRQ(%d) getting no interrupts during init %d\n",
+			       hc->irq, 4 - cnt);
+			if (cnt == 1) {
+				spin_unlock_irqrestore(&hc->lock, flags);
+				return (-EIO);
+			} else {
+				reset_hfcpci(hc);
+				cnt--;
+			}
+		} else {
+			spin_unlock_irqrestore(&hc->lock, flags);
+			return(0);
+		}
+	}
+	spin_unlock_irqrestore(&hc->lock, flags);
+	return(-EIO);
+}
+
+static int
+SelFreeBChannel(hfc_pci_t *hc, channel_info_t *ci)
+{
+	channel_t		*bch;
+	hfc_pci_t		*hfc;
+	mISDNstack_t		*bst;
+	u_int			cnr;
+	struct list_head	*head;
+	
+	if (!ci)
+		return(-EINVAL);
+	ci->st.p = NULL;
+	cnr=0;
+	bst = hc->dch.inst.st;
+	if (list_empty(&bst->childlist)) {
+		if ((bst->id & FLG_CLONE_STACK) &&
+			(bst->childlist.prev != &bst->childlist)) {
+			head = bst->childlist.prev;
+		} else {
+			printk(KERN_ERR "%s: invalid empty childlist (no clone) stid(%x) childlist(%p<-%p->%p)\n",
+				__FUNCTION__, bst->id, bst->childlist.prev, &bst->childlist, bst->childlist.next);
+			return(-EINVAL);
+		}
+	} else
+		head = &bst->childlist;
+	list_for_each_entry(bst, head, list) {
+		if (!bst->mgr) {
+			int_errtxt("no mgr st(%p)", bst);
+			return(-EINVAL);
+		}
+		bch = container_of(bst->mgr, channel_t, inst);
+		hfc = bst->mgr->privat;
+		if (!hfc) {
+			int_errtxt("no mgr->data st(%p)", bst);
+			return(-EINVAL);
+		}
+		bch = &hfc->bch[cnr & 1];
+		if (!(ci->channel & (~CHANNEL_NUMBER))) {
+			/* only number is set */
+			if ((ci->channel & 0x3) == (cnr + 1)) {
+				if (test_bit(FLG_ACTIVE, &bch->Flags))
+					return(-EBUSY);
+				bch->channel = (cnr & 1) ? 2 : 1;
+				ci->st.p = bst;
+				return(0);
+			}
+		} else if ((ci->channel & (~CHANNEL_NUMBER)) == 0x00a18300) {
+			if (!test_bit(FLG_ACTIVE, &bch->Flags)) {
+				ci->st.p = bst;
+				bch->channel = (cnr & 1) ? 2 : 1;
+				bch->channel |= CHANNEL_EXT_PCM;
+				bch->channel |= (ci->channel & 0x1f) << 16;
+				bch->channel |= (ci->channel & 0x1f) << 8;
+				ci->st.p = bst;
+				return(0);
+			}
+		}
+		cnr++;
+	}
+	return(-EBUSY);
+}
+
+#define MAX_CARDS	8
+static int HFC_cnt;
+static uint protocol[MAX_CARDS];
+static uint layermask[MAX_CARDS];
+static uint debug;
+
+static mISDNobject_t	HFC_obj;
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#define MODULE_PARM_T   "1-4i"
+MODULE_PARM(protocol, MODULE_PARM_T);
+MODULE_PARM(layermask, MODULE_PARM_T);
+#else
+module_param (debug, uint, 0);
+MODULE_PARM_DESC (debug, "hfcpci debug mask");
+#ifdef OLD_MODULE_PARAM_ARRAY
+static int	protocol_cnt;
+module_param_array(protocol, uint, protocol_cnt, 0);
+#else
+module_param_array(protocol, uint, NULL, 0);
+#endif
+MODULE_PARM_DESC (protocol, "hfcpci protcol (DSS1 := 2)");
+
+/* short description of protocol
+ * protocol=<p1>[,p2,p3...]
+ *
+ * Values:
+ * the value has following structure
+ * <bit  3 -  0>  D-channel protocol id
+ * <bit 15 -  4>  Flags for special features
+ * <bit 31 - 16>  Spare (set to 0)
+ *
+ * D-channel protocol ids
+ * 1       1TR6 (not released yet)
+ * 2       DSS1
+ *
+ * Feature Flags
+ * bit 4   0x0010  Net side stack (NT mode)
+ * bit 5   0x0020  point to point line
+ * bit 6   0x0040  PCM slave mode
+ * bit 7   0x0080  use negativ frame pulse
+ * bit 8   0x0100  use setting from the previous HFC driver and add channels to
+ *                 the previous stack, used for the second chip in 2 chip setups
+ * bit 9   0x0200  switch DD/DU interface
+ * bit 10 - 15     reserved
+ */
+#ifdef OLD_MODULE_PARAM_ARRAY
+static int	layermask_cnt;
+module_param_array(layermask, uint, layermask_cnt, 0);
+#else
+module_param_array(layermask, uint, NULL, 0);
+#endif
+MODULE_PARM_DESC(layermask, "hfcpci layer mask");
+#endif
+#endif
+
+static char HFCName[] = "HFC_PCI";
+
+/* this variable is used as card index when more than one cards are present */
+static struct pci_dev *dev_hfcpci = NULL;
+
+
+static int
+setup_hfcpci(hfc_pci_t *hc)
+{
+	char tmp[64];
+	int i=0;
+	struct pci_dev *tmp_hfcpci = NULL;
+	void *buffer;
+
+	strcpy(tmp, hfcpci_revision);
+	printk(KERN_INFO "mISDN: HFC-PCI driver Rev. %s\n", mISDN_getrev(tmp));
+	hc->hw.cirm = 0;
+	hc->dch.state = 0;
+	while (id_list[i].vendor_id) {
+		tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
+				id_list[i].device_id, dev_hfcpci);
+		i++;
+		if (tmp_hfcpci) {
+			if (pci_enable_device(tmp_hfcpci))
+				continue;
+			pci_set_master(tmp_hfcpci);
+			break;
+		}
+	}
+	if (tmp_hfcpci) {
+		i--;
+		dev_hfcpci = tmp_hfcpci;	/* old device */
+		hc->hw.dev = dev_hfcpci;
+		hc->irq = dev_hfcpci->irq;
+		if (!hc->irq) {
+			printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
+			return (1);
+		}
+		hc->hw.pci_io = (char *) get_pcibase(dev_hfcpci, 1);
+		printk(KERN_INFO "mISDN: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
+	} else {
+		printk(KERN_WARNING "HFC-PCI: No more PCI cards found\n");
+		return (1);
+	}
+	if (!hc->hw.pci_io) {
+		printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
+		return (1);
+	}
+	/* Allocate memory for FIFOS */
+	/* the memory needs to be on a 32k boundary within the first 4G */
+	pci_set_dma_mask(dev_hfcpci, 0xFFFF8000);
+	buffer = pci_alloc_consistent(dev_hfcpci, 0x8000, &hc->hw.dmahandle);
+	/* We silently assume the address is okay if nonzero */
+	if(!buffer) {
+		printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
+		return 1;
+	}
+	hc->hw.fifos = buffer;
+	pci_write_config_dword(hc->hw.dev, 0x80, hc->hw.dmahandle);
+	hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256);
+	printk(KERN_INFO
+		"HFC-PCI: defined at mem %#lx fifo %#lx(%#lx) IRQ %d HZ %d\n",
+		(u_long) hc->hw.pci_io, (u_long) hc->hw.fifos,
+		(u_long) virt_to_bus(hc->hw.fifos),
+		hc->irq, HZ);
+	pci_write_config_word(hc->hw.dev, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */
+	hc->hw.int_m2 = 0;
+	disable_hwirq(hc);
+	hc->hw.int_m1 = 0;
+	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
+	/* At this point the needed PCI config is done */
+	/* fifos are still not enabled */
+	hc->hw.timer.function = (void *) hfcpci_Timer;
+	hc->hw.timer.data = (long) hc;
+	init_timer(&hc->hw.timer);
+	reset_hfcpci(hc);
+	return (0);
+}
+
+static void
+release_card(hfc_pci_t *hc) {
+	u_long	flags;
+
+	free_irq(hc->irq, hc);
+	spin_lock_irqsave(&hc->lock, flags);
+	mode_hfcpci(&hc->bch[0], 1, ISDN_PID_NONE);
+	mode_hfcpci(&hc->bch[1], 2, ISDN_PID_NONE);
+	if (hc->dch.timer.function != NULL) {
+		del_timer(&hc->dch.timer);
+		hc->dch.timer.function = NULL;
+	}
+	release_io_hfcpci(hc);
+	mISDN_freechannel(&hc->bch[1]);
+	mISDN_freechannel(&hc->bch[0]);
+	mISDN_freechannel(&hc->dch);
+	spin_unlock_irqrestore(&hc->lock, flags);
+	mISDN_ctrl(&hc->dch.inst, MGR_UNREGLAYER | REQUEST, NULL);
+	spin_lock_irqsave(&HFC_obj.lock, flags);
+	list_del(&hc->list);
+	spin_unlock_irqrestore(&HFC_obj.lock, flags);
+	kfree(hc);
+}
+
+static int
+HFC_manager(void *data, u_int prim, void *arg) {
+	hfc_pci_t	*card;
+	mISDNinstance_t	*inst = data;
+	struct sk_buff	*skb;
+	int		channel = -1;
+	u_long		flags;
+
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim,arg,&HFC_obj)
+		printk(KERN_ERR "%s: no data prim %x arg %p\n",
+			__FUNCTION__, prim, arg);
+		return(-EINVAL);
+	}
+	spin_lock_irqsave(&HFC_obj.lock, flags);
+	list_for_each_entry(card, &HFC_obj.ilist, list) {
+		if (&card->dch.inst == inst) {
+			channel = 2;
+			break;
+		}
+		if (&card->bch[0].inst == inst) {
+			channel = 0;
+			break;
+		}
+		if (&card->bch[1].inst == inst) {
+			inst = &card->bch[1].inst;
+			channel = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&HFC_obj.lock, flags);
+	if (channel<0) {
+		printk(KERN_ERR "%s: no channel data %p prim %x arg %p\n",
+			__FUNCTION__, data, prim, arg);
+		return(-EINVAL);
+	}
+
+	switch(prim) {
+	    case MGR_REGLAYER | CONFIRM:
+		if (channel == 2)
+			mISDN_setpara(&card->dch, &inst->st->para);
+		else
+			mISDN_setpara(&card->bch[channel], &inst->st->para);
+		break;
+	    case MGR_UNREGLAYER | REQUEST:
+		if ((skb = create_link_skb(PH_CONTROL | REQUEST,
+			HW_DEACTIVATE, 0, NULL, 0))) {
+			if (hfcpci_l2l1(inst, skb))
+				dev_kfree_skb(skb);
+		}
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+		break;
+	    case MGR_CLRSTPARA | INDICATION:
+		arg = NULL;
+	    case MGR_ADDSTPARA | INDICATION:
+		if (channel == 2)
+			mISDN_setpara(&card->dch, arg);
+		else
+			mISDN_setpara(&card->bch[channel], arg);
+		break;
+	    case MGR_RELEASE | INDICATION:
+		if (channel == 2) {
+			release_card(card);
+		} else {
+			HFC_obj.refcnt--;
+		}
+		break;
+#ifdef FIXME
+	    case MGR_CONNECT | REQUEST:
+		return(mISDN_ConnectIF(inst, arg));
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+		if (channel==2)
+			return(mISDN_SetIF(inst, arg, prim, HFCD_l1hw, NULL,
+				&card->dch));
+		else
+			return(mISDN_SetIF(inst, arg, prim, hfcpci_l2l1, NULL,
+				&card->bch[channel]));
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		return(mISDN_DisConnectIF(inst, arg));
+#endif
+	    case MGR_SELCHANNEL | REQUEST:
+		if (channel != 2) {
+			printk(KERN_WARNING "%s: selchannel not dinst\n",
+				__FUNCTION__);
+			return(-EINVAL);
+		}
+		return(SelFreeBChannel(card, arg));
+	    case MGR_SETSTACK | INDICATION:
+		if ((channel!=2) && (inst->pid.global == 2)) {
+			if ((skb = create_link_skb(PH_ACTIVATE | REQUEST, 0, 0, NULL, 0))) {
+				if (hfcpci_l2l1(inst, skb))
+					dev_kfree_skb(skb);
+			}
+			if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
+					0, 0, NULL, 0);
+			else
+				mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
+					0, 0, NULL, 0);
+		}
+		break;
+	    PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+	    PRIM_NOT_HANDLED(MGR_GLOBALOPT | REQUEST);
+	    default:
+		printk(KERN_WARNING "%s: prim %x not handled\n",
+			__FUNCTION__, prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+static int __init HFC_init(void)
+{
+	int		err,i;
+	hfc_pci_t	*card, *prev;
+	mISDN_pid_t	pid;
+	mISDNstack_t	*dst;
+	u_long		flags;
+
+#ifdef MODULE
+	HFC_obj.owner = THIS_MODULE;
+#endif
+	spin_lock_init(&HFC_obj.lock);
+	INIT_LIST_HEAD(&HFC_obj.ilist);
+	HFC_obj.name = HFCName;
+	HFC_obj.own_ctrl = HFC_manager;
+	HFC_obj.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0 |
+				     ISDN_PID_L0_NT_S0;
+	HFC_obj.DPROTO.protocol[1] = ISDN_PID_L1_NT_S0;
+	HFC_obj.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS |
+				     ISDN_PID_L1_B_64HDLC;
+	HFC_obj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS |
+				     ISDN_PID_L2_B_RAWDEV;
+	if ((err = mISDN_register(&HFC_obj))) {
+		printk(KERN_ERR "Can't register HFC PCI error(%d)\n", err);
+		return(err);
+	}
+	while (HFC_cnt < MAX_CARDS) {
+		if (!(card = kmalloc(sizeof(hfc_pci_t), GFP_ATOMIC))) {
+			printk(KERN_ERR "No kmem for HFCcard\n");
+			mISDN_unregister(&HFC_obj);
+			return(-ENOMEM);
+		}
+		memset(card, 0, sizeof(hfc_pci_t));
+		spin_lock_irqsave(&HFC_obj.lock, flags);
+		list_add_tail(&card->list, &HFC_obj.ilist);
+		spin_unlock_irqrestore(&HFC_obj.lock, flags);
+		card->dch.debug = debug;
+		spin_lock_init(&card->lock);
+		card->dch.inst.hwlock = &card->lock;
+		mISDN_init_instance(&card->dch.inst, &HFC_obj, card, hfcpci_l2l1);
+		card->dch.inst.pid.layermask = ISDN_LAYER(0);
+		sprintf(card->dch.inst.name, "HFC%d", HFC_cnt+1);
+		err = mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
+		card->dch.hw = card;
+		if (err) {
+			mISDN_unregister(&HFC_obj);
+			return(err);
+		}
+		for (i=0; i<2; i++) {
+			card->bch[i].channel = i + 1;
+			mISDN_init_instance(&card->bch[i].inst, &HFC_obj, card, hfcpci_l2l1);
+			card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
+			card->bch[i].inst.hwlock = &card->lock;
+			card->bch[i].debug = debug;
+			sprintf(card->bch[i].inst.name, "%s B%d",
+				card->dch.inst.name, i+1);
+			mISDN_initchannel(&card->bch[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM);
+			card->bch[i].hw = card;
+#ifdef FIXME
+			if (card->bch[i].dev) {
+				card->bch[i].dev->wport.pif.func =
+					hfcpci_l2l1;
+				card->bch[i].dev->wport.pif.fdata =
+					&card->bch[i];
+			}
+#endif
+		}
+		if (protocol[HFC_cnt] == 0x100) {
+			if (card->list.prev == &HFC_obj.ilist)
+				prev = NULL;
+			else
+				prev = list_entry(card->list.prev, hfc_pci_t, list);
+
+			if (!prev) {
+				int_errtxt("card(%d) no previous HFC",
+					HFC_cnt);
+				if (!HFC_cnt)
+					mISDN_unregister(&HFC_obj);
+				else
+					err = 0;
+				return(err);
+			}
+			i = HFC_cnt - 1;
+			test_and_set_bit(HFC_CFG_2HFC, &prev->cfg);
+			test_and_set_bit(HFC_CFG_2HFC, &card->cfg);
+			test_and_set_bit(HFC_CFG_SLAVEHFC, &card->cfg);
+		} else {
+			prev = NULL;
+			i = HFC_cnt;
+		}
+		mISDN_set_dchannel_pid(&pid, protocol[i], layermask[i]);
+		test_and_set_bit(HFC_CFG_MASTER, &card->cfg);
+		if (protocol[i] & 0x10) {
+			card->dch.inst.pid.protocol[0] = ISDN_PID_L0_NT_S0;
+			card->dch.inst.pid.protocol[1] = ISDN_PID_L1_NT_S0;
+			pid.protocol[0] = ISDN_PID_L0_NT_S0;
+			pid.protocol[1] = ISDN_PID_L1_NT_S0;
+			card->dch.inst.pid.layermask |= ISDN_LAYER(1);
+			pid.layermask |= ISDN_LAYER(1);
+			if (layermask[i] & ISDN_LAYER(2))
+				pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
+			card->hw.nt_mode = 1;
+		} else {
+			card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
+			card->hw.nt_mode = 0;
+		}
+		if (protocol[i] & 0x40) {
+			if (pid.layermask & ISDN_LAYER(3))
+				pid.protocol[3] |= ISDN_PID_L3_DF_EXTCID;
+			test_and_set_bit(HFC_CFG_PCM, &card->cfg);
+			test_and_set_bit(HFC_CFG_SLAVE, &card->cfg);
+			test_and_clear_bit(HFC_CFG_MASTER, &card->cfg);
+		}
+		if (protocol[i] & 0x80) {
+			test_and_set_bit(HFC_CFG_NEG_F0, &card->cfg);
+		}
+		if (protocol[i] & 0x200) {
+			test_and_set_bit(HFC_CFG_SW_DD_DU, &card->cfg);
+		}
+		printk(KERN_DEBUG "HFC card %p dch %p bch1 %p bch2 %p\n",
+			card, &card->dch, &card->bch[0], &card->bch[1]);
+		if (setup_hfcpci(card)) {
+			err = 0;
+			mISDN_freechannel(&card->dch);
+			mISDN_freechannel(&card->bch[1]);
+			mISDN_freechannel(&card->bch[0]);
+			spin_lock_irqsave(&HFC_obj.lock, flags);
+			list_del(&card->list);
+			spin_unlock_irqrestore(&HFC_obj.lock, flags);
+			kfree(card);
+			if (!HFC_cnt) {
+				mISDN_unregister(&HFC_obj);
+				err = -ENODEV;
+			} else
+				printk(KERN_INFO "HFC %d cards installed\n",
+					HFC_cnt);
+			return(err);
+		}
+		card->dch.inst.class_dev.dev = &card->hw.dev->dev;
+		HFC_cnt++;
+		if (prev) {
+			dst = prev->dch.inst.st;
+		} else {
+			if ((err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST,
+				&card->dch.inst))) {
+				printk(KERN_ERR  "MGR_ADDSTACK REQUEST dch err(%d)\n", err);
+				release_card(card);
+				if (!HFC_cnt)
+					mISDN_unregister(&HFC_obj);
+				else
+					err = 0;
+				return(err);
+			}
+			dst = card->dch.inst.st;
+		}
+		mISDN_ctrl(dst, MGR_STOPSTACK | REQUEST, NULL);
+		for (i = 0; i < 2; i++) {
+			card->bch[i].inst.class_dev.dev = &card->hw.dev->dev;
+			if ((err = mISDN_ctrl(dst, MGR_NEWSTACK | REQUEST, &card->bch[i].inst))) {
+				printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
+				mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+				if (!HFC_cnt)
+					mISDN_unregister(&HFC_obj);
+				else
+					err = 0;
+				return(err);
+			}
+		}
+		if (protocol[HFC_cnt] != 0x100) { /* next not second HFC */
+			if ((err = mISDN_ctrl(dst, MGR_SETSTACK | REQUEST, &pid))) {
+				printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n",
+					err);
+				mISDN_ctrl(dst, MGR_DELSTACK | REQUEST, NULL);
+				if (!HFC_cnt)
+					mISDN_unregister(&HFC_obj);
+				else
+					err = 0;
+				return(err);
+			}
+		}
+		if ((err = init_card(card))) {
+			mISDN_ctrl(dst, MGR_DELSTACK | REQUEST, NULL);
+			if (!HFC_cnt)
+				mISDN_unregister(&HFC_obj);
+			else
+				err = 0;
+			return(err);
+		}
+		mISDN_ctrl(dst, MGR_STARTSTACK | REQUEST, NULL);
+		mISDN_ctrl(dst, MGR_CTRLREADY | INDICATION, NULL);
+	}
+	mISDN_module_register(THIS_MODULE);
+	printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt);
+	return(0);
+}
+
+#ifdef MODULE
+static void __exit HFC_cleanup(void)
+{
+	hfc_pci_t	*card, *next;
+	int		err;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if ((err = mISDN_unregister(&HFC_obj))) {
+		printk(KERN_ERR "Can't unregister HFC PCI error(%d)\n", err);
+	}
+	list_for_each_entry_safe(card, next, &HFC_obj.ilist, list) {
+		printk(KERN_ERR "HFC PCI card struct not empty refs %d\n",
+			HFC_obj.refcnt);
+		release_card(card);
+	}
+	return;
+}
+
+module_init(HFC_init);
+module_exit(HFC_cleanup);
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_pci.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_pci.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfc_pci.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,243 @@
+/* $Id: hfc_pci.h,v 1.3 2003/06/21 21:39:54 kkeil Exp $
+ *
+ *  specific defines for CCD's HFC 2BDS0 PCI chips
+ *
+ * Author     Werner Cornelius (werner at isdn4linux.de)      
+ *
+ * Copyright 1999  by Werner Cornelius (werner at 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.
+ *
+ */
+
+/*********************************************/
+/* thresholds for transparent B-channel mode */
+/* change mask and threshold simultaneously  */
+/*********************************************/
+#define HFCPCI_BTRANS_THRESHOLD 128
+#define HFCPCI_BTRANS_THRESMASK 0x00
+
+
+
+/* defines for PCI config */
+
+#define PCI_ENA_MEMIO    0x02
+#define PCI_ENA_MASTER   0x04
+
+
+/* GCI/IOM bus monitor registers */
+
+#define HCFPCI_C_I       0x08
+#define HFCPCI_TRxR      0x0C
+#define HFCPCI_MON1_D    0x28
+#define HFCPCI_MON2_D    0x2C
+
+
+/* GCI/IOM bus timeslot registers */
+
+#define HFCPCI_B1_SSL    0x80
+#define HFCPCI_B2_SSL    0x84
+#define HFCPCI_AUX1_SSL  0x88
+#define HFCPCI_AUX2_SSL  0x8C
+#define HFCPCI_B1_RSL    0x90
+#define HFCPCI_B2_RSL    0x94
+#define HFCPCI_AUX1_RSL  0x98
+#define HFCPCI_AUX2_RSL  0x9C
+
+/* GCI/IOM bus data registers */
+
+#define HFCPCI_B1_D      0xA0
+#define HFCPCI_B2_D      0xA4
+#define HFCPCI_AUX1_D    0xA8
+#define HFCPCI_AUX2_D    0xAC
+
+/* GCI/IOM bus configuration registers */
+
+#define HFCPCI_MST_EMOD  0xB4
+#define HFCPCI_MST_MODE	 0xB8
+#define HFCPCI_CONNECT 	 0xBC
+
+
+/* Interrupt and status registers */
+
+#define HFCPCI_FIFO_EN   0x44
+#define HFCPCI_TRM       0x48
+#define HFCPCI_B_MODE    0x4C
+#define HFCPCI_CHIP_ID   0x58
+#define HFCPCI_CIRM  	 0x60
+#define HFCPCI_CTMT	 0x64
+#define HFCPCI_INT_M1  	 0x68
+#define HFCPCI_INT_M2  	 0x6C
+#define HFCPCI_INT_S1  	 0x78
+#define HFCPCI_INT_S2  	 0x7C
+#define HFCPCI_STATUS  	 0x70
+
+/* S/T section registers */
+
+#define HFCPCI_STATES  	 0xC0
+#define HFCPCI_SCTRL  	 0xC4
+#define HFCPCI_SCTRL_E   0xC8
+#define HFCPCI_SCTRL_R   0xCC
+#define HFCPCI_SQ  	 0xD0
+#define HFCPCI_CLKDEL  	 0xDC
+#define HFCPCI_B1_REC    0xF0
+#define HFCPCI_B1_SEND   0xF0
+#define HFCPCI_B2_REC    0xF4
+#define HFCPCI_B2_SEND   0xF4
+#define HFCPCI_D_REC     0xF8
+#define HFCPCI_D_SEND    0xF8
+#define HFCPCI_E_REC     0xFC
+
+
+/* bits in status register (READ) */
+#define HFCPCI_PCI_PROC   0x02
+#define HFCPCI_NBUSY	  0x04 
+#define HFCPCI_TIMER_ELAP 0x10
+#define HFCPCI_STATINT	  0x20
+#define HFCPCI_FRAMEINT	  0x40
+#define HFCPCI_ANYINT	  0x80
+
+/* bits in CTMT (Write) */
+#define HFCPCI_CLTIMER    0x80
+#define HFCPCI_TIM3_125   0x04
+#define HFCPCI_TIM25      0x10
+#define HFCPCI_TIM50      0x14
+#define HFCPCI_TIM400     0x18
+#define HFCPCI_TIM800     0x1C
+#define HFCPCI_AUTO_TIMER 0x20
+#define HFCPCI_TRANSB2    0x02
+#define HFCPCI_TRANSB1    0x01
+
+/* bits in CIRM (Write) */
+#define HFCPCI_AUX_MSK    0x07
+#define HFCPCI_RESET  	  0x08
+#define HFCPCI_B1_REV     0x40
+#define HFCPCI_B2_REV     0x80
+
+/* bits in INT_M1 and INT_S1 */
+#define HFCPCI_INTS_B1TRANS  0x01
+#define HFCPCI_INTS_B2TRANS  0x02
+#define HFCPCI_INTS_DTRANS   0x04
+#define HFCPCI_INTS_B1REC    0x08
+#define HFCPCI_INTS_B2REC    0x10
+#define HFCPCI_INTS_DREC     0x20
+#define HFCPCI_INTS_L1STATE  0x40
+#define HFCPCI_INTS_TIMER    0x80
+
+/* bits in INT_M2 */
+#define HFCPCI_PROC_TRANS    0x01
+#define HFCPCI_GCI_I_CHG     0x02
+#define HFCPCI_GCI_MON_REC   0x04
+#define HFCPCI_IRQ_ENABLE    0x08
+#define HFCPCI_PMESEL        0x80
+
+/* bits in STATES */
+#define HFCPCI_STATE_MSK     0x0F
+#define HFCPCI_LOAD_STATE    0x10
+#define HFCPCI_ACTIVATE	     0x20
+#define HFCPCI_DO_ACTION     0x40
+#define HFCPCI_NT_G2_G3      0x80
+
+/* bits in HFCD_MST_MODE */
+#define HFCPCI_MASTER	     0x01
+#define HFCPCI_SLAVE         0x00
+#define HFCPCI_F0IO_POSITIV  0x02
+#define HFCPCI_F0_NEGATIV    0x04
+#define HFCPCI_F0_2C4        0x08
+/* remaining bits are for codecs control */
+
+/* bits in HFCD_SCTRL */
+#define SCTRL_B1_ENA	     0x01
+#define SCTRL_B2_ENA	     0x02
+#define SCTRL_MODE_TE        0x00
+#define SCTRL_MODE_NT        0x04
+#define SCTRL_LOW_PRIO	     0x08
+#define SCTRL_SQ_ENA	     0x10
+#define SCTRL_TEST	     0x20
+#define SCTRL_NONE_CAP	     0x40
+#define SCTRL_PWR_DOWN	     0x80
+
+/* bits in SCTRL_E  */
+#define HFCPCI_AUTO_AWAKE    0x01
+#define HFCPCI_DBIT_1        0x04
+#define HFCPCI_IGNORE_COL    0x08
+#define HFCPCI_CHG_B1_B2     0x80
+
+/****************************/
+/* bits in FIFO_EN register */
+/****************************/
+#define HFCPCI_FIFOEN_B1     0x03
+#define HFCPCI_FIFOEN_B2     0x0C
+#define HFCPCI_FIFOEN_DTX    0x10
+#define HFCPCI_FIFOEN_B1TX   0x01
+#define HFCPCI_FIFOEN_B1RX   0x02
+#define HFCPCI_FIFOEN_B2TX   0x04
+#define HFCPCI_FIFOEN_B2RX   0x08
+
+
+/***********************************/
+/* definitions of fifo memory area */
+/***********************************/
+#define MAX_D_FRAMES 15
+#define MAX_B_FRAMES 31
+#define B_SUB_VAL    0x200
+#define B_FIFO_SIZE  (0x2000 - B_SUB_VAL)
+#define D_FIFO_SIZE  512
+#define D_FREG_MASK  0xF
+
+typedef struct {
+	unsigned short z1;  /* Z1 pointer 16 Bit */
+	unsigned short z2;  /* Z2 pointer 16 Bit */
+} z_type;
+
+typedef struct {
+	u_char data[D_FIFO_SIZE]; /* FIFO data space */
+	u_char fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */
+	u_char f1,f2; /* f pointers */
+	u_char fill2[0x20C0-0x20A2]; /* reserved, do not use */
+	z_type za[MAX_D_FRAMES+1]; /* mask index with D_FREG_MASK for access */
+	u_char fill3[0x4000-0x2100]; /* align 16K */  
+} dfifo_type;
+
+typedef struct {
+	z_type za[MAX_B_FRAMES+1]; /* only range 0x0..0x1F allowed */ 
+	u_char f1,f2; /* f pointers */
+	u_char fill[0x2100-0x2082]; /* alignment */
+} bzfifo_type;
+
+
+typedef union {
+	struct { 
+		dfifo_type d_tx; /* D-send channel */
+		dfifo_type d_rx; /* D-receive channel */
+	} d_chan; 
+	struct {
+		u_char fill1[0x200];
+		u_char txdat_b1[B_FIFO_SIZE];
+		bzfifo_type txbz_b1;
+		bzfifo_type txbz_b2;
+		u_char txdat_b2[B_FIFO_SIZE];
+		u_char fill2[D_FIFO_SIZE];
+		u_char rxdat_b1[B_FIFO_SIZE];
+		bzfifo_type rxbz_b1;
+		bzfifo_type rxbz_b2;
+		u_char rxdat_b2[B_FIFO_SIZE];
+	} b_chans;  
+	u_char fill[32768]; 
+} fifo_area;
+
+#define Write_hfc(a,b,c) (*(((u_char *)a->hw.pci_io)+b) = c) 
+#define Read_hfc(a,b) (*(((u_char *)a->hw.pci_io)+b))
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_mini.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_mini.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_mini.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1878 @@
+/* $Id: hfcs_mini.c,v 1.10 2007/02/13 10:43:45 crich Exp $
+ *
+ * mISDN driver for Colognechip HFC-S mini Evaluation Card
+ *
+ * Authors : Martin Bachem, Joerg Ciesielski
+ * Contact : info at colognechip.com
+ *
+ * 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.
+ *
+ *******************************************************************************
+ *
+ * MODULE PARAMETERS:
+ * (NOTE: layermask and protocol must be given for all ports,
+ *  not for the number of cards.)
+ *
+ * - protocol=<p1>[,p2,p3...]
+ *   Values:
+ *      <bit  3 -  0>  D-channel protocol id
+ *      <bit  4 -  4>  Flags for special features
+ *      <bit 31 -  5>  Spare (set to 0)
+ *
+ *        D-channel protocol ids
+ *        - 1       1TR6 (not released yet)
+ *        - 2       DSS1
+ *
+ *        Feature Flags
+ *        <bit 4>   0x0010  Net side stack (NT mode)
+ *        <bit 5>   0x0020  PCI mode (0=master, 1=slave)
+ *        <bit 6>   0x0040  not in use
+ *        <bit 7>   0x0080  B channel loop (for layer1 tests)
+ *
+ * - layermask=<l1>[,l2,l3...] (32bit):
+ *        mask of layers to be used for D-channel stack
+ *
+ * - debug:
+ *        enable debugging (see hfcs_mini.h for debug options)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <asm/timex.h>
+#include "core.h"
+#include "layer1.h"
+#include "debug.h"
+#include "hfcs_mini.h"
+#include "hfcsmcc.h"
+
+#if HFCBRIDGE == BRIDGE_HFCPCI
+#include <linux/pci.h>
+#endif
+
+static const char hfcsmini_rev[] = "$Revision: 1.10 $";
+
+#define MAX_CARDS	8
+static int card_cnt;
+static u_int protocol[MAX_CARDS];
+static int layermask[MAX_CARDS];
+
+static mISDNobject_t hw_mISDNObj;
+static int debug = 0;
+
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#define MODULE_PARM_T   "1-4i"
+MODULE_PARM(protocol, MODULE_PARM_T);
+MODULE_PARM(layermask, MODULE_PARM_T);
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+
+#ifdef OLD_MODULE_PARAM_ARRAY
+static int num_protocol=0, num_layermask=0;
+module_param_array(protocol, uint, num_protocol, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, num_layermask, S_IRUGO | S_IWUSR);
+#else
+module_param_array(protocol, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, NULL, S_IRUGO | S_IWUSR);
+#endif
+#endif
+#endif
+
+#if HFCBRIDGE == BRIDGE_HFCPCI
+
+static inline void
+hfcsmini_sel_reg(hfcsmini_hw * hw, __u8 reg_addr)
+{
+	outb(6, hw->iobase + 3); /* A0 = 1, reset = 1 */
+	outb(reg_addr, hw->iobase + 1); /* write register number */
+	outb(4, hw->iobase + 3); /* A0 = 0, reset = 1 */
+}
+
+
+static inline __u8
+read_hfcsmini(hfcsmini_hw * hw, __u8 reg_addr)
+{
+	register u_char ret;
+	
+#ifdef SPIN_LOCK_HFCSMINI_REGISTER
+	spin_lock_irq(&hw->rlock);
+#endif
+	hfcsmini_sel_reg(hw, reg_addr);
+	ret = inb(hw->iobase + 1);
+#ifdef SPIN_LOCK_HFCSMINI_REGISTER	
+	spin_unlock_irq(&hw->rlock);
+#endif	
+	return(ret);
+}
+
+
+/* read register in already spin-locked irq context */
+static inline __u8
+read_hfcsmini_irq(hfcsmini_hw * hw, __u8 reg_addr)
+{
+	register u_char ret;
+	hfcsmini_sel_reg(hw, reg_addr);
+	ret = inb(hw->iobase + 1);
+	return(ret);
+}
+
+
+static inline __u8  
+read_hfcsmini_stable(hfcsmini_hw * hw, __u8 reg_addr)
+{
+	register u_char in1, in2; 
+
+#ifdef SPIN_LOCK_HFCSMINI_REGISTER
+	spin_lock_irq(&hw->rlock);
+#endif
+	hfcsmini_sel_reg(hw, reg_addr);
+
+	in1 = inb(hw->iobase + 1);
+	// loop until 2 equal accesses
+	while((in2=inb(hw->iobase + 1))!=in1) in1=in2;
+	
+#ifdef SPIN_LOCK_HFCSMINI_REGISTER	
+	spin_unlock_irq(&hw->rlock);
+#endif	
+	return(in1);
+}
+
+
+static inline void
+write_hfcsmini(hfcsmini_hw * hw, __u8 reg_addr, __u8 value)
+{
+#ifdef SPIN_LOCK_HFCSMINI_REGISTER
+	spin_lock_irq(&hw->rlock);
+#endif
+	hfcsmini_sel_reg(hw, reg_addr);
+	outb(value, hw->iobase + 1);
+#ifdef SPIN_LOCK_HFCSMINI_REGISTER	
+	spin_unlock_irq(&hw->rlock);
+#endif	
+}
+
+#endif
+
+
+static void
+hfcsmini_ph_command(channel_t * dch, u_char command)
+{
+	hfcsmini_hw *hw = dch->hw;
+	
+	if (dch->debug)
+		mISDN_debugprint(&dch->inst,
+				 "%s command(%i) channel(%i)",
+				 __FUNCTION__, command, dch->channel);
+
+	switch (command) {
+		case HFC_L1_ACTIVATE_TE:
+			if ((dch->debug) & (debug & DEBUG_HFC_S0_STATES)) {
+				mISDN_debugprint(&dch->inst,
+						 "HFC_L1_ACTIVATE_TE channel(%i) command(%i)",
+						 dch->channel, command);
+			}
+
+			write_hfcsmini(hw, R_ST_WR_STA, (M_ST_LD_STA | (M1_ST_SET_STA*4)));
+			udelay(125); /* to be sure INFO1 signals are sent */
+			write_hfcsmini(hw, R_ST_WR_STA, (M1_ST_SET_STA * 4));
+			break;
+			
+		case HFC_L1_FORCE_DEACTIVATE_TE:
+			write_hfcsmini(hw, R_ST_WR_STA, (M_ST_LD_STA | (M1_ST_SET_STA*3)));
+			udelay(7); /* wait at least 5,21 us */
+			write_hfcsmini(hw, R_ST_WR_STA, (M1_ST_SET_STA*3));
+			break;
+			
+
+		case HFC_L1_ACTIVATE_NT:
+			if ((dch->debug) & (debug & DEBUG_HFC_S0_STATES))
+				mISDN_debugprint(&dch->inst,
+					 "HFC_L1_ACTIVATE_NT channel(%i)");
+
+			write_hfcsmini(hw, R_ST_WR_STA, (M1_ST_ACT | M_SET_G2_G3));
+			break;
+
+		case HFC_L1_DEACTIVATE_NT:
+			if ((dch->debug) & (debug & DEBUG_HFC_S0_STATES))
+				mISDN_debugprint(&dch->inst,
+						 "HFC_L1_DEACTIVATE_NT channel(%i)");
+
+			write_hfcsmini(hw, R_ST_WR_STA, (M1_ST_ACT * 2));
+			break;
+			
+		case HFC_L1_TESTLOOP_B1:
+			break;
+			
+		case HFC_L1_TESTLOOP_B2:
+			break;
+
+	}
+}
+
+
+/*********************************/
+/* S0 state change event handler */
+/*********************************/
+static void
+s0_new_state(channel_t * dch)
+{
+	u_int prim = PH_SIGNAL | INDICATION;
+	u_int para = 0;
+	hfcsmini_hw *hw = dch->hw;
+
+	if (hw->portmode & PORT_MODE_TE) {
+		if ((dch->debug) & (debug & DEBUG_HFC_S0_STATES))
+			mISDN_debugprint(&dch->inst,
+					 "%s: TE %d",
+					 __FUNCTION__, dch->state);
+
+		switch (dch->state) {
+			case (0):
+				prim = PH_CONTROL | INDICATION;
+				para = HW_RESET;
+				break;
+			case (3):
+				prim = PH_CONTROL | INDICATION;
+				para = HW_DEACTIVATE;
+				break;
+			case (6):
+				para = INFO2;
+				break;
+			case (7):
+				para = INFO4_P8;
+				break;
+			case (5):
+			case (8):
+				para = ANYSIGNAL;
+				break;
+			default:
+				return;
+		}
+		if (dch->state== 7)
+			test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+		else
+			test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+	} // PORT_MODE_TE
+
+	if (hw->portmode & PORT_MODE_NT) {
+		if ((dch->debug) & (debug & DEBUG_HFC_S0_STATES))
+			mISDN_debugprint(&dch->inst,
+					 "%s: NT %d",
+					 __FUNCTION__, dch->state);
+
+		switch (dch->state) {
+			case (1):
+				hw->nt_timer = 0;
+				hw->portmode &= ~NT_TIMER;
+				prim = PH_DEACTIVATE | INDICATION;
+				test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+				para = 0;
+				break;
+			case (2):
+				if (hw->nt_timer < 0) {
+					hw->nt_timer = 0;
+					hw->portmode &= ~NT_TIMER;
+					hfcsmini_ph_command(dch,
+							HFC_L1_DEACTIVATE_NT);
+				} else {
+					hw->nt_timer = NT_T1_COUNT;
+					hw->portmode |= NT_TIMER;
+					write_hfcsmini(hw, R_ST_WR_STA, M_SET_G2_G3);
+				}
+				return;
+			case (3):
+				hw->nt_timer = 0;
+				hw->portmode &= ~NT_TIMER;
+				prim = PH_ACTIVATE | INDICATION;
+				test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+				para = 0;
+				break;
+			case (4):
+				hw->nt_timer = 0;
+				hw->portmode &= ~NT_TIMER;
+				return;
+			default:
+				break;
+		}
+	} // PORT_MODE_NT
+	mISDN_queue_data(&dch->inst, FLG_MSG_UP, prim, para, 0, NULL, 0);
+}
+
+/*************************************/
+/* Layer 1 D-channel hardware access */
+/*************************************/
+static int
+handle_dmsg(channel_t *dch, struct sk_buff *skb)
+{
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	hfcsmini_hw	*hw = dch->hw;
+	u_long		flags;
+		
+	if (hh->prim == (PH_SIGNAL | REQUEST)) {
+		ret = -EINVAL;
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		spin_lock_irqsave(&hw->rlock, flags);
+		if (hh->dinfo == HW_RESET) {
+			if (dch->state != 0)
+				hfcsmini_ph_command(dch, HFC_L1_ACTIVATE_TE);
+			spin_unlock_irqrestore(&hw->rlock, flags);
+			skb_trim(skb, 0);
+			return(mISDN_queueup_newhead(&dch->inst, 0, PH_CONTROL | INDICATION,HW_POWERUP, skb));
+		} else if (hh->dinfo == HW_DEACTIVATE) {
+			if (dch->next_skb) {
+				dev_kfree_skb(dch->next_skb);
+				dch->next_skb = NULL;
+			}
+			test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+#ifdef FIXME
+			if (test_and_clear_bit(FLG_L1_DBUSY, &dch->Flags))
+				dchannel_sched_event(dch, D_CLEARBUSY);
+#endif
+		} else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) {
+			if (1 & hh->dinfo)
+				hfcsmini_ph_command(dch, HFC_L1_TESTLOOP_B1);
+				
+			if (2 & hh->dinfo)
+				hfcsmini_ph_command(dch, HFC_L1_TESTLOOP_B2);
+				
+		} else if (hh->dinfo == HW_POWERUP) {
+			hfcsmini_ph_command(dch, HFC_L1_FORCE_DEACTIVATE_TE);
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst,
+					"hfcsmini_l1hw unknown ctrl %x",
+					hh->dinfo);
+			ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(&hw->rlock, flags);
+	} else if (hh->prim == (PH_ACTIVATE | REQUEST)) {
+		spin_lock_irqsave(&hw->rlock, flags);
+		if (hw->portmode & PORT_MODE_NT) {
+			hfcsmini_ph_command(dch, HFC_L1_ACTIVATE_NT);
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst,
+					"%s: PH_ACTIVATE none NT mode",
+					__FUNCTION__);
+			ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(&hw->rlock, flags);
+	} else if (hh->prim == (PH_DEACTIVATE | REQUEST)) {
+		spin_lock_irqsave(&hw->rlock, flags);
+		if (hw->portmode & PORT_MODE_NT) {
+			hfcsmini_ph_command(dch, HFC_L1_DEACTIVATE_NT);
+			if (test_and_clear_bit(FLG_TX_NEXT, &dch->Flags)) {
+				dev_kfree_skb(dch->next_skb);
+				dch->next_skb = NULL;
+			}
+			if (dch->tx_skb) {
+				dev_kfree_skb(dch->tx_skb);
+				dch->tx_skb = NULL;
+			}
+			dch->tx_idx = 0;
+			if (dch->rx_skb) {
+				dev_kfree_skb(dch->rx_skb);
+				dch->rx_skb = NULL;
+			}
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+			test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst,
+					"%s: PH_DEACTIVATE none NT mode",
+					__FUNCTION__);
+			ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(&hw->rlock, flags);
+	} else if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS) {
+		u_int temp = hh->dinfo & SSTATUS_ALL; // remove SSTATUS_BROADCAST_BIT
+		if ((hw->portmode & PORT_MODE_NT) &&
+			(temp == SSTATUS_ALL || temp == SSTATUS_L1)) {
+			if (hh->dinfo & SSTATUS_BROADCAST_BIT)
+				temp = dch->inst.id | MSG_BROADCAST;
+			else
+				temp = hh->addr | FLG_MSG_TARGET;
+			skb_trim(skb, 0);
+			hh->dinfo = test_bit(FLG_ACTIVE, &dch->Flags) ?
+				SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED;
+			hh->prim = MGR_SHORTSTATUS | CONFIRM;
+			return(mISDN_queue_message(&dch->inst, temp, skb));
+		}
+		ret = -EOPNOTSUPP;
+	} else {
+		printk(KERN_WARNING "%s %s: unknown prim(%x)\n",
+		       hw->card_name, __FUNCTION__, hh->prim);
+		ret = -EAGAIN;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return (ret);
+}
+
+/*************************************/
+/* Layer 1 B-channel hardware access */
+/*************************************/
+static int
+handle_bmsg(channel_t *bch, struct sk_buff *skb)
+{
+	hfcsmini_hw 	*hw = bch->hw;
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_ESTABLISH | REQUEST))) {
+		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
+			spin_lock_irqsave(&hw->rlock, flags);
+			ret = setup_channel(hw, bch->channel,
+				bch->inst.pid.protocol[1]);
+			if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				test_and_set_bit(FLG_L2DATA, &bch->Flags);
+			spin_unlock_irqrestore(&hw->rlock, flags);
+		}
+#ifdef FIXME
+		if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+			if (bch->dev)
+				if_link(&bch->dev->rport.pif,
+					hh->prim | CONFIRM, 0, 0, NULL, 0);
+#endif
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, ret, skb));
+	} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_RELEASE | REQUEST)) ||
+		((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
+		   	
+		spin_lock_irqsave(&hw->rlock, flags);
+		if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+			dev_kfree_skb(bch->next_skb);
+			bch->next_skb = NULL;
+		}
+		if (bch->tx_skb) {
+			dev_kfree_skb(bch->tx_skb);
+			bch->tx_skb = NULL;
+		}
+		bch->tx_idx = 0;
+		if (bch->rx_skb) {
+			dev_kfree_skb(bch->rx_skb);
+			bch->rx_skb = NULL;
+		}
+		test_and_clear_bit(FLG_L2DATA, &bch->Flags);
+		test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		setup_channel(hw, bch->channel, ISDN_PID_NONE);
+		test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+		spin_unlock_irqrestore(&hw->rlock, flags);
+		skb_trim(skb, 0);
+		if (hh->prim != (PH_CONTROL | REQUEST)) {
+#ifdef FIXME
+			if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+				if (bch->dev)
+					if_link(&bch->dev->rport.pif,
+						hh->prim | CONFIRM, 0, 0, NULL, 0);
+#endif
+			if (!mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, 0, skb))
+				return(0);
+		}
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		// do not handle PH_CONTROL | REQUEST ??
+	} else {
+		printk(KERN_WARNING "%s %s: unknown prim(%x)\n",
+			hw->card_name, __FUNCTION__, hh->prim);
+		ret = -EAGAIN;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return (ret);
+}
+
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+static int
+hfcsmini_l2l1(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*chan = container_of(inst, channel_t, inst);
+	hfcsmini_hw	*hw = chan->hw;
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		ret = channel_senddata(chan, hh->dinfo, skb);
+		if (ret > 0) { /* direct TX */
+			tasklet_schedule(&hw->tasklet);
+			ret = 0;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		return(ret);
+	} 
+	if (test_bit(FLG_DCHANNEL, &chan->Flags)) {
+		ret = handle_dmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (test_bit(FLG_BCHANNEL, &chan->Flags)) {
+		ret = handle_bmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+
+static int
+hfcsmini_manager(void *data, u_int prim, void *arg)
+{
+	hfcsmini_hw *hw = NULL;
+	mISDNinstance_t *inst = data;
+	struct sk_buff *skb;
+	int channel = -1;
+	int i;
+	channel_t *chan = NULL;
+	u_long flags;
+
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim, arg, &hw_mISDNObj)
+		    printk(KERN_ERR "%s %s: no data prim %x arg %p\n",
+			   hw->card_name, __FUNCTION__, prim, arg);
+		return (-EINVAL);
+	}
+	
+	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+
+	/* find channel and card */
+	list_for_each_entry(hw, &hw_mISDNObj.ilist, list) {
+		i = 0;
+		while (i < MAX_CHAN) {
+			if (hw->chan[i].Flags &&
+				&hw->chan[i].inst == inst) {
+				channel = i;
+				chan = &hw->chan[i];
+				break;
+			}
+			i++;
+		}
+		if (channel >= 0)
+			break;
+	}
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+	
+	if (channel < 0) {
+		printk(KERN_ERR
+		       "%s: no card/channel found  data %p prim %x arg %p\n",
+		       __FUNCTION__, data, prim, arg);
+		return (-EINVAL);
+	}
+
+	switch (prim) {
+		case MGR_REGLAYER | CONFIRM:
+			mISDN_setpara(chan, &inst->st->para);
+			break;
+		case MGR_UNREGLAYER | REQUEST:
+			if ((skb = create_link_skb(PH_CONTROL | REQUEST,
+				HW_DEACTIVATE, 0, NULL, 0))) {
+				if (hfcsmini_l2l1(inst, skb))
+					dev_kfree_skb(skb);
+			} else
+				printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
+			mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+			break;
+		case MGR_CLRSTPARA | INDICATION:
+			arg = NULL;
+		case MGR_ADDSTPARA | INDICATION:
+			mISDN_setpara(chan, arg);
+			break;
+		case MGR_RELEASE | INDICATION:
+			if (channel == 2) {
+				release_card(hw);
+			} else {
+				hw_mISDNObj.refcnt--;
+			}
+			break;
+		case MGR_SETSTACK | INDICATION:
+			if ((channel != 2) && (inst->pid.global == 2)) {
+				if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
+					0, 0, NULL, 0))) {
+					if (hfcsmini_l2l1(inst, skb))
+						dev_kfree_skb(skb);
+				}
+				if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+					mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
+						0, 0, NULL, 0);
+				else
+					mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
+						0, 0, NULL, 0);
+			}
+			break;
+		case MGR_GLOBALOPT | REQUEST:
+			if (arg) {
+				// FIXME: detect cards with HEADSET
+				u_int *gopt = arg;
+				*gopt = GLOBALOPT_INTERNAL_CTRL |
+				    GLOBALOPT_EXTERNAL_EQUIPMENT |
+				    GLOBALOPT_HANDSET;
+			} else
+				return (-EINVAL);
+			break;
+		case MGR_SELCHANNEL | REQUEST:
+			// no special procedure
+			return (-EINVAL);
+			PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+		default:
+			printk(KERN_WARNING "%s %s: prim %x not handled\n",
+			       hw->card_name, __FUNCTION__, prim);
+			return (-EINVAL);
+	}
+	return (0);
+}
+
+
+/***********************************/
+/* check if new buffer for channel */
+/* is waitinng is transmitt queue  */
+/***********************************/
+int
+next_tx_frame(hfcsmini_hw * hw, __u8 channel)
+{
+	channel_t *ch = &hw->chan[channel];
+
+	if (ch->tx_skb)
+		dev_kfree_skb(ch->tx_skb);
+	if (test_and_clear_bit(FLG_TX_NEXT, &ch->Flags)) {
+		ch->tx_skb = ch->next_skb;
+		if (ch->tx_skb) {
+			mISDN_head_t *hh = mISDN_HEAD_P(ch->tx_skb);
+			ch->next_skb = NULL;
+			test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
+			ch->tx_idx = 0;
+			queue_ch_frame(ch, CONFIRM, hh->dinfo, NULL);
+			return (1);
+		} else {
+			printk(KERN_WARNING
+			       "%s channel(%i) TX_NEXT without skb\n",
+			       hw->card_name, channel);
+			test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
+		}
+	} else
+		ch->tx_skb = NULL;
+	test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
+	return (0);
+}
+
+static inline void
+hfcsmini_waitbusy(hfcsmini_hw *hw)
+{
+	while (read_hfcsmini(hw, R_STATUS) & M_BUSY);
+}
+
+
+static inline void
+hfcsmini_selfifo(hfcsmini_hw *hw, __u8 fifo)
+{
+	write_hfcsmini(hw, R_FIFO, fifo);
+	hfcsmini_waitbusy(hw);
+}
+
+
+static inline void
+hfcsmini_inc_f(hfcsmini_hw *hw)
+{
+	write_hfcsmini(hw, A_INC_RES_FIFO, M_INC_F);
+	hfcsmini_waitbusy(hw);
+}
+
+
+static inline void
+hfcsmini_resetfifo(hfcsmini_hw *hw)
+{
+	write_hfcsmini(hw, A_INC_RES_FIFO, M_RES_FIFO);
+	hfcsmini_waitbusy(hw);
+}
+
+
+/**************************/
+/* fill fifo with TX data */
+/**************************/
+void
+hfcsmini_write_fifo(hfcsmini_hw *hw, __u8 channel)
+{
+	__u8		fcnt, tcnt, i;
+	__u8		free;
+	__u8		f1, f2;
+	__u8		fstat;
+	__u8		*data;
+	int		remain;
+	channel_t	*ch = &hw->chan[channel];
+
+send_buffer:
+	if (!ch->tx_skb)
+		return;
+	remain = ch->tx_skb->len - ch->tx_idx;
+	if (remain <= 0)
+		return;
+	hfcsmini_selfifo(hw, (channel * 2));
+	free = (hw->max_z - (read_hfcsmini_stable(hw, A_USAGE)));
+	tcnt = (free >= remain) ? remain : free;
+
+	fstat = read_hfcsmini(hw, R_ST_RD_STA);
+	f1 = read_hfcsmini_stable(hw, A_F1);
+	f2 = read_hfcsmini(hw, A_F2);
+	fcnt = 0x07 - ((f1 - f2) & 0x07);	/* free frame count in tx fifo */
+
+	if (debug & DEBUG_HFC_FIFO) {
+		mISDN_debugprint(&ch->inst,
+			"%s channel(%i) len(%i) idx(%i) f1(%i) "
+			"f2(%i) fcnt(%i) tcnt(%i) free(%i) fstat(%i)",
+			__FUNCTION__, channel, ch->tx_skb->len, ch->tx_idx,
+			f1, f2, fcnt, tcnt, free, fstat);
+	}
+
+	if (free && fcnt && tcnt) {
+		data = ch->tx_skb->data + ch->tx_idx;
+		ch->tx_idx += tcnt;
+
+		if (debug & DEBUG_HFC_FIFO) {
+			printk(KERN_DEBUG "%s channel(%i) writing: ",
+				hw->card_name, channel);
+		}
+		i = tcnt;
+		/* write data to Fifo */
+		while (i--) {
+			if (debug & DEBUG_HFC_FIFO)
+				printk("%02x ", *data);
+			write_hfcsmini(hw, A_FIFO_DATA, *data++);
+		}
+		if (debug & DEBUG_HFC_FIFO)
+			printk("\n");
+			
+		if (ch->tx_idx == ch->tx_skb->len) {
+			if (test_bit(FLG_HDLC, &ch->Flags)) {
+				/* terminate frame */
+				hfcsmini_inc_f(hw);
+			} else {
+				hfcsmini_selfifo(hw, (channel * 2));
+			}
+			if (debug & DEBUG_HFC_BTRACE)
+				mISDN_debugprint(&ch->inst,
+					"TX frame channel(%i) completed",
+					channel);
+			if (next_tx_frame(hw, channel)) {
+				if (debug & DEBUG_HFC_BTRACE)
+					mISDN_debugprint(&ch->inst,
+						"channel(%i) has next_tx_frame",
+						channel);
+				if ((free - tcnt) > 8) {
+					if (debug & DEBUG_HFC_BTRACE)
+						mISDN_debugprint(&ch->inst,
+							"channel(%i) continue B-TX immediatetly",
+							channel);
+					goto send_buffer;
+				}
+			}
+		} else {
+			/* tx buffer not complete, but fifo filled to maximum */
+			hfcsmini_selfifo(hw, (channel * 2));
+		}
+	}
+}
+
+
+/****************************/
+/* read RX data out of fifo */
+/****************************/
+void
+hfcsmini_read_fifo(hfcsmini_hw *hw, __u8 channel)
+{
+	__u8	f1 = 0, f2 = 0, z1, z2;
+	__u8	fstat = 0;
+	int	i;
+	int	rcnt;		/* read rcnt bytes out of fifo */
+	__u8	*data;		/* new data pointer */
+	struct sk_buff	*skb;	/* data buffer for upper layer */
+	channel_t	*ch = &hw->chan[channel];
+
+receive_buffer:
+	hfcsmini_selfifo(hw, (channel * 2) + 1);
+	if (test_bit(FLG_HDLC, &ch->Flags)) {
+		/* hdlc rcnt */
+		f1 = read_hfcsmini_stable(hw, A_F1);
+		f2 = read_hfcsmini(hw, A_F2);
+		z1 = read_hfcsmini_stable(hw, A_Z1);
+		z2 = read_hfcsmini(hw, A_Z2);
+		fstat = read_hfcsmini(hw, R_ST_RD_STA);
+		rcnt = (z1 - z2) & hw->max_z;
+		if (f1 != f2)
+			rcnt++;
+	} else {
+		/* transparent rcnt */
+		rcnt = read_hfcsmini_stable(hw, A_USAGE) - 1;
+		f1=f2=z1=z2=0;
+	}
+	if (debug & DEBUG_HFC_FIFO) {
+		if (ch->rx_skb)
+			i = ch->rx_skb->len;
+		else
+			i = 0;
+		mISDN_debugprint(&ch->inst, "reading %i bytes channel(%i) "
+			"irq_cnt(%i) fstat(%i) idx(%i) f1(%i) f2(%i) z1(%i) z2(%i)",
+			rcnt, channel, hw->irq_cnt, fstat, i, f1, f2, z1, z2);
+	}
+	if (rcnt > 0) {
+		if (!ch->rx_skb) {
+			ch->rx_skb = alloc_stack_skb(ch->maxlen + 3, ch->up_headerlen);
+			if (!ch->rx_skb) {
+				printk(KERN_DEBUG "%s: No mem for rx_skb\n", __FUNCTION__);
+				return;
+			}
+		}
+		data = skb_put(ch->rx_skb, rcnt);
+		/* read data from FIFO*/
+		while (rcnt--)
+			*data++ = read_hfcsmini(hw, A_FIFO_DATA);
+	} else
+		return;
+
+
+	if (test_bit(FLG_HDLC, &ch->Flags)) {
+		if (f1 != f2) {
+			hfcsmini_inc_f(hw);
+			/* check minimum frame size */
+			if (ch->rx_skb->len < 4) {
+				if (debug & DEBUG_HFC_FIFO_ERR)
+					mISDN_debugprint(&ch->inst,
+						"%s: frame in channel(%i) < minimum size",
+						__FUNCTION__, channel);
+				goto read_exit;
+			}
+			/* check crc */
+			if (ch->rx_skb->data[ch->rx_skb->len - 1]) {
+				if (debug & DEBUG_HFC_FIFO_ERR)
+					mISDN_debugprint(&ch->inst,
+						"%s: channel(%i) CRC-error",
+						__FUNCTION__, channel);
+				goto read_exit;	
+			}
+			/* remove cksum */
+			skb_trim(ch->rx_skb, ch->rx_skb->len - 3);
+
+			if (ch->rx_skb->len < MISDN_COPY_SIZE) {
+				skb = alloc_stack_skb(ch->rx_skb->len, ch->up_headerlen);
+				if (skb) {
+					memcpy(skb_put(skb, ch->rx_skb->len),
+						ch->rx_skb->data, ch->rx_skb->len);
+					skb_trim(ch->rx_skb, 0);
+				} else {
+					skb = ch->rx_skb;
+					ch->rx_skb = NULL;
+				}
+			} else {
+				skb = ch->rx_skb;
+				ch->rx_skb = NULL;
+			}
+			if ((ch->debug) && (debug & DEBUG_HFC_DTRACE)) {
+				mISDN_debugprint(&ch->inst,
+					"channel(%i) new RX len(%i): ",
+					channel, skb->len);
+				i = 0;
+				printk("  ");
+				while (i < skb->len)
+					printk("%02x ", skb->data[i++]);
+				printk("\n");
+			}
+			queue_ch_frame(ch, INDICATION, MISDN_ID_ANY, skb);
+read_exit:
+			if (ch->rx_skb)
+				skb_trim(ch->rx_skb, 0);
+			if (read_hfcsmini_stable(hw, A_USAGE) > 8) {
+				if (debug & DEBUG_HFC_FIFO)
+					mISDN_debugprint(&ch->inst,
+						"%s: channel(%i) continue hfcsmini_read_fifo",
+						__FUNCTION__, channel);
+				goto receive_buffer;
+			}
+			return;
+		} else {
+			hfcsmini_selfifo(hw, (channel * 2) + 1);
+		}
+	} else { /* transparent data */
+		hfcsmini_selfifo(hw, (channel * 2) + 1);
+		if (ch->rx_skb->len >= 128) {
+			/* deliver transparent data to layer2 */
+			queue_ch_frame(ch, INDICATION, MISDN_ID_ANY, ch->rx_skb);
+			ch->rx_skb = NULL;
+		}
+	}
+}
+
+
+/*************************************/
+/* bottom half handler for interrupt */
+/*************************************/
+static void
+hfcsmini_bh_handler(unsigned long ul_hw)
+{
+	hfcsmini_hw *hw = (hfcsmini_hw *) ul_hw;
+	reg_r_st_rd_sta state;
+	int i;
+
+	/* Timer Int */	
+	if (hw->misc_irq.bit.v_ti_irq) {
+		hw->misc_irq.bit.v_ti_irq = 0;
+		/* add Fifo-Fill info into int_s1 bitfield */
+		hw->fifo_irq.reg |= ((read_hfcsmini(hw, R_FILL) ^ FIFO_MASK_TX) & hw->fifomask);
+		/* Handle TX Fifos */
+		for (i = 0; i < hw->max_fifo; i++) {
+			if ((1 << (i * 2)) & (hw->fifo_irq.reg)) {
+				hw->fifo_irq.reg &= ~(1 << (i * 2));
+				if (test_bit(FLG_TX_BUSY, &hw->chan[i].Flags))
+					hfcsmini_write_fifo(hw, i);
+			}
+		}
+		/* handle NT Timer */
+		if ((hw->portmode & PORT_MODE_NT) && (hw->portmode & NT_TIMER))
+			if ((--hw->nt_timer) < 0)
+				s0_new_state(&hw->chan[2]);
+	}
+	/* Handle RX Fifos */
+	for (i = 0; i < hw->max_fifo; i++) {
+		if ((1 << (i * 2 + 1)) & (hw->fifo_irq.reg)) {
+			hw->fifo_irq.reg &= ~(1 << (i * 2 + 1));
+			hfcsmini_read_fifo(hw, i);
+		}
+	}
+	/* state machine IRQ */	
+	if (hw->misc_irq.bit.v_st_irq) {
+		hw->misc_irq.bit.v_st_irq = 0;
+		state.reg = read_hfcsmini(hw, R_ST_RD_STA);
+		/*
+		mISDN_debugprint(&dch->inst,
+			"new_l1_state(0x%02x)", state.bit.v_st_sta);
+		*/
+		if (state.bit.v_st_sta != hw->chan[2].state) {
+			hw->chan[2].state = state.bit.v_st_sta;
+			s0_new_state(&hw->chan[2]);
+		}		
+	}
+	return;
+}
+
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static irqreturn_t
+hfcsmini_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	__u8 fifo_irq, misc_irq;
+	hfcsmini_hw *hw = dev_id;
+
+	spin_lock(&hw->rlock);
+	
+	if (!(hw->misc_irqmsk.bit.v_irq_en)) {
+		if (!(hw->testirq))
+			printk(KERN_INFO
+			       "%s %s GLOBAL INTERRUPT DISABLED\n",
+			       hw->card_name, __FUNCTION__);		
+		spin_unlock(&hw->rlock);
+		return IRQ_NONE;
+	} 
+
+	fifo_irq = read_hfcsmini_irq(hw, R_FIFO_IRQ) & hw->fifo_irqmsk.reg;
+	misc_irq = read_hfcsmini_irq(hw, R_MISC_IRQ) & hw->misc_irqmsk.reg;
+	
+	if (!fifo_irq && !misc_irq) {
+		spin_unlock(&hw->rlock);
+		return IRQ_NONE; /* other hardware interrupted */
+	}
+	
+	hw->irq_cnt++;
+	
+	hw->fifo_irq.reg |= fifo_irq;
+	hw->misc_irq.reg |= misc_irq;
+	
+	/* queue bottom half */
+	if (!(hw->testirq)) {
+		tasklet_schedule(&hw->tasklet);
+	}
+	
+	spin_unlock(&hw->rlock);
+	
+	return IRQ_HANDLED;
+}
+
+
+/*************************************/
+/* free memory for all used channels */
+/*************************************/
+void
+release_channels(hfcsmini_hw * hw)
+{
+	int i = 0;
+
+	while (i < MAX_CHAN) {
+		if (hw->chan[i].Flags) {
+			if (debug & DEBUG_HFC_INIT)
+				printk(KERN_DEBUG "%s %s: free channel %d\n",
+					hw->card_name, __FUNCTION__, i);
+			mISDN_freechannel(&hw->chan[i]);
+			mISDN_ctrl(&hw->chan[i].inst, MGR_UNREGLAYER | REQUEST, NULL);
+		}
+		i++;
+	}
+}
+
+
+/******************************************/
+/* Setup Fifo using HDLC_PAR and CON_HDLC */
+/******************************************/
+void setup_fifo(hfcsmini_hw * hw, int fifo, __u8 hdlcreg, __u8 con_reg, __u8 irq_enable, __u8 enable)
+{       
+	
+	if (enable)
+		/* mark fifo to be 'in use' */
+		hw->fifomask |= (1 << fifo);
+	else
+		hw->fifomask &= ~(1 << fifo);
+
+	if (irq_enable)
+		hw->fifo_irqmsk.reg |= (1 << fifo);
+	else
+		hw->fifo_irqmsk.reg &= ~(1 << fifo);
+		
+	write_hfcsmini(hw, R_FIFO_IRQMSK, hw->fifo_irqmsk.reg);
+	
+	hfcsmini_selfifo(hw, fifo);
+	write_hfcsmini(hw, A_HDLC_PAR, hdlcreg); 
+	write_hfcsmini(hw, A_CON_HDLC, con_reg); 
+	hfcsmini_resetfifo(hw);
+}
+
+
+/*************************************************/
+/* Setup ST interface, enable/disable B-Channels */
+/*************************************************/
+void
+setup_st(hfcsmini_hw * hw, __u8 bc, __u8 enable)
+{
+	if (!((bc == 0) || (bc == 1))) {
+		printk(KERN_INFO "%s %s: ERROR: bc(%i) unvalid!\n",
+		       hw->card_name, __FUNCTION__, bc);
+		return;
+	}
+
+	if (bc) {
+		hw->st_ctrl0.bit.v_b2_en = (enable?1:0);
+		hw->st_ctrl2.bit.v_b2_rx_en = (enable?1:0);
+	} else {
+		hw->st_ctrl0.bit.v_b1_en = (enable?1:0);
+		hw->st_ctrl2.bit.v_b1_rx_en = (enable?1:0);
+	}
+
+	write_hfcsmini(hw, R_ST_CTRL0, hw->st_ctrl0.reg);
+	write_hfcsmini(hw, R_ST_CTRL2, hw->st_ctrl2.reg);
+	
+	if (debug & DEBUG_HFC_MODE) {
+		printk(KERN_INFO
+		       "%s %s: bc(%i) %s, R_ST_CTRL0(0x%02x) R_ST_CTRL2(0x%02x)\n",
+		       hw->card_name, __FUNCTION__, bc, enable?"enable":"disable",
+		       hw->st_ctrl0.reg, hw->st_ctrl2.reg);
+	}
+}
+
+
+/*********************************************/
+/* (dis-) connect D/B-Channel using protocol */
+/*********************************************/
+int
+setup_channel(hfcsmini_hw *hw, __u8 channel, int protocol)
+{
+	if (test_bit(FLG_BCHANNEL, &hw->chan[channel].Flags)) {
+		if (debug & DEBUG_HFC_MODE)
+			mISDN_debugprint(&hw->chan[channel].inst,
+				"channel(%i) protocol %x-->%x",
+				channel, hw->chan[channel].state, protocol);
+		switch (protocol) {
+			case (-1):	/* used for init */
+				hw->chan[channel].state = -1;
+				hw->chan[channel].channel = channel;
+				/* fall trough */
+			case (ISDN_PID_NONE):
+				if (debug & DEBUG_HFC_MODE)
+					mISDN_debugprint(&hw->chan[channel].inst,
+						"ISDN_PID_NONE");
+				if (hw->chan[channel].state == ISDN_PID_NONE)
+					return (0);	/* already in idle state */
+				hw->chan[channel].state = ISDN_PID_NONE;
+				/* B-TX */
+				setup_fifo(hw, (channel << 1), 0, 0,
+					FIFO_IRQ_OFF, FIFO_DISABLE); 
+				/* B-RX */                   
+				setup_fifo(hw, (channel << 1) + 1, 0, 0,
+					FIFO_IRQ_OFF, FIFO_DISABLE);
+				setup_st(hw, channel, 0);
+				test_and_clear_bit(FLG_HDLC, &hw->chan[channel].Flags);
+				test_and_clear_bit(FLG_TRANSPARENT, &hw->chan[channel].Flags);
+				break;
+			case (ISDN_PID_L1_B_64TRANS):
+				if (debug & DEBUG_HFC_MODE)
+					mISDN_debugprint(&hw->chan[channel].inst,
+						"ISDN_PID_L1_B_64TRANS");
+				/* B-TX */
+				setup_fifo(hw, (channel << 1), HDLC_PAR_BCH,
+					CON_HDLC_B_TRANS, FIFO_IRQ_OFF,
+					FIFO_ENABLE); 
+				/* B-RX */
+				setup_fifo(hw, (channel << 1) + 1, HDLC_PAR_BCH,
+					CON_HDLC_B_TRANS, FIFO_IRQ_OFF,
+					FIFO_ENABLE);
+				setup_st(hw, channel, 1);
+				hw->chan[channel].state = ISDN_PID_L1_B_64TRANS;
+				test_and_set_bit(FLG_TRANSPARENT, &hw->chan[channel].Flags);
+				break;
+			case (ISDN_PID_L1_B_64HDLC):
+				if (debug & DEBUG_HFC_MODE)
+					mISDN_debugprint(&hw->chan[channel].inst,
+						"ISDN_PID_L1_B_64HDLC");
+				/* B-TX */
+				setup_fifo(hw, (channel << 1), HDLC_PAR_BCH,
+					CON_HDLC_B_HDLC, FIFO_IRQ_OFF,
+					FIFO_ENABLE); 
+				/* B-RX */
+				setup_fifo(hw, (channel << 1) + 1, HDLC_PAR_BCH,
+					CON_HDLC_B_HDLC, FIFO_IRQ_ON,
+					FIFO_ENABLE);
+				setup_st(hw, channel, 1);
+				hw->chan[channel].state = ISDN_PID_L1_B_64HDLC;
+				test_and_set_bit(FLG_HDLC, &hw->chan[channel].Flags);
+				break;
+			default:
+				mISDN_debugprint(&hw->chan[channel].inst,
+					"prot not known %x", protocol);
+				return (-ENOPROTOOPT);
+		}
+		return (0);
+	}
+
+	if (test_bit(FLG_DCHANNEL, &hw->chan[channel].Flags)) {
+		if (debug & DEBUG_HFC_MODE)
+			mISDN_debugprint(&hw->chan[channel].inst,
+				"D channel(%i) protocol(%i)",channel, protocol);
+		
+		/* init the D-channel fifos */
+		/* D-TX */
+		setup_fifo(hw, (channel << 1), HDLC_PAR_DCH,
+			CON_HDLC_D_HDLC, FIFO_IRQ_OFF, FIFO_ENABLE); 
+		/* D-RX */
+		setup_fifo(hw, (channel << 1) + 1, HDLC_PAR_DCH,
+			CON_HDLC_D_HDLC, FIFO_IRQ_ON, FIFO_DISABLE);
+		return (0);
+	}
+	printk(KERN_INFO "%s %s ERROR: channel(%i) is NEITHER B nor D !!!\n",
+		hw->card_name, __FUNCTION__, channel);
+	return (-1);
+}
+
+
+/*****************************************************/
+/* register ISDN stack for one HFC-S mini instance   */
+/*   - register all ports and channels               */
+/*   - set param_idx                                 */
+/*                                                   */
+/*  channel mapping in mISDN in hw->chan[]           */
+/*    0=B1,  1=B2,  2=D,  3=PCM                      */
+/*****************************************************/
+int
+init_mISDN_channels(hfcsmini_hw * hw)
+{
+	int err;
+	int ch;
+	int b;
+	mISDN_pid_t pid;
+	u_long flags;
+
+	/* clear PCM */
+	memset(&hw->chan[3], 0, sizeof(channel_t));
+	/* init D channels */
+	ch = 2;
+	if (debug & DEBUG_HFC_INIT)
+		printk(KERN_INFO
+		       "%s %s: Registering D-channel, card(%d) protocol(%x)\n",
+		       hw->card_name, __FUNCTION__, hw->cardnum,
+		       hw->dpid);
+
+	memset(&hw->chan[ch], 0, sizeof(channel_t));
+	hw->chan[ch].channel = ch;
+	hw->chan[ch].debug = debug;
+	hw->chan[ch].inst.obj = &hw_mISDNObj;
+	hw->chan[ch].inst.hwlock = &hw->mlock;
+	hw->chan[ch].inst.class_dev.dev = &hw->pdev->dev;
+	mISDN_init_instance(&hw->chan[ch].inst, &hw_mISDNObj, hw, hfcsmini_l2l1);
+	
+	hw->chan[ch].inst.pid.layermask = ISDN_LAYER(0);
+	sprintf(hw->chan[ch].inst.name, "%s", hw->card_name);
+	err = mISDN_initchannel(&hw->chan[ch], MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
+	if (err)
+		goto free_channels;
+	hw->chan[ch].hw = hw;
+
+	/* init B channels */
+	for (b = 0; b < 2; b++) {
+		if (debug & DEBUG_HFC_INIT)
+			printk(KERN_DEBUG
+			       "%s %s: Registering B-channel, card(%d) "
+			       "ch(%d)\n", hw->card_name,
+			       __FUNCTION__, hw->cardnum, b);
+
+		memset(&hw->chan[b], 0, sizeof(channel_t));
+		hw->chan[b].channel = b;
+		hw->chan[b].debug = debug;
+		mISDN_init_instance(&hw->chan[b].inst, &hw_mISDNObj, hw, hfcsmini_l2l1);
+		hw->chan[b].inst.pid.layermask = ISDN_LAYER(0);
+		hw->chan[b].inst.hwlock = &hw->mlock;
+		hw->chan[b].inst.class_dev.dev = &hw->pdev->dev;
+		
+		sprintf(hw->chan[b].inst.name, "%s B%d",
+			hw->chan[ch].inst.name, b + 1);
+		if (mISDN_initchannel(&hw->chan[b], MSK_INIT_BCHANNEL, MAX_DATA_MEM)) {
+			err = -ENOMEM;
+			goto free_channels;
+		}
+		hw->chan[b].hw = hw;
+	}
+
+	mISDN_set_dchannel_pid(&pid, hw->dpid, layermask[hw->param_idx]);
+
+	/* set protocol for NT/TE */
+	if (hw->portmode & PORT_MODE_NT) {
+		/* NT-mode */
+		hw->portmode |= NT_TIMER;
+		hw->nt_timer = 0;
+
+		hw->chan[ch].inst.pid.protocol[0] = ISDN_PID_L0_NT_S0;
+		hw->chan[ch].inst.pid.protocol[1] = ISDN_PID_L1_NT_S0;
+		pid.protocol[0] = ISDN_PID_L0_NT_S0;
+		pid.protocol[1] = ISDN_PID_L1_NT_S0;
+		hw->chan[ch].inst.pid.layermask |= ISDN_LAYER(1);
+		pid.layermask |= ISDN_LAYER(1);
+		if (layermask[hw->param_idx] & ISDN_LAYER(2))
+			pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
+	} else {
+		/* TE-mode */
+		hw->portmode |= PORT_MODE_TE;
+		hw->chan[ch].inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
+		pid.protocol[0] = ISDN_PID_L0_TE_S0;
+	}
+
+	if (debug & DEBUG_HFC_INIT)
+		printk(KERN_INFO
+		       "%s %s: registering Stack\n",
+		       hw->card_name, __FUNCTION__);
+
+	/* register stack */
+	err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &hw->chan[ch].inst);
+	if (err) {
+		printk(KERN_ERR "%s %s: MGR_NEWSTACK | REQUEST  err(%d)\n",
+		       hw->card_name, __FUNCTION__, err);
+		goto free_channels;
+	}
+
+	hw->chan[ch].state = 0;
+	for (b = 0; b < 2; b++) {
+		err = mISDN_ctrl(hw->chan[ch].inst.st, MGR_NEWSTACK | REQUEST, &hw->chan[b].inst);
+		if (err) {
+			printk(KERN_ERR
+			       "%s %s: MGR_ADDSTACK bchan error %d\n",
+			       hw->card_name, __FUNCTION__, err);
+			goto free_stack;
+		}
+	}
+
+	err = mISDN_ctrl(hw->chan[ch].inst.st, MGR_SETSTACK | REQUEST, &pid);
+
+	if (err) {
+		printk(KERN_ERR
+		       "%s %s: MGR_SETSTACK REQUEST dch err(%d)\n",
+		       hw->card_name, __FUNCTION__, err);
+		mISDN_ctrl(hw->chan[ch].inst.st, MGR_DELSTACK | REQUEST, NULL);
+		goto free_stack;
+	}
+
+	setup_channel(hw, hw->chan[ch].channel, -1);
+	for (b = 0; b < 2; b++) {
+		setup_channel(hw, b, -1);
+	}
+
+	/* delay some time */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((100 * HZ) / 1000);	/* Timeout 100ms */
+
+	mISDN_ctrl(hw->chan[ch].inst.st, MGR_CTRLREADY | INDICATION, NULL);
+	return (0);
+
+      free_stack:
+	mISDN_ctrl(hw->chan[ch].inst.st, MGR_DELSTACK | REQUEST, NULL);
+      free_channels:
+      	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+	release_channels(hw);
+	list_del(&hw->list);
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+
+	return (err);
+}
+
+
+/********************************/
+/* parse module paramaters like */
+/* NE/TE and S0/Up port mode    */
+/********************************/
+void
+parse_module_params(hfcsmini_hw * hw)
+{
+
+	/* D-Channel protocol: (2=DSS1) */
+	hw->dpid = (protocol[hw->param_idx] & 0x0F);
+	if (hw->dpid == 0) {
+		printk(KERN_INFO
+		       "%s %s: WARNING: wrong value for protocol[%i], "
+		       "assuming 0x02 (DSS1)...\n",
+		       hw->card_name, __FUNCTION__,
+		       hw->param_idx);
+		hw->dpid = 0x02;
+	}
+
+	/* Line Interface TE or NT */
+	if (protocol[hw->param_idx] & 0x10)
+		hw->portmode |= PORT_MODE_NT;
+	else
+		hw->portmode |= PORT_MODE_TE;
+
+	/* Line Interface in S0 or Up mode */
+	if (!(protocol[hw->param_idx] & 0x40))
+		hw->portmode |= PORT_MODE_BUS_MASTER;
+
+		
+	/* link B-channel loop */
+	if (protocol[hw->param_idx] & 0x80)
+		hw->portmode |= PORT_MODE_LOOP;
+	
+
+	if (debug & DEBUG_HFC_INIT)
+		printk ("%s %s: protocol[%i]=0x%02x, dpid=%d,%s bus-mode:%s %s\n",
+		        hw->card_name, __FUNCTION__, hw->param_idx,
+		        protocol[hw->param_idx],
+		        hw->dpid,
+		        (hw->portmode & PORT_MODE_TE)?"TE":"NT",
+		        (hw->portmode & PORT_MODE_BUS_MASTER)?"MASTER":"SLAVE",
+		        (hw->portmode & PORT_MODE_LOOP)?"B-LOOP":""
+		        );
+}
+
+
+/*****************************************/
+/* initialise the HFC-S mini ISDN Chip   */
+/* return 0 on success.                  */
+/*****************************************/
+int
+init_hfcsmini(hfcsmini_hw * hw)
+{
+	int err = 0;
+	reg_r_fifo_thres threshold;
+
+#if HFCBRIDGE == BRIDGE_HFCPCI
+	err = init_pci_bridge(hw);
+	if (err)
+		return(-ENODEV);
+#endif
+
+	hw->chip_id.reg = read_hfcsmini(hw, R_CHIP_ID);
+
+	if (debug & DEBUG_HFC_INIT)
+		printk(KERN_INFO "%s %s ChipID: 0x%x\n", hw->card_name,
+		       __FUNCTION__, hw->chip_id.bit.v_chip_id);
+
+	switch (hw->chip_id.bit.v_chip_id) {
+		case CHIP_ID_HFCSMINI:
+			hw->max_fifo = 4;
+			hw->ti.reg   = 5; /* 8 ms timer interval */
+			hw->max_z    = 0x7F;
+			break;
+		default:
+			err = -ENODEV;
+	}
+
+	if (err) {
+		if (debug & DEBUG_HFC_INIT)
+			printk(KERN_ERR "%s %s: unkown Chip ID 0x%x\n",
+			       hw->card_name, __FUNCTION__, hw->chip_id.bit.v_chip_id);
+		return (err);
+	}
+	
+	/* reset card */
+	write_hfcsmini(hw, R_CIRM, M_SRES); /* Reset On */
+	udelay(10);
+	write_hfcsmini(hw, R_CIRM, 0); /* Reset Off */
+	
+	/* wait until fifo controller init sequence is finished */
+	hfcsmini_waitbusy(hw);
+
+	/* reset D-Channel S/T controller */
+	write_hfcsmini(hw, R_ST_CTRL1, M_D_RES);
+
+	if (hw->portmode & PORT_MODE_TE) {
+		/* TE mode */
+		hw->st_ctrl0.reg = 0;
+		write_hfcsmini(hw, R_ST_CLK_DLY, (M1_ST_CLK_DLY* 0xF));
+		write_hfcsmini(hw, R_ST_CTRL1, 0);
+	} else {
+		/* NT mode */
+		hw->st_ctrl0.reg = 4;
+		write_hfcsmini(hw, R_ST_CLK_DLY, ((M1_ST_SMPL * 0x6) | (M1_ST_CLK_DLY*0xC)));
+		write_hfcsmini(hw, R_ST_CTRL1, M_E_IGNO);
+	}
+	
+	hw->st_ctrl2.reg = 0;
+	write_hfcsmini(hw, R_ST_CTRL0, hw->st_ctrl0.reg);
+	write_hfcsmini(hw, R_ST_CTRL2, hw->st_ctrl2.reg);
+
+	/* HFC Master/Slave Mode */
+	if (hw->portmode & PORT_MODE_BUS_MASTER)
+		hw->pcm_md0.bit.v_pcm_md = 1;
+	else
+		hw->pcm_md0.bit.v_pcm_md = 0;
+
+	write_hfcsmini(hw, R_PCM_MD0, hw->pcm_md0.reg);
+	write_hfcsmini(hw, R_PCM_MD1, 0);
+	write_hfcsmini(hw, R_PCM_MD2, 0);
+
+	/* setup threshold register */
+	threshold.bit.v_thres_tx = (HFCSMINI_TX_THRESHOLD / 8);
+	threshold.bit.v_thres_rx = (HFCSMINI_RX_THRESHOLD / 8);
+	write_hfcsmini(hw, R_FIFO_THRES, threshold.reg);
+
+	/* test timer irq */
+	enable_interrupts(hw);
+	mdelay(((1 << hw->ti.reg)+1)*2);
+	hw->testirq = 0;
+	
+	if (hw->irq_cnt) {
+		printk(KERN_INFO
+		       "%s %s: test IRQ OK, irq_cnt %i\n",
+		       hw->card_name, __FUNCTION__, hw->irq_cnt);
+		disable_interrupts(hw);
+		return (0);
+	} else {
+		if (debug & DEBUG_HFC_INIT)
+			printk(KERN_INFO
+			       "%s %s: ERROR getting IRQ (irq_cnt %i)\n",
+			       hw->card_name, __FUNCTION__, hw->irq_cnt);
+		disable_interrupts(hw);
+		free_irq(hw->irq, hw);
+		return (-EIO);
+	}
+}
+
+
+/*****************************************************/
+/* disable all interrupts by disabling M_GLOB_IRQ_EN */
+/*****************************************************/
+void
+disable_interrupts(hfcsmini_hw * hw)
+{
+	u_long flags;
+	if (debug & DEBUG_HFC_IRQ)
+		printk(KERN_INFO "%s %s\n", hw->card_name, __FUNCTION__);
+
+	spin_lock_irqsave(&hw->mlock, flags);
+	hw->fifo_irqmsk.reg = 0;
+	hw->misc_irqmsk.reg = 0;	
+	write_hfcsmini(hw, R_FIFO_IRQMSK, hw->fifo_irqmsk.reg);
+	write_hfcsmini(hw, R_MISC_IRQMSK, hw->misc_irqmsk.reg);
+	spin_unlock_irqrestore(&hw->mlock, flags);
+}
+
+
+/******************************************/
+/* start interrupt and set interrupt mask */
+/******************************************/
+void
+enable_interrupts(hfcsmini_hw * hw)
+{
+	u_long flags;
+	
+	if (debug & DEBUG_HFC_IRQ)
+		printk(KERN_INFO "%s %s\n", hw->card_name, __FUNCTION__);
+
+	spin_lock_irqsave(&hw->mlock, flags);
+	
+	hw->fifo_irq.reg = 0;
+	hw->misc_irq.reg = 0;
+	
+	write_hfcsmini(hw, R_TI, hw->ti.reg); 
+
+	/* D-RX and D-TX interrupts enable */
+	hw->fifo_irqmsk.bit.v_fifo2_tx_irqmsk = 1;
+	hw->fifo_irqmsk.bit.v_fifo2_rx_irqmsk = 1;	
+
+	/* clear pending ints */
+	if (read_hfcsmini(hw, R_FIFO_IRQ));
+	if (read_hfcsmini(hw, R_MISC_IRQ));
+	
+	/* Finally enable IRQ output */
+	hw->misc_irqmsk.bit.v_st_irqmsk = 1; /* enable L1-state change irq */
+	hw->misc_irqmsk.bit.v_ti_irqmsk = 1; /* enable timer irq */
+	hw->misc_irqmsk.bit.v_irq_en    = 1; /* IRQ global enable */
+	
+	write_hfcsmini(hw, R_MISC_IRQMSK, hw->misc_irqmsk.reg);
+	
+	spin_unlock_irqrestore(&hw->mlock, flags);
+	
+	return;
+}
+
+
+/**************************************/
+/* initialise the HFC-S mini hardware */
+/* return 0 on success.               */
+/**************************************/
+static int __devinit
+setup_instance(hfcsmini_hw * hw)
+{
+	int		err;
+	hfcsmini_hw *previous_hw;
+	u_long		flags;
+	
+
+	if (debug & DEBUG_HFC_INIT)
+		printk(KERN_WARNING "%s %s\n",
+		       hw->card_name, __FUNCTION__);
+
+	spin_lock_init(&hw->mlock);
+	spin_lock_init(&hw->rlock);
+	tasklet_init(&hw->tasklet, hfcsmini_bh_handler, (unsigned long) hw);
+	
+	/* search previous instances to index protocol[] array */
+	list_for_each_entry(previous_hw, &hw_mISDNObj.ilist, list)
+		hw->param_idx++;
+
+	/* add this instance to hardware list */
+	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+	list_add_tail(&hw->list, &hw_mISDNObj.ilist);
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+
+	/* init interrupt engine */
+	hw->testirq = 1;
+	if (debug & DEBUG_HFC_INIT)
+		printk(KERN_WARNING "%s %s: requesting IRQ %d\n",
+		       hw->card_name, __FUNCTION__, hw->irq);
+		       
+	if (request_irq(hw->irq, hfcsmini_interrupt, SA_SHIRQ, "HFC-S mini", hw)) {
+		printk(KERN_WARNING "%s %s: couldn't get interrupt %d\n",
+		       hw->card_name, __FUNCTION__, hw->irq);
+		       
+		hw->irq = 0;
+		err = -EIO;
+		goto out;
+	}
+
+	parse_module_params(hw);
+	
+	err = init_hfcsmini(hw);
+	if (err)
+		goto out;
+
+	/* register all channels at ISDN procol stack */
+	err = init_mISDN_channels(hw);
+	if (err)
+		goto out;
+		
+	/* delay some time to have mISDN initialazed complete */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((100 * HZ) / 1000);	/* Timeout 100ms */
+	
+	/* Clear already pending ints */
+	if (read_hfcsmini(hw, R_FIFO_IRQ));
+	
+	enable_interrupts(hw);
+	
+	/* enable state machine */
+	write_hfcsmini(hw, R_ST_RD_STA, 0x0);
+	
+	return(0);
+
+      out:
+	return (err);
+}
+
+
+#if HFCBRIDGE == BRIDGE_HFCPCI
+
+/***********************/
+/* PCI Bridge ID List  */
+/***********************/
+static struct pci_device_id hfcsmini_ids[] = {
+	{.vendor = PCI_VENDOR_ID_CCD,
+	 .device = 0xA001,
+	 .subvendor = PCI_VENDOR_ID_CCD,
+	 .subdevice = 0xFFFF,
+	 .driver_data =
+	 (unsigned long) &((hfcsmini_param) {0xFF, "HFC-S mini Evaluation Board"}),
+	 },
+	{}
+};
+
+/******************************/
+/* initialise the PCI Bridge  */
+/* return 0 on success.       */
+/******************************/
+int
+init_pci_bridge(hfcsmini_hw * hw)
+{
+	outb(0x58, hw->iobase + 4); /* ID-register of bridge */
+	if ((inb(hw->iobase) & 0xf0) != 0x30) {
+		printk(KERN_INFO "%s %s: chip ID for PCI bridge invalid\n",
+		       hw->card_name, __FUNCTION__);
+		release_region(hw->iobase, 8);
+		return(-EIO);
+	}
+
+	outb(0x60, hw->iobase + 4); /* CIRM register of bridge */
+	outb(0x07, hw->iobase); /* 15 PCI clocks aux access */
+
+	/* reset sequence */
+	outb(2, hw->iobase + 3); /* A0 = 1, reset = 0 (active) */
+	udelay(10);
+	outb(6, hw->iobase + 3); /* A0 = 1, reset = 1 (inactive) */
+	outb(0, hw->iobase + 1); /* write dummy register number */
+
+	/* wait until reset sequence finished, can be redefined after schematic review */
+	mdelay(300);
+
+	return (0);
+}
+
+/************************/
+/* release single card  */
+/************************/
+static void
+release_card(hfcsmini_hw * hw)
+{
+	u_long	flags;
+
+	disable_interrupts(hw);
+	free_irq(hw->irq, hw);
+
+	/* wait for pending tasklet to finish */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((100 * HZ) / 1000);	/* Timeout 100ms */
+	
+	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+	release_channels(hw);
+	list_del(&hw->list);
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+	
+	kfree(hw);
+}
+
+/*****************************************/
+/* PCI hotplug interface: probe new card */
+/*****************************************/
+static int __devinit
+hfcsmini_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	hfcsmini_param *driver_data = (hfcsmini_param *) ent->driver_data;
+	hfcsmini_hw *hw;
+
+	int err = -ENOMEM;
+
+	if (!(hw = kmalloc(sizeof(hfcsmini_hw), GFP_ATOMIC))) {
+		printk(KERN_ERR "%s %s: No kmem for HFC-S mini card\n",
+		       hw->card_name, __FUNCTION__);
+		return (err);
+	}
+	memset(hw, 0, sizeof(hfcsmini_hw));
+
+	hw->pdev = pdev;
+	err = pci_enable_device(pdev);
+
+	if (err)
+		goto out;
+
+	hw->cardnum = card_cnt;
+	sprintf(hw->card_name, "%s_%d", DRIVER_NAME, hw->cardnum);
+	printk(KERN_INFO "%s %s: adapter '%s' found on PCI bus %02x dev %02x\n",
+	       hw->card_name, __FUNCTION__, driver_data->device_name,
+	       pdev->bus->number, pdev->devfn);
+
+	hw->driver_data = *driver_data;
+	hw->irq = pdev->irq;
+	
+ 	hw->iobase = (u_int) get_pcibase(pdev, 0);
+	if (!hw->iobase) {
+		printk(KERN_WARNING "%s no IO for PCI card found\n",
+		       hw->card_name);
+		return(-EIO);
+	}
+	
+	if (!request_region(hw->iobase, 8, "hfcmulti")) {
+		printk(KERN_WARNING "%s failed to request "
+		                    "address space at 0x%04x\n",
+		                    hw->card_name,
+		                    hw->iobase);
+	}
+	
+        printk(KERN_INFO "%s defined at IOBASE 0x%#x IRQ %d HZ %d\n",
+	       hw->card_name, 
+	       (u_int) hw->iobase,
+	       hw->irq,
+	       HZ);
+
+	/* enable IO */
+	pci_write_config_word(pdev, PCI_COMMAND, 0x01);
+	
+	pci_set_drvdata(pdev, hw);
+	err = setup_instance(hw);
+	
+	if (!err) {
+		card_cnt++;
+		return (0);
+	} else {
+		goto out;
+	}
+
+      out:
+	kfree(hw);
+	return (err);
+};
+
+
+/**************************************/
+/* PCI hotplug interface: remove card */
+/**************************************/
+static void __devexit
+hfcsmini_pci_remove(struct pci_dev *pdev)
+{
+	hfcsmini_hw *hw = pci_get_drvdata(pdev);
+	printk(KERN_INFO "%s %s: removing card\n", hw->card_name,
+	       __FUNCTION__);
+	release_card(hw);
+	card_cnt--;
+	pci_disable_device(pdev);
+	return;
+};
+
+
+/*****************************/
+/* Module PCI driver exports */
+/*****************************/
+static struct pci_driver hfcsmini_driver = {
+	name:DRIVER_NAME,
+	probe:hfcsmini_pci_probe,
+	remove:__devexit_p(hfcsmini_pci_remove),
+	id_table:hfcsmini_ids,
+};
+
+MODULE_DEVICE_TABLE(pci, hfcsmini_ids);
+
+#endif
+
+/***************/
+/* Module init */
+/***************/
+static int __init
+hfcsmini_init(void)
+{
+	int err;
+
+	printk(KERN_INFO "HFC-S mini: %s driver Rev. %s (debug=%i)\n",
+	       __FUNCTION__, mISDN_getrev(hfcsmini_rev), debug);
+
+#ifdef MODULE
+	hw_mISDNObj.owner = THIS_MODULE;
+#endif
+
+	INIT_LIST_HEAD(&hw_mISDNObj.ilist);
+	spin_lock_init(&hw_mISDNObj.lock);
+	hw_mISDNObj.name = DRIVER_NAME;
+	hw_mISDNObj.own_ctrl = hfcsmini_manager;
+
+	hw_mISDNObj.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0 |
+	    ISDN_PID_L0_NT_S0;
+	hw_mISDNObj.DPROTO.protocol[1] = ISDN_PID_L1_NT_S0;
+	hw_mISDNObj.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS |
+	    ISDN_PID_L1_B_64HDLC;
+	hw_mISDNObj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS |
+	    ISDN_PID_L2_B_RAWDEV;
+
+	card_cnt = 0;
+
+	if ((err = mISDN_register(&hw_mISDNObj))) {
+		printk(KERN_ERR "HFC-S mini: can't register HFC-S mini, error(%d)\n",
+		       err);
+		goto out;
+	}
+
+#if HFCBRIDGE == BRIDGE_HFCPCI
+	err = pci_register_driver(&hfcsmini_driver);
+	if (err < 0) {
+		goto out;
+	}
+#if !defined(CONFIG_HOTPLUG)
+	if (err == 0) {
+		err = -ENODEV;
+		pci_unregister_driver(&hfcsmini_driver);
+		goto out;
+	}
+#endif
+#endif
+
+	mISDN_module_register(THIS_MODULE);
+	printk(KERN_INFO "HFC-S mini: %d cards installed\n", card_cnt);
+	return 0;
+
+      out:
+	return (err);
+}
+
+
+static void __exit
+hfcsmini_cleanup(void)
+{
+	int err;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+#if HFCBRIDGE == BRIDGE_HFCPCI
+	pci_unregister_driver(&hfcsmini_driver);
+#endif
+
+	if ((err = mISDN_unregister(&hw_mISDNObj))) {
+		printk(KERN_ERR "HFC-S mini: can't unregister HFC-S mini, error(%d)\n",
+		       err);
+	}
+	printk(KERN_INFO "%s: driver removed\n", __FUNCTION__);
+}
+
+module_init(hfcsmini_init);
+module_exit(hfcsmini_cleanup);


Property changes on: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_mini.c
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_mini.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_mini.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_mini.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,187 @@
+/* $Id: hfcs_mini.h,v 1.2 2006/03/06 12:58:31 keil Exp $
+ *
+ * mISDN driver for Colognechip HFC-S mini Evaluation Card
+ *
+ * Authors : Martin Bachem, Joerg Ciesielski
+ * Contact : info at colognechip.com
+ *
+ * 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.
+ *
+ */
+
+#ifndef __HFCMINI_H__
+#define __HFCMINI_H__
+
+#include "channel.h"
+#include "hfcsmcc.h"
+
+
+#define BRIDGE_UNKWOWN	0
+#define BRIDGE_HFCPCI	1
+
+/* use HFC-S PCI as PCI Bridge */
+#define HFCBRIDGE	BRIDGE_HFCPCI
+#define SPIN_LOCK_HFCSMINI_REGISTER
+
+#define DRIVER_NAME "HFCMINI"
+#define CHIP_ID_HFCSMINI CHIP_ID
+
+#define MAX_CHAN	4	/* D, B1, B2, PCM */
+
+/* flags in _u16  port mode */
+#define PORT_UNUSED		0x0000
+#define PORT_MODE_NT		0x0001
+#define PORT_MODE_TE		0x0002
+#define PORT_MODE_BUS_MASTER	0x0004
+#define PORT_MODE_UP		0x0008
+#define PORT_MODE_EXCH_POL	0x0010
+#define PORT_MODE_LOOP		0x0020
+#define NT_TIMER		0x8000
+
+
+/* NT / TE defines */
+#define NT_T1_COUNT	12	/* number of 8ms interrupts for G2 timeout */
+#define CLK_DLY_TE	0x0e	/* CLKDEL in TE mode */
+#define CLK_DLY_NT	0x6c	/* CLKDEL in NT mode */
+#define STA_ACTIVATE	0x60	/* start activation   in A_SU_WR_STA */
+#define STA_DEACTIVATE	0x40	/* start deactivation in A_SU_WR_STA */
+#define LIF_MODE_NT	0x04	/* Line Interface NT mode */
+
+
+/* HFC-S mini Layer1 physical commands */
+#define HFC_L1_ACTIVATE_TE		0x01
+#define HFC_L1_FORCE_DEACTIVATE_TE	0x02
+#define HFC_L1_ACTIVATE_NT		0x03
+#define HFC_L1_DEACTIVATE_NT		0x04
+#define HFC_L1_TESTLOOP_B1		0x05
+#define HFC_L1_TESTLOOP_B2		0x06
+
+/* FIFO handling support values */
+#define FIFO_IRQ_OFF	0
+#define FIFO_IRQ_ON	1
+#define FIFO_DISABLE	0
+#define FIFO_ENABLE	1
+#define FIFO_MASK_TX	0x55
+#define FIFO_MASK_RX	0xAA
+#define HDLC_PAR_BCH      0 				/* init value for all B-channel fifos */
+#define HDLC_PAR_DCH      (M1_BIT_CNT*2)		/* same for D- and E-channel */
+#define CON_HDLC_B_TRANS  (M_HDLC_TRP | M1_TRP_IRQ*2)	/* transparent mode B-channel 32 byte threshold */ 
+#define CON_HDLC_B_HDLC   (M1_TRP_IRQ*2)		/* HDLC mode b-channel */
+#define CON_HDLC_D_HDLC   (M1_TRP_IRQ*2 | M_IFF)	/* HDLC mode D-channel, 1 fill mode */
+#define CON_HDLC_B_LOOP   (M1_TRP_IRQ*2 | M1_DATA_FLOW*6) /* B-channel loopback mode */
+#define HFCSMINI_RX_THRESHOLD 32
+#define HFCSMINI_TX_THRESHOLD 96
+#define DCH_RX_SIZE 267
+#define BCH_RX_SIZE 2051
+#define BCH_RX_SIZE_TRANS 64
+
+/* DEBUG flags, use combined value for module parameter debug=x */
+#define DEBUG_HFC_INIT		0x0001
+#define DEBUG_HFC_MODE		0x0002
+#define DEBUG_HFC_S0_STATES	0x0004
+#define DEBUG_HFC_IRQ		0x0008
+#define DEBUG_HFC_FIFO_ERR	0x0010
+#define DEBUG_HFC_DTRACE	0x2000
+#define DEBUG_HFC_BTRACE	0x4000	/* very(!) heavy messageslog load */
+#define DEBUG_HFC_FIFO		0x8000	/* very(!) heavy messageslog load */
+
+
+/* private driver_data */
+typedef struct {
+	int chip_id;
+	char *device_name;
+} hfcsmini_param;
+
+struct _hfcmini_hw;
+
+/**********************/
+/* hardware structure */
+/**********************/
+typedef struct _hfcmini_hw {
+
+	struct list_head list;
+	__u32 irq_cnt;	/* count irqs */
+	struct tasklet_struct tasklet;	/* interrupt bottom half */	
+	spinlock_t mlock; /* mISDN mq lock */
+	spinlock_t rlock; /* register access lock */
+
+	int cardnum;
+	__u8 param_idx;		/* used to access module param arrays */
+	__u8 testirq;
+	int irq;
+	int iobase;
+	u_char *membase;
+	u_char *hw_membase;
+	struct pci_dev *pdev;
+	hfcsmini_param driver_data;
+	char card_name[60];
+
+	int max_fifo;		/* always 4 fifos per port */
+	__u8 max_z;		/* fifo depth -1 */
+	
+	channel_t chan[MAX_CHAN];	/* line interfaces */
+	
+	__u8 fifomask;
+	
+	/* HFC-S MINI regsister */
+	reg_r_chip_id chip_id;	/* Chip ID */
+	
+	reg_r_pcm_md0 pcm_md0;	/* PCM config */
+	reg_r_pcm_md1 pcm_md1;	/* PCM config */
+	reg_r_pcm_md2 pcm_md2;	/* PCM config */
+	
+	reg_r_ti ti;		/* timer interrupt configuration */
+
+	reg_r_fifo_irqmsk	fifo_irqmsk;	/* FIFO interrupt mask */ 
+	reg_r_fifo_irq		fifo_irq;	/* FIFO interrupt state */
+
+	reg_r_misc_irqmsk	misc_irqmsk;	/* MISC interrupt mask */
+	reg_r_misc_irq		misc_irq;	/* MISC interrupt state */
+
+	reg_r_st_ctrl0		st_ctrl0;
+	reg_r_st_ctrl2		st_ctrl2;	
+	
+	int nt_timer;
+	__u8 dpid;		/* DChannel Protocoll ID */
+	__u16 portmode;		/* NT/TE */
+
+} hfcsmini_hw;
+
+
+/* function prototypes */
+int setup_channel(hfcsmini_hw * hw, __u8 channel, int protocol);
+void hfcsmini_write_fifo(hfcsmini_hw * hw, __u8 channel);
+void hfcsmini_read_fifo(hfcsmini_hw * hw, __u8 channel);
+void print_fc(hfcsmini_hw * hw, __u8 fifo);
+void setup_fifo(hfcsmini_hw * hw, int fifo, __u8 hdlcreg, __u8 con_reg, __u8 irq_enable, __u8 enable);
+void setup_s(hfcsmini_hw * hw, __u8 bc, __u8 enable);
+void disable_interrupts(hfcsmini_hw * hw);
+void enable_interrupts(hfcsmini_hw * hw);
+static void release_card(hfcsmini_hw * hw);
+
+
+#if HFCBRIDGE == BRIDGE_HFCPCI
+int init_pci_bridge(hfcsmini_hw * hw);
+#endif
+
+/* HFC-S MINI register access functions */
+static inline void hfcsmini_sel_reg(hfcsmini_hw * hw, __u8 reg_addr);
+static inline __u8 read_hfcsmini(hfcsmini_hw * hw, __u8 reg_addr);
+static inline __u8 read_hfcsmini_irq(hfcsmini_hw * hw, __u8 reg_addr);
+static inline __u8 read_hfcsmini_stable(hfcsmini_hw * hw, __u8 reg_addr);
+static inline void write_hfcsmini(hfcsmini_hw * hw, __u8 reg_addr, __u8 value);
+
+
+#endif				/* __hfcsmini_H__ */


Property changes on: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_mini.h
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_usb.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_usb.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_usb.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,2229 @@
+/* $Id: hfcs_usb.c,v 1.29 2007/02/13 10:43:45 crich Exp $
+ *
+ * mISDN driver for Colognechip HFC-S USB chip
+ *
+ * Author : Martin Bachem   (info at colognechip.com)
+ *  - based on the HiSax hfcusb.c driver by Peter Sprenger
+ *  - based on a mISDN skel driver by Karten Keil
+ *
+ * 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.
+ *
+ * TODO
+ *   - E channel features
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include "core.h"
+#include "channel.h"
+#include "layer1.h"
+#include "debug.h"
+#include "hfcs_usb.h"
+
+
+#define DRIVER_NAME "mISDN_hfcsusb"
+const char *hfcsusb_rev = "$Revision: 1.29_ab $";
+
+#define MAX_CARDS	8
+static int hfcsusb_cnt;
+static u_int protocol[MAX_CARDS] = {2,2,2,2,2,2,2,2};
+static int layermask[MAX_CARDS];
+
+static mISDNobject_t hw_mISDNObj;
+static int debug = 0;
+static int poll = 128;
+
+
+#ifdef MODULE
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+MODULE_PARM(poll, "1i");
+#define MODULE_PARM_T   "1-4i"
+MODULE_PARM(protocol, MODULE_PARM_T);
+MODULE_PARM(layermask, MODULE_PARM_T);
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+module_param(poll, uint, S_IRUGO | S_IWUSR);
+
+#ifdef OLD_MODULE_PARAM_ARRAY
+static int num_protocol=0, num_layermask=0;
+module_param_array(protocol, uint, num_protocol, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, num_layermask, S_IRUGO | S_IWUSR);
+#else
+module_param_array(protocol, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, NULL, S_IRUGO | S_IWUSR);
+#endif
+#endif
+#endif
+
+
+struct _hfcsusb_t;		/* forward definition */
+
+/***************************************************************/
+/* structure defining input+output fifos (interrupt/bulk mode) */
+/***************************************************************/
+struct usb_fifo;		/* forward definition */
+typedef struct iso_urb_struct {
+	struct urb *purb;
+	__u8 buffer[ISO_BUFFER_SIZE];	/* buffer incoming/outgoing USB URB data */
+	struct usb_fifo *owner_fifo;	/* pointer to owner fifo */
+} iso_urb_struct;
+
+typedef struct usb_fifo {
+	int fifonum;		/* fifo index attached to this structure */
+	int active;		/* fifo is currently active */
+	struct _hfcsusb_t *card;	/* pointer to main structure */
+	int pipe;		/* address of endpoint */
+	__u8 usb_packet_maxlen;	/* maximum length for usb transfer */
+	unsigned int max_size;	/* maximum size of receive/send packet */
+	__u8 intervall;		/* interrupt interval */
+	struct urb *urb;	/* transfer structure for usb routines */
+	__u8 buffer[128];	/* buffer USB INT OUT URB data */
+	int bit_line;		/* how much bits are in the fifo? */
+
+	volatile __u8 usb_transfer_mode;	/* switched between ISO and INT */
+	iso_urb_struct iso[2];	/* need two urbs to have one always for pending */
+	__u8 ch_idx;		/* link BChannel Fifos to chan[ch_idx] */
+	int last_urblen;	/* remember length of last packet */
+} usb_fifo;
+
+typedef struct _hfcsusb_t {
+	struct list_head	list;
+	channel_t		chan[4]; // B1,B2,D,(PCM)
+
+	struct usb_device	*dev;		/* our device */
+	struct usb_interface	*intf;		/* used interface */
+	int			if_used;	/* used interface number */
+	int			alt_used;	/* used alternate config */
+	int			cfg_used;	/* configuration index used */
+	int			vend_idx;	/* index in hfcsusb_idtab */
+	int			packet_size;
+	int			iso_packet_size;
+	int			disc_flag;	/* 1 if device was disonnected to avoid some USB actions */
+	usb_fifo		fifos[HFCUSB_NUM_FIFOS];	/* structure holding all fifo data */
+
+	/* control pipe background handling */
+	ctrl_buft		ctrl_buff[HFC_CTRL_BUFSIZE];	/* buffer holding queued data */
+	volatile int		ctrl_in_idx, ctrl_out_idx, ctrl_cnt;	/* input/output pointer + count */
+	struct urb		*ctrl_urb;	/* transfer structure for control channel */
+	struct usb_ctrlrequest	ctrl_write;	/* buffer for control write request */
+	struct usb_ctrlrequest	ctrl_read;	/* same for read request */
+	int			ctrl_paksize;	/* control pipe packet size */
+	int			ctrl_in_pipe, ctrl_out_pipe;	/* handles for control pipe */
+	spinlock_t		ctrl_lock;	/* queueing ctrl urbs needs to be locked */
+	spinlock_t              lock;
+
+	volatile __u8		threshold_mask;	/* threshold in fifo flow control */
+	__u8			old_led_state, led_state;
+
+	__u8			portmode; /* TE ?, NT ?, NT Timer runnning? */
+	int			nt_timer;
+} hfcsusb_t;
+
+/* private vendor specific data */
+typedef struct {
+	__u8		led_scheme;	// led display scheme
+	signed short	led_bits[8];	// array of 8 possible LED bitmask settings
+	char		*vend_name;	// device name
+} hfcsusb_vdata;
+
+/****************************************/
+/* data defining the devices to be used */
+/****************************************/
+static struct usb_device_id hfcsusb_idtab[] = {
+	{
+	 USB_DEVICE(0x0959, 0x2bd0),
+	 .driver_info = (unsigned long) &((hfcsusb_vdata)
+			  {LED_OFF, {4, 0, 2, 1},
+			   "ISDN USB TA (Cologne Chip HFC-S USB based)"}),
+	},
+	{
+	 USB_DEVICE(0x0675, 0x1688),
+	 .driver_info = (unsigned long) &((hfcsusb_vdata)
+			  {LED_SCHEME1, {1, 2, 0, 0},
+			   "DrayTek miniVigor 128 USB ISDN TA"}),
+	},
+	{
+	 USB_DEVICE(0x07b0, 0x0007),
+	 .driver_info = (unsigned long) &((hfcsusb_vdata)
+			  {LED_SCHEME1, {0x80, -64, -32, -16},
+			   "Billion tiny USB ISDN TA 128"}),
+	},
+	{
+	 USB_DEVICE(0x0742, 0x2008),
+	 .driver_info = (unsigned long) &((hfcsusb_vdata)
+			  {LED_SCHEME1, {4, 0, 2, 1},
+			   "Stollmann USB TA"}),
+	},
+	{
+	 USB_DEVICE(0x0742, 0x2009),
+	 .driver_info = (unsigned long) &((hfcsusb_vdata)
+			  {LED_SCHEME1, {4, 0, 2, 1},
+			   "Aceex USB ISDN TA"}),
+	},
+	{
+	 USB_DEVICE(0x0742, 0x200A),
+	 .driver_info = (unsigned long) &((hfcsusb_vdata)
+			  {LED_SCHEME1, {4, 0, 2, 1},
+			   "OEM USB ISDN TA"}),
+	},
+	{
+	 USB_DEVICE(0x08e3, 0x0301),
+	 .driver_info = (unsigned long) &((hfcsusb_vdata)
+			  {LED_SCHEME1, {2, 0, 1, 4},
+			   "Olitec USB RNIS"}),
+	},
+	{
+	 USB_DEVICE(0x07fa, 0x0846),
+	 .driver_info = (unsigned long) &((hfcsusb_vdata)
+			  {LED_SCHEME1, {0x80, -64, -32, -16},
+			   "Bewan Modem RNIS USB"}),
+	},
+	{
+	 USB_DEVICE(0x07fa, 0x0847),
+	 .driver_info = (unsigned long) &((hfcsusb_vdata)
+			  {LED_SCHEME1, {0x80, -64, -32, -16},
+			   "Djinn Numeris USB"}),
+	},
+	{
+	 USB_DEVICE(0x07b0, 0x0006),
+	 .driver_info = (unsigned long) &((hfcsusb_vdata)
+			  {LED_SCHEME1, {0x80, -64, -32, -16},
+			   "Twister ISDN TA"}),
+	},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, hfcsusb_idtab);
+
+/* some function prototypes */
+static int	hfcsusb_l2l1(mISDNinstance_t *inst, struct sk_buff *skb);
+static int	setup_bchannel(channel_t * bch, int protocol);
+static void	hfcsusb_ph_command(hfcsusb_t * card, u_char command);
+static void	release_card(hfcsusb_t * card);
+
+
+/******************************************************/
+/* start next background transfer for control channel */
+/******************************************************/
+static void
+ctrl_start_transfer(hfcsusb_t * card)
+{
+	if (card->ctrl_cnt) {
+		card->ctrl_urb->pipe = card->ctrl_out_pipe;
+		card->ctrl_urb->setup_packet =
+		    (u_char *) & card->ctrl_write;
+		card->ctrl_urb->transfer_buffer = NULL;
+		card->ctrl_urb->transfer_buffer_length = 0;
+		card->ctrl_write.wIndex =
+		    cpu_to_le16(card->ctrl_buff[card->ctrl_out_idx].hfcs_reg);
+		card->ctrl_write.wValue =
+		    cpu_to_le16(card->ctrl_buff[card->ctrl_out_idx].reg_val);
+
+		usb_submit_urb(card->ctrl_urb, GFP_ATOMIC);	/* start transfer */
+	}
+}				/* ctrl_start_transfer */
+
+/************************************/
+/* queue a control transfer request */
+/* to write HFC-S USB register      */
+/* return 0 on success.             */
+/************************************/
+static int
+queued_Write_hfc(hfcsusb_t * card, __u8 reg, __u8 val)
+{
+	ctrl_buft *buf;
+
+	spin_lock(&card->ctrl_lock);
+	if (card->ctrl_cnt >= HFC_CTRL_BUFSIZE)
+		return (1);	/* no space left */
+	buf = &card->ctrl_buff[card->ctrl_in_idx];	/* pointer to new index */
+	buf->hfcs_reg = reg;
+	buf->reg_val = val;
+	if (++card->ctrl_in_idx >= HFC_CTRL_BUFSIZE)
+		card->ctrl_in_idx = 0;	/* pointer wrap */
+	if (++card->ctrl_cnt == 1)
+		ctrl_start_transfer(card);
+	spin_unlock(&card->ctrl_lock);
+
+	return (0);
+}
+
+/***************************************************************/
+/* control completion routine handling background control cmds */
+/***************************************************************/
+static void
+ctrl_complete(struct urb *urb, struct pt_regs *regs)
+{
+	hfcsusb_t *card = (hfcsusb_t *) urb->context;
+	ctrl_buft *buf;
+
+	urb->dev = card->dev;
+	if (card->ctrl_cnt) {
+		buf = &card->ctrl_buff[card->ctrl_out_idx];
+		card->ctrl_cnt--;	/* decrement actual count */
+		if (++card->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
+			card->ctrl_out_idx = 0;	/* pointer wrap */
+
+		ctrl_start_transfer(card);	/* start next transfer */
+	}
+}
+
+/***************************************************/
+/* write led data to auxport & invert if necessary */
+/***************************************************/
+static void
+write_led(hfcsusb_t * card, __u8 led_state)
+{
+	if (led_state != card->old_led_state) {
+		card->old_led_state = led_state;
+		queued_Write_hfc(card, HFCUSB_P_DATA, led_state);
+	}
+}
+
+/*********************/
+/* handle LED bits   */
+/*********************/
+static void
+set_led_bit(hfcsusb_t * card, signed short led_bits, int unset)
+{
+	if (unset) {
+		if (led_bits < 0)
+			card->led_state |= abs(led_bits);
+		else
+			card->led_state &= ~led_bits;
+	} else {
+		if (led_bits < 0)
+			card->led_state &= ~abs(led_bits);
+		else
+			card->led_state |= led_bits;
+	}
+}
+
+/************************/
+/* handle LED requests  */
+/************************/
+static void
+handle_led(hfcsusb_t * card, int event)
+{
+	hfcsusb_vdata *driver_info =
+	    (hfcsusb_vdata *) hfcsusb_idtab[card->vend_idx].driver_info;
+
+	if (driver_info->led_scheme == LED_OFF) {
+		return;
+	}
+
+	switch (event) {
+		case LED_POWER_ON:
+			set_led_bit(card, driver_info->led_bits[0], 0);
+			set_led_bit(card, driver_info->led_bits[1], 1);
+			set_led_bit(card, driver_info->led_bits[2], 1);
+			set_led_bit(card, driver_info->led_bits[3], 1);
+			break;
+		case LED_POWER_OFF:
+			set_led_bit(card, driver_info->led_bits[0], 1);
+			set_led_bit(card, driver_info->led_bits[1], 1);
+			set_led_bit(card, driver_info->led_bits[2], 1);
+			set_led_bit(card, driver_info->led_bits[3], 1);
+			break;
+		case LED_S0_ON:
+			set_led_bit(card, driver_info->led_bits[1], 0);
+			break;
+		case LED_S0_OFF:
+			set_led_bit(card, driver_info->led_bits[1], 1);
+			break;
+		case LED_B1_ON:
+			set_led_bit(card, driver_info->led_bits[2], 0);
+			break;
+		case LED_B1_OFF:
+			set_led_bit(card, driver_info->led_bits[2], 1);
+			break;
+		case LED_B2_ON:
+			set_led_bit(card, driver_info->led_bits[3], 0);
+			break;
+		case LED_B2_OFF:
+			set_led_bit(card, driver_info->led_bits[3], 1);
+			break;
+	}
+	write_led(card, card->led_state);
+}
+
+
+/*********************************/
+/* S0 state change event handler */
+/*********************************/
+static void
+S0_new_state(channel_t * dch)
+{
+	u_int		prim = PH_SIGNAL | INDICATION;
+	u_int		para = 0;
+	hfcsusb_t	*card = dch->inst.privat;
+
+	if (card->portmode & PORT_MODE_TE) {
+		if (dch->debug)
+			mISDN_debugprint(&card->chan[D].inst,
+				 "%s: TE %d",
+				 __FUNCTION__, dch->state);
+
+		switch (dch->state) {
+			case (0):
+				prim = PH_CONTROL | INDICATION;
+				para = HW_RESET;
+				break;
+			case (3):
+				prim = PH_CONTROL | INDICATION;
+				para = HW_DEACTIVATE;
+				handle_led(card, LED_S0_OFF);
+				break;
+			case (5):
+			case (8):
+				para = ANYSIGNAL;
+				break;
+			case (6):
+				para = INFO2;
+				break;
+			case (7):
+				para = INFO4_P8;
+				handle_led(card, LED_S0_ON);
+				break;
+			default:
+				return;
+		}
+		if (dch->state== 7)
+			test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+		else
+			test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+
+	} else {
+		if (dch->debug)
+			mISDN_debugprint(&card->chan[D].inst,
+				 "%s: NT %d",
+				 __FUNCTION__, dch->state);
+
+		switch (dch->state) {
+			case (1):
+				test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+				card->nt_timer = 0;
+				card->portmode &= ~NT_ACTIVATION_TIMER;
+				prim = PH_DEACTIVATE | INDICATION;
+				para = 0;
+				handle_led(card, LED_S0_OFF);
+				break;
+
+			case (2):
+				if (card->nt_timer < 0) {
+					card->nt_timer = 0;
+					card->portmode &= ~NT_ACTIVATION_TIMER;
+					hfcsusb_ph_command(dch->hw, HFC_L1_DEACTIVATE_NT);
+				} else {
+					card->portmode |= NT_ACTIVATION_TIMER;
+					card->nt_timer = NT_T1_COUNT;
+					/* allow G2 -> G3 transition */
+					queued_Write_hfc(card, HFCUSB_STATES, 2 | HFCUSB_NT_G2_G3);
+				}
+				return;
+			case (3):
+				test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+				card->nt_timer = 0;
+				card->portmode &= ~NT_ACTIVATION_TIMER;
+				prim = PH_ACTIVATE | CONFIRM;
+				para = 0;
+				handle_led(card, LED_S0_ON);
+				break;
+			case (4):
+				card->nt_timer = 0;
+				card->portmode &= ~NT_ACTIVATION_TIMER;
+				return;
+			default:
+				break;
+		}
+		mISDN_queue_data(&dch->inst, dch->inst.id | MSG_BROADCAST,
+			MGR_SHORTSTATUS | INDICATION, test_bit(FLG_ACTIVE, &dch->Flags) ?
+			SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED,
+			0, NULL, 0);
+	}
+	mISDN_queue_data(&dch->inst, FLG_MSG_UP, prim, para, 0, NULL, 0);
+}
+
+/******************************/
+/* trigger S0 state changes   */
+/******************************/
+static void
+state_handler(hfcsusb_t * card, __u8 new_l1_state)
+{
+	if (new_l1_state == card->chan[D].state
+	    || new_l1_state < 1 || new_l1_state > 8)
+		return;
+
+	card->chan[D].state = new_l1_state;
+	S0_new_state(&card->chan[D]);
+}
+
+/*
+ * B-channel setup routine, setup the selected B-channel mode for a given
+ * protocol
+ * It also maybe change the B-channel timeslot to match the allocated slot
+ *
+ * basic protocol values
+ *	-1			used for first time setup during init
+ *	ISDN_PID_NONE		unused channel, idle mode (disconnected)
+ *	ISDN_PID_L1_B_64TRANS   64 kBit transparent
+ *	ISDN_PID_L1_B_64HDLC	64 kBit HDLC framing
+ *
+ *	if the hardware supports more protocols, they should be handled too
+ */
+static int
+setup_bchannel(channel_t * bch, int protocol)
+{
+	__u8 conhdlc, sctrl, sctrl_r;	/* conatainer for new register vals */
+
+	hfcsusb_t *card = bch->inst.privat;
+
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst,
+				 "protocol %x-->%x channel(%d)",
+				 bch->state, protocol,
+				 bch->channel);
+
+	/* setup val for CON_HDLC */
+	conhdlc = 0;
+	if (protocol > ISDN_PID_NONE)
+		conhdlc = 8;	/* enable FIFO */
+
+	switch (protocol) {
+		case (-1):	/* used for init */
+			bch->state = -1;
+			/* fall trough */
+		case (ISDN_PID_NONE):
+			if (bch->state == ISDN_PID_NONE)
+				return (0);	/* already in idle state */
+			bch->state = ISDN_PID_NONE;
+			test_and_clear_bit(FLG_HDLC, &bch->Flags);
+			test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
+			break;
+		case (ISDN_PID_L1_B_64TRANS):
+			conhdlc |= 2;
+			bch->state = protocol;
+			set_bit(FLG_TRANSPARENT, &bch->Flags);
+			break;
+		case (ISDN_PID_L1_B_64HDLC):
+			bch->state = protocol;
+			set_bit(FLG_HDLC, &bch->Flags);
+			break;
+		default:
+			mISDN_debugprint(&bch->inst, "prot not known %x",
+					 protocol);
+			return (-ENOPROTOOPT);
+	}
+
+	if (protocol >= ISDN_PID_NONE) {
+		/*
+		printk ("HFCS-USB: %s: HFCUSB_FIFO(0x%x) HFCUSB_CON_HDLC(0x%x)\n",
+			__FUNCTION__, (bch->channel)?2:0, conhdlc);
+		*/
+
+		/* set FIFO to transmit register */
+		queued_Write_hfc(card, HFCUSB_FIFO,
+				      (bch->channel)?2:0);
+		queued_Write_hfc(card, HFCUSB_CON_HDLC, conhdlc);
+
+		/* reset fifo */
+		queued_Write_hfc(card, HFCUSB_INC_RES_F, 2);
+
+		/*
+		printk ("HFCS-USB: %s: HFCUSB_FIFO(0x%x) HFCUSB_CON_HDLC(0x%x)\n",
+			__FUNCTION__, (bch->channel)?2:0, conhdlc);
+		*/
+
+		/* set FIFO to receive register */
+		queued_Write_hfc(card, HFCUSB_FIFO,
+				      ((bch->channel)?3:1));
+		queued_Write_hfc(card, HFCUSB_CON_HDLC, conhdlc);
+
+		/* reset fifo */
+		queued_Write_hfc(card, HFCUSB_INC_RES_F, 2);
+
+		sctrl = 0x40 + ((card->portmode & PORT_MODE_TE)?0x00:0x04);
+		sctrl_r = 0x0;
+
+		if (card->chan[B1].state) {
+			sctrl |= ((card->chan[B1].channel)?2:1);
+			sctrl_r |= ((card->chan[B1].channel)?2:1);
+		}
+
+		if (card->chan[B2].state) {
+			sctrl |= ((card->chan[B2].channel)?2:1);
+			sctrl_r |= ((card->chan[B2].channel)?2:1);
+		}
+
+		/*
+		printk ("HFCS-USB: %s: HFCUSB_SCTRL(0x%x) HFCUSB_SCTRL_R(0x%x)\n",
+			__FUNCTION__, sctrl, sctrl_r);
+		*/
+
+		queued_Write_hfc(card, HFCUSB_SCTRL, sctrl);
+		queued_Write_hfc(card, HFCUSB_SCTRL_R, sctrl_r);
+
+		if (protocol > ISDN_PID_NONE) {
+			handle_led(card, ((bch->channel)?LED_B2_ON:LED_B1_ON));
+		} else {
+			handle_led(card, ((bch->channel)?LED_B2_OFF:LED_B1_OFF));
+		}
+	}
+	return (0);
+}
+
+static void
+hfcsusb_ph_command(hfcsusb_t * card, u_char command)
+{
+	if (card->chan[D].debug & L1_DEB_ISAC)
+		mISDN_debugprint(&card->chan[D].inst, "hfcsusb_ph_command %x",
+				 command);
+
+	switch (command) {
+		case HFC_L1_ACTIVATE_TE:
+			/* force sending sending INFO1 */
+			queued_Write_hfc(card, HFCUSB_STATES, 0x14);
+			/* start l1 activation */
+			queued_Write_hfc(card, HFCUSB_STATES, 0x04);
+			break;
+
+		case HFC_L1_FORCE_DEACTIVATE_TE:
+			queued_Write_hfc(card, HFCUSB_STATES, 0x10);
+			queued_Write_hfc(card, HFCUSB_STATES, 0x03);
+			break;
+
+		case HFC_L1_ACTIVATE_NT:
+			if (card->chan[D].state == 3) {
+				mISDN_queue_data(&card->chan[D].inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION, 0, 0, NULL, 0);
+			} else {
+				queued_Write_hfc(card, HFCUSB_STATES,
+				                       HFCUSB_ACTIVATE
+				                       | HFCUSB_DO_ACTION
+				                       | HFCUSB_NT_G2_G3);
+			}
+			break;
+
+		case HFC_L1_DEACTIVATE_NT:
+			queued_Write_hfc(card, HFCUSB_STATES,
+			 		       HFCUSB_DO_ACTION);
+			break;
+	}
+}
+
+/*************************************/
+/* Layer 1 D-channel hardware access */
+/*************************************/
+static int
+handle_dmsg(channel_t *dch, struct sk_buff *skb)
+{
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	hfcsusb_t	*hw = dch->hw;
+
+	if (hh->prim == (PH_SIGNAL | REQUEST)) {
+		ret = -EINVAL;
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		if (hh->dinfo == HW_RESET) {
+			if (dch->state != 0)
+				hfcsusb_ph_command(hw, HFC_L1_ACTIVATE_TE);
+			skb_trim(skb, 0);
+			return(mISDN_queueup_newhead(&dch->inst, 0, PH_CONTROL | INDICATION,HW_POWERUP, skb));
+		} else if (hh->dinfo == HW_DEACTIVATE) {
+			if (dch->next_skb) {
+				dev_kfree_skb(dch->next_skb);
+				dch->next_skb = NULL;
+			}
+			test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+#ifdef FIXME
+			if (test_and_clear_bit(FLG_L1_DBUSY, &dch->Flags))
+				dchannel_sched_event(dch, D_CLEARBUSY);
+#endif
+		} else if (hh->dinfo == HW_POWERUP) {
+			hfcsusb_ph_command(hw, HFC_L1_FORCE_DEACTIVATE_TE);
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst,
+					"hfcsusb_l1hw unknown ctrl %x",
+					hh->dinfo);
+			ret = -EINVAL;
+		}
+	} else if (hh->prim == (PH_ACTIVATE | REQUEST)) {
+		if (hw->portmode & PORT_MODE_NT) {
+			hfcsusb_ph_command(hw, HFC_L1_ACTIVATE_NT);
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst,
+					"%s: PH_ACTIVATE none NT mode",
+					__FUNCTION__);
+			ret = -EINVAL;
+		}
+	} else if (hh->prim == (PH_DEACTIVATE | REQUEST)) {
+		if (hw->portmode & PORT_MODE_NT) {
+			hfcsusb_ph_command(hw, HFC_L1_DEACTIVATE_NT);
+			if (test_and_clear_bit(FLG_TX_NEXT, &dch->Flags)) {
+				dev_kfree_skb(dch->next_skb);
+				dch->next_skb = NULL;
+			}
+			if (dch->tx_skb) {
+				dev_kfree_skb(dch->tx_skb);
+				dch->tx_skb = NULL;
+			}
+			dch->tx_idx = 0;
+			if (dch->rx_skb) {
+				dev_kfree_skb(dch->rx_skb);
+				dch->rx_skb = NULL;
+			}
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+			test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst,
+					"%s: PH_DEACTIVATE none NT mode",
+					__FUNCTION__);
+			ret = -EINVAL;
+		}
+	} else if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS) {
+		u_int temp = hh->dinfo & SSTATUS_ALL; // remove SSTATUS_BROADCAST_BIT
+		if ((hw->portmode & PORT_MODE_NT) &&
+			(temp == SSTATUS_ALL || temp == SSTATUS_L1)) {
+			if (hh->dinfo & SSTATUS_BROADCAST_BIT)
+				temp = dch->inst.id | MSG_BROADCAST;
+			else
+				temp = hh->addr | FLG_MSG_TARGET;
+			skb_trim(skb, 0);
+			hh->dinfo = test_bit(FLG_ACTIVE, &dch->Flags) ?
+				SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED;
+			hh->prim = MGR_SHORTSTATUS | CONFIRM;
+			return(mISDN_queue_message(&dch->inst, temp, skb));
+		}
+		ret = -EOPNOTSUPP;
+	} else {
+		printk(KERN_WARNING "%s %s: unknown prim(%x)\n",
+		       dch->inst.name, __FUNCTION__, hh->prim);
+		ret = -EAGAIN;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return (ret);
+}
+
+/*************************************/
+/* Layer 1 B-channel hardware access */
+/*************************************/
+static int
+handle_bmsg(channel_t *bch, struct sk_buff *skb)
+{
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	hfcsusb_t       *hw = bch->hw;
+	u_long		flags;
+
+	if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_ESTABLISH | REQUEST))) {
+		spin_lock_irqsave(&hw->lock, flags);
+		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
+			ret = setup_bchannel(bch, bch->inst.pid.protocol[1]);
+			if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				test_and_set_bit(FLG_L2DATA, &bch->Flags);
+		}
+		spin_unlock_irqrestore(&hw->lock, flags);
+#ifdef FIXME
+		if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+			if (bch->dev)
+				if_link(&bch->dev->rport.pif,
+					hh->prim | CONFIRM, 0, 0, NULL, 0);
+#endif
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, ret, skb));
+	} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_RELEASE | REQUEST)) ||
+		((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
+
+		spin_lock_irqsave(&hw->lock, flags);
+		if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+			dev_kfree_skb(bch->next_skb);
+			bch->next_skb = NULL;
+		}
+		if (bch->tx_skb) {
+			dev_kfree_skb(bch->tx_skb);
+			bch->tx_skb = NULL;
+		}
+		bch->tx_idx = 0;
+		if (bch->rx_skb) {
+			dev_kfree_skb(bch->rx_skb);
+			bch->rx_skb = NULL;
+		}
+		test_and_clear_bit(FLG_L2DATA, &bch->Flags);
+		test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		setup_bchannel(bch, ISDN_PID_NONE);
+		test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+		spin_unlock_irqrestore(&hw->lock, flags);
+		skb_trim(skb, 0);
+		if (hh->prim != (PH_CONTROL | REQUEST)) {
+#ifdef FIXME
+			if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+				if (bch->dev)
+					if_link(&bch->dev->rport.pif,
+						hh->prim | CONFIRM, 0, 0, NULL, 0);
+#endif
+			if (!mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, 0, skb))
+				return(0);
+		}
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		// do not handle PH_CONTROL | REQUEST ??
+	} else {
+		printk(KERN_WARNING "%s %s: unknown prim(%x)\n",
+			bch->inst.name, __FUNCTION__, hh->prim);
+		ret = -EAGAIN;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return (ret);
+}
+
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+static int
+hfcsusb_l2l1(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*chan = container_of(inst, channel_t, inst);
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+	int		i;
+
+	if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		ret = channel_senddata(chan, hh->dinfo, skb);
+		if (ret > 0) {
+
+			if (!(chan)) {
+				printk (KERN_INFO "HFC-S USB: CRITICAL ERROR! chan is NULL pointer!\n");
+				spin_unlock_irqrestore(inst->hwlock, flags);
+				return(-EINVAL);
+			}
+
+			if (!(chan->tx_skb)) {
+				printk (KERN_INFO "HFC-S USB: CRITICAL ERROR! channel_senddata returned %d without chan->tx_skb\n", ret);
+				spin_unlock_irqrestore(inst->hwlock, flags);
+				return(-EINVAL);
+			}
+
+			/* channel data debug: */
+			if ((chan->debug) && (debug & DEBUG_HFC_FIFO)) {
+				mISDN_debugprint(&chan->inst,
+					"new TX channel(%i) len(%i): ",
+					chan->channel, chan->tx_skb->len);
+				i = 0;
+				printk("  ");
+				while (i < chan->tx_skb->len)
+					printk("%02x ", chan->tx_skb->data[i++]);
+				printk("\n");
+			}
+
+			/* data gets transmitted later in USB ISO OUT traffic */
+			ret = 0;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		return(ret);
+	}
+	if (test_bit(FLG_DCHANNEL, &chan->Flags)) {
+		ret = handle_dmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (test_bit(FLG_BCHANNEL, &chan->Flags)) {
+		ret = handle_bmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+
+static int
+hfcsusb_manager(void *data, u_int prim, void *arg)
+{
+	hfcsusb_t *hw = NULL;
+	mISDNinstance_t *inst = data;
+	struct sk_buff *skb;
+	int channel = -1;
+	int i;
+	channel_t *chan = NULL;
+	u_long flags;
+
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim, arg, &hw_mISDNObj)
+		    printk(KERN_ERR "%s %s: no data prim %x arg %p\n",
+			   hw->chan[D].inst.name, __FUNCTION__, prim, arg);
+		return (-EINVAL);
+	}
+
+	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+
+	/* find channel and card */
+	list_for_each_entry(hw, &hw_mISDNObj.ilist, list) {
+		i = 0;
+		while (i < MAX_CHAN) {
+			if (hw->chan[i].Flags &&
+				&hw->chan[i].inst == inst) {
+				channel = i;
+				chan = &hw->chan[i];
+				break;
+			}
+			i++;
+		}
+		if (channel >= 0)
+			break;
+	}
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+
+	if (channel < 0) {
+		printk(KERN_ERR
+		       "%s: no card/channel found  data %p prim %x arg %p\n",
+		       __FUNCTION__, data, prim, arg);
+		return (-EINVAL);
+	}
+
+	switch (prim) {
+		case MGR_REGLAYER | CONFIRM:
+			mISDN_setpara(chan, &inst->st->para);
+			break;
+		case MGR_UNREGLAYER | REQUEST:
+			if ((skb = create_link_skb(PH_CONTROL | REQUEST,
+				HW_DEACTIVATE, 0, NULL, 0))) {
+				if (hfcsusb_l2l1(inst, skb))
+					dev_kfree_skb(skb);
+			} else
+				printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
+			mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+			break;
+		case MGR_CLRSTPARA | INDICATION:
+			arg = NULL;
+		case MGR_ADDSTPARA | INDICATION:
+			mISDN_setpara(chan, arg);
+			break;
+		case MGR_RELEASE | INDICATION:
+			if (channel == 2) {
+				release_card(hw);
+			} else {
+				hw_mISDNObj.refcnt--;
+			}
+			break;
+		case MGR_SETSTACK | INDICATION:
+			if ((channel != 2) && (inst->pid.global == 2)) {
+				if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
+					0, 0, NULL, 0))) {
+					if (hfcsusb_l2l1(inst, skb))
+						dev_kfree_skb(skb);
+				}
+				if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+					mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
+						0, 0, NULL, 0);
+				else
+					mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
+						0, 0, NULL, 0);
+			}
+			break;
+		case MGR_GLOBALOPT | REQUEST:
+			if (arg) {
+				// FIXME: detect cards with HEADSET
+				u_int *gopt = arg;
+				*gopt = GLOBALOPT_INTERNAL_CTRL |
+				    GLOBALOPT_EXTERNAL_EQUIPMENT |
+				    GLOBALOPT_HANDSET;
+			} else
+				return (-EINVAL);
+			break;
+		case MGR_SELCHANNEL | REQUEST:
+			// no special procedure
+			return (-EINVAL);
+			PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+		default:
+			printk(KERN_WARNING "%s %s: prim %x not handled\n",
+			       hw->chan[D].inst.name, __FUNCTION__, prim);
+			return (-EINVAL);
+	}
+	return (0);
+}
+
+
+/***********************************************/
+/* collect data from interrupt or isochron in  */
+/***********************************************/
+static void
+collect_rx_frame(usb_fifo * fifo, __u8 * data, unsigned int len, int finish)
+{
+	hfcsusb_t	*card = fifo->card;
+	channel_t	*ch = &card->chan[fifo->ch_idx];
+	struct sk_buff	*skb;	/* data buffer for upper layer */
+	int		fifon;
+	int		i;
+
+	if (!len)
+		return;
+
+	fifon = fifo->fifonum;
+
+	if (!ch->rx_skb) {
+		if (ch->debug)
+			printk(KERN_INFO "alloc new skb for fifon(%d), len(%d+%d)\n",
+				fifon, ch->maxlen + 3, ch->up_headerlen);
+		ch->rx_skb = alloc_stack_skb(ch->maxlen + 3, ch->up_headerlen);
+		if (!ch->rx_skb) {
+			if (ch->debug)
+				printk(KERN_DEBUG "%s: No mem for rx_skb\n", __FUNCTION__);
+			return;
+		}
+		skb_trim(ch->rx_skb, 0);
+	}
+
+	if (fifon == HFCUSB_D_RX) {
+		/* D-Channel SKK range check */
+		if ((ch->rx_skb->len + len) >= MAX_DFRAME_LEN_L1) {
+			if (ch->debug)
+				printk(KERN_DEBUG "%s: sbk mem exceeded for fifo(%d) HFCUSB_D_RX\n",
+			       __FUNCTION__, fifon);
+			skb_trim(ch->rx_skb, 0);
+			return;
+		}
+	} else {
+		/* B-Channel SKB range check */
+		if ((ch->rx_skb->len + len) >= (MAX_BCH_SIZE + 3)) {
+			if (ch->debug)
+				printk(KERN_DEBUG "%s: sbk mem exceeded for fifo(%d) HFCUSB_B_RX\n",
+			       __FUNCTION__, fifon);
+			skb_trim(ch->rx_skb, 0);
+			return;
+		}
+	}
+
+	// printk ("skb_put: len(%d) new_len(%d)", ch->rx_skb->len, len);
+	memcpy(skb_put(ch->rx_skb, len), data, len);
+
+	if (test_bit(FLG_HDLC, &ch->Flags)) {
+		/* we have a complete hdlc packet */
+		if (finish) {
+			if ((ch->rx_skb->len > 3) &&
+			   (!(ch->rx_skb->data[ch->rx_skb->len - 1]))) {
+
+				if ((ch->debug) && (debug & DEBUG_HFC_FIFO)) {
+					mISDN_debugprint(&ch->inst,
+						"fifon(%i) new RX len(%i): ",
+						fifon, ch->rx_skb->len);
+					i = 0;
+					printk("  ");
+					while (i < ch->rx_skb->len)
+						printk("%02x ", ch->rx_skb->data[i++]);
+					printk("\n");
+				}
+
+				/* remove CRC & status */
+				skb_trim(ch->rx_skb, ch->rx_skb->len - 3);
+
+				if (ch->rx_skb->len < MISDN_COPY_SIZE) {
+					skb = alloc_stack_skb(ch->rx_skb->len, ch->up_headerlen);
+					if (skb) {
+						memcpy(skb_put(skb, ch->rx_skb->len),
+							ch->rx_skb->data, ch->rx_skb->len);
+						skb_trim(ch->rx_skb, 0);
+					} else {
+						skb = ch->rx_skb;
+						ch->rx_skb = NULL;
+					}
+				} else {
+					skb = ch->rx_skb;
+					ch->rx_skb = NULL;
+				}
+				queue_ch_frame(ch, INDICATION, MISDN_ID_ANY, skb);
+			} else {
+				if (ch->debug) {
+					printk ("HFC-S USB: CRC or minlen ERROR fifon(%i) RX len(%i): ",
+						fifon, ch->rx_skb->len);
+					i = 0;
+					printk("  ");
+					while (i < ch->rx_skb->len)
+						printk("%02x ", ch->rx_skb->data[i++]);
+					printk("\n");
+				}
+				skb_trim(ch->rx_skb, 0);
+			}
+		}
+	} else {
+		if (finish || ch->rx_skb->len >= poll) {
+			if (ch->debug)
+				printk(KERN_DEBUG "%s: queueing transp data fifon(%i) (%i)\n",
+					__FUNCTION__, fifon, ch->rx_skb->len);
+
+			/* deliver transparent data to layer2 */
+			queue_ch_frame(ch, INDICATION, MISDN_ID_ANY, ch->rx_skb);
+			ch->rx_skb = NULL;
+		}
+	}
+}
+
+void
+fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
+	      void *buf, int num_packets, int packet_size, int interval,
+	      usb_complete_t complete, void *context)
+{
+	int k;
+
+	spin_lock_init(&urb->lock);
+	urb->dev = dev;
+	urb->pipe = pipe;
+	urb->complete = complete;
+	urb->number_of_packets = num_packets;
+	urb->transfer_buffer_length = packet_size * num_packets;
+	urb->context = context;
+	urb->transfer_buffer = buf;
+	urb->transfer_flags = URB_ISO_ASAP;
+	urb->actual_length = 0;
+	urb->interval = interval;
+	for (k = 0; k < num_packets; k++) {
+		urb->iso_frame_desc[k].offset = packet_size * k;
+		urb->iso_frame_desc[k].length = packet_size;
+		urb->iso_frame_desc[k].actual_length = 0;
+	}
+}
+
+/*****************************************************/
+/* receive completion routine for all ISO tx fifos   */
+/*****************************************************/
+static void
+rx_iso_complete(struct urb *urb, struct pt_regs *regs)
+{
+	iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
+	usb_fifo *fifo = context_iso_urb->owner_fifo;
+	hfcsusb_t *card = fifo->card;
+	channel_t *ch = &card->chan[fifo->ch_idx];
+	int k, len, errcode, offset, num_isoc_packets, fifon, maxlen,
+	    status;
+	unsigned int iso_status;
+	__u8 *buf;
+	static __u8 eof[8];
+
+	fifon = fifo->fifonum;
+	status = urb->status;
+
+	if (fifo->active && !status) {
+		num_isoc_packets = iso_packets[fifon];
+		maxlen = fifo->usb_packet_maxlen;
+
+		for (k = 0; k < num_isoc_packets; ++k) {
+
+			len = urb->iso_frame_desc[k].actual_length;
+			offset = urb->iso_frame_desc[k].offset;
+			buf = context_iso_urb->buffer + offset;
+			iso_status = urb->iso_frame_desc[k].status;
+
+			if (iso_status && !card->disc_flag)
+				if (ch->debug)
+					printk(KERN_INFO
+				       "HFC-S USB: ISO packet failure - status:%x",
+				       iso_status);
+
+			/*
+			USB data log for every ISO in:
+			if (fifon == 1) {
+				printk ("(%d/%d) len(%d) ", k, num_isoc_packets-1, len);
+				for (i=0; i<len; i++) {
+					printk ("%x ", buf[i]);
+				}
+				printk ("\n");
+			}
+			*/
+
+			if (fifo->last_urblen != maxlen) {
+				/* the threshold mask is in the 2nd status byte */
+				card->threshold_mask = buf[1];
+				/* care for L1 state only for D-Channel
+				   to avoid overlapped iso completions */
+
+				if (fifon == HFCUSB_D_RX) {
+					/* the S0 state is in the upper half
+					   of the 1st status byte */
+					state_handler(card, buf[0] >> 4);
+				}
+
+				eof[fifon] = buf[0] & 1;
+				if (len > 2)
+					collect_rx_frame(fifo, buf + 2,
+							 len - 2,
+							 (len < maxlen) ? eof[fifon] : 0);
+			} else {
+				collect_rx_frame(fifo, buf, len,
+						 (len <
+						  maxlen) ? eof[fifon] :
+						 0);
+			}
+			fifo->last_urblen = len;
+		}
+
+		fill_isoc_urb(urb, fifo->card->dev, fifo->pipe,
+			      context_iso_urb->buffer, num_isoc_packets,
+			      fifo->usb_packet_maxlen, fifo->intervall,
+			      (usb_complete_t)rx_iso_complete, urb->context);
+		errcode = usb_submit_urb(urb, GFP_ATOMIC);
+		if (errcode < 0) {
+			if (ch->debug)
+				printk(KERN_INFO
+			       "HFC-S USB: error submitting ISO URB: %d\n",
+			       errcode);
+		}
+	} else {
+		if (status && !card->disc_flag) {
+			if (ch->debug)
+				printk(KERN_INFO
+					"HFC-S USB: rx_iso_complete : "
+					"urb->status %d, fifonum %d\n",
+					status, fifon);
+		}
+	}
+}				/* rx_iso_complete */
+
+
+/*********************************************************/
+/* receive completion routine for all interrupt rx fifos */
+/*********************************************************/
+static void
+rx_int_complete(struct urb *urb, struct pt_regs *regs)
+{
+	int len;
+	int status;
+	__u8 *buf, maxlen, fifon;
+	usb_fifo *fifo = (usb_fifo *) urb->context;
+	hfcsusb_t *card = fifo->card;
+	channel_t *ch = &card->chan[fifo->ch_idx];
+	static __u8 eof[8];
+
+	urb->dev = card->dev;	/* security init */
+
+	fifon = fifo->fifonum;
+	if ((!fifo->active) || (urb->status)) {
+		if (ch->debug)
+			printk(KERN_INFO
+				"HFC-S USB: RX-Fifo %i is going down (%i)\n", fifon,
+				urb->status);
+
+		fifo->urb->interval = 0;	/* cancel automatic rescheduling */
+		return;
+	}
+	len = urb->actual_length;
+	buf = fifo->buffer;
+	maxlen = fifo->usb_packet_maxlen;
+
+	/*
+	USB data log for every INT in:
+	if (fifon == 1) {
+		printk ("fifon %d len %d: ", fifon, len);
+		for (i=0; i<len; i++) {
+			printk ("%x ", buf[i]);
+		}
+		printk ("\n");
+	}
+	*/
+
+	if (fifo->last_urblen != fifo->usb_packet_maxlen) {
+		/* the threshold mask is in the 2nd status byte */
+		card->threshold_mask = buf[1];
+
+		/* the S0 state is in the upper half of the 1st status byte */
+		state_handler(card, buf[0] >> 4);
+
+		eof[fifon] = buf[0] & 1;
+		/* if we have more than the 2 status bytes -> collect data */
+		if (len > 2)
+			collect_rx_frame(fifo, buf + 2,
+					 urb->actual_length - 2,
+					 (len < maxlen) ? eof[fifon] : 0);
+	} else {
+		collect_rx_frame(fifo, buf, urb->actual_length,
+				 (len < maxlen) ? eof[fifon] : 0);
+	}
+	fifo->last_urblen = urb->actual_length;
+
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status) {
+		if (ch->debug)
+			printk(KERN_INFO
+				"HFC-S USB: error resubmitting URN at rx_int_complete...\n");
+	}
+}				/* rx_int_complete */
+
+
+/***********************************/
+/* check if new buffer for channel */
+/* is waitinng is transmitt queue  */
+/***********************************/
+int
+next_tx_frame(hfcsusb_t * hw, __u8 channel)
+{
+	int i;
+	channel_t *ch = &hw->chan[channel];
+
+	if (ch->tx_skb)
+		dev_kfree_skb(ch->tx_skb);
+	if (test_and_clear_bit(FLG_TX_NEXT, &ch->Flags)) {
+		ch->tx_skb = ch->next_skb;
+		if (ch->tx_skb) {
+			mISDN_head_t *hh = mISDN_HEAD_P(ch->tx_skb);
+			ch->next_skb = NULL;
+			test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
+			ch->tx_idx = 0;
+
+			/* channel data debug: */
+			if ((ch->debug) && (debug & DEBUG_HFC_FIFO)) {
+				mISDN_debugprint(&ch->inst,
+					"new TX channel(%i) len(%i): ",
+					ch->channel, ch->tx_skb->len);
+				i = 0;
+				printk("  ");
+				while (i < ch->tx_skb->len)
+					printk("%02x ", ch->tx_skb->data[i++]);
+				printk(" (TX_NEXT)\n");
+			}
+
+			queue_ch_frame(ch, CONFIRM, hh->dinfo, NULL);
+			return (1);
+		} else {
+			printk(KERN_WARNING
+			       "%s channel(%i) TX_NEXT without skb\n",
+			       ch->inst.name, channel);
+			test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
+		}
+	} else
+		ch->tx_skb = NULL;
+	test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
+	return (0);
+}
+
+
+/*****************************************************/
+/* transmit completion routine for all ISO tx fifos */
+/*****************************************************/
+static void
+tx_iso_complete(struct urb *urb, struct pt_regs *regs)
+{
+	iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
+	usb_fifo *fifo = context_iso_urb->owner_fifo;
+	hfcsusb_t *card = fifo->card;
+	channel_t *ch = &card->chan[fifo->ch_idx];
+	int k, tx_offset, num_isoc_packets, sink, remain, current_len,
+	    errcode;
+	int i;
+	int frame_complete, fifon, status;
+	__u8 threshbit;
+	__u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80 };
+
+	fifon = fifo->fifonum;
+	status = urb->status;
+
+	tx_offset = 0;
+
+	if (fifo->active && !status) {
+		/* is FifoFull-threshold set for our channel? */
+		threshbit = threshtable[fifon] & card->threshold_mask;
+		num_isoc_packets = iso_packets[fifon];
+
+		/* predict dataflow to avoid fifo overflow */
+		if (fifon >= HFCUSB_D_TX) {
+			sink = (threshbit) ? SINK_DMIN : SINK_DMAX;
+		} else {
+			sink = (threshbit) ? SINK_MIN : SINK_MAX;
+		}
+		fill_isoc_urb(urb, fifo->card->dev, fifo->pipe,
+			      context_iso_urb->buffer, num_isoc_packets,
+			      fifo->usb_packet_maxlen, fifo->intervall,
+			      (usb_complete_t)tx_iso_complete, urb->context);
+		memset(context_iso_urb->buffer, 0,
+		       sizeof(context_iso_urb->buffer));
+		frame_complete = 0;
+
+
+		/* Generate next Iso Packets */
+		for (k = 0; k < num_isoc_packets; ++k) {
+			if (ch->tx_skb) {
+				remain = ch->tx_skb->len - ch->tx_idx;
+			} else {
+				remain = 0;
+			}
+			if (remain > 0) {
+
+				/* we lower data margin every msec */
+				fifo->bit_line -= sink;
+				current_len = (0 - fifo->bit_line) / 8;
+
+				/* maximum 15 byte for every ISO packet makes our life easier */
+				if (current_len > 14)
+					current_len = 14;
+				current_len = (remain <= current_len) ? remain : current_len;
+
+				/* how much bit do we put on the line? */
+				fifo->bit_line += current_len * 8;
+
+				context_iso_urb->buffer[tx_offset] = 0;
+				if (current_len == remain) {
+					if (test_bit(FLG_HDLC, &ch->Flags)) {
+						/* here frame completion */
+						context_iso_urb->buffer[tx_offset] = 1;
+						/* add 2 byte flags and 16bit CRC at end of ISDN frame */
+						fifo->bit_line += 32;
+					}
+					frame_complete = 1;
+				}
+
+				/* copy tx data to iso-urb buffer */
+				memcpy(context_iso_urb->buffer + tx_offset + 1,
+				       (ch->tx_skb->data + ch->tx_idx), current_len);
+				ch->tx_idx += current_len;
+
+				/* define packet delimeters within the URB buffer */
+				urb->iso_frame_desc[k].offset = tx_offset;
+				urb->iso_frame_desc[k].length = current_len + 1;
+
+				// USB data log for every ISO out
+				if (fifon == HFCUSB_D_TX && ch->debug) {
+					printk ("D ISO TX (%d/%d) offset(%d) len(%d) ", k, num_isoc_packets-1,
+					        urb->iso_frame_desc[k].offset,
+					        urb->iso_frame_desc[k].length);
+
+					for (i=urb->iso_frame_desc[k].offset; i<(urb->iso_frame_desc[k].offset + urb->iso_frame_desc[k].length); i++) {
+						printk ("%x ", context_iso_urb->buffer[i]);
+					}
+					printk (" skb->len(%i) tx-idx(%d)\n", ch->tx_skb->len, ch->tx_idx);
+				}
+
+
+				tx_offset += (current_len + 1);
+			} else {
+				urb->iso_frame_desc[k].offset = tx_offset++;
+
+				urb->iso_frame_desc[k].length = 1;
+				fifo->bit_line -= sink;	/* we lower data margin every msec */
+
+				if (fifo->bit_line < BITLINE_INF) {
+					fifo->bit_line = BITLINE_INF;
+				}
+			}
+
+			if (frame_complete) {
+				next_tx_frame(card, fifo->ch_idx);
+				frame_complete = 0;
+			}
+
+		}
+		errcode = usb_submit_urb(urb, GFP_ATOMIC);
+		if (errcode < 0) {
+			if (ch->debug)
+				printk(KERN_INFO
+					"HFC-S USB: error submitting ISO URB: %d \n",
+					errcode);
+		}
+
+		/*
+		abuse DChannel tx iso completion to trigger NT mode state changes
+		tx_iso_complete is assumed to be called every fifo->intervall ms
+		*/
+		if ((fifon == HFCUSB_D_TX) && (card->portmode & PORT_MODE_NT)
+		    && (card->portmode & NT_ACTIVATION_TIMER)) {
+			if ((--card->nt_timer) < 0)
+				S0_new_state(&card->chan[D]);
+		}
+
+	} else {
+		if (status && !card->disc_flag) {
+			if (ch->debug)
+				printk(KERN_INFO
+					"HFC-S USB: tx_iso_complete : urb->status %s (%i), fifonum=%d\n",
+					symbolic(urb_errlist, status), status,
+					fifon);
+		}
+	}
+}
+
+
+/* allocs urbs and start isoc transfer with two pending urbs to avoid
+   gaps in the transfer chain */
+static int
+start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,
+		 usb_complete_t complete, int packet_size)
+{
+	int i, k, errcode;
+	hfcsusb_t *card = fifo->card;
+	channel_t *ch = &card->chan[fifo->ch_idx];
+
+	if (ch->debug)
+		printk(KERN_INFO "HFC-S USB: starting ISO-chain for Fifo %i\n",
+	       		fifo->fifonum);
+
+	/* allocate Memory for Iso out Urbs */
+	for (i = 0; i < 2; i++) {
+		if (!(fifo->iso[i].purb)) {
+			fifo->iso[i].purb =
+			    usb_alloc_urb(num_packets_per_urb, GFP_KERNEL);
+			if (!(fifo->iso[i].purb)) {
+				if (ch->debug)
+					printk(KERN_INFO
+						"alloc urb for fifo %i failed!!!",
+						fifo->fifonum);
+			}
+			fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
+
+			/* Init the first iso */
+			if (ISO_BUFFER_SIZE >=
+			    (fifo->usb_packet_maxlen *
+			     num_packets_per_urb)) {
+				fill_isoc_urb(fifo->iso[i].purb,
+					      fifo->card->dev, fifo->pipe,
+					      fifo->iso[i].buffer,
+					      num_packets_per_urb,
+					      fifo->usb_packet_maxlen,
+					      fifo->intervall, complete,
+					      &fifo->iso[i]);
+				memset(fifo->iso[i].buffer, 0,
+				       sizeof(fifo->iso[i].buffer));
+				/* defining packet delimeters in fifo->buffer */
+				for (k = 0; k < num_packets_per_urb; k++) {
+					fifo->iso[i].purb->
+					    iso_frame_desc[k].offset =
+					    k * packet_size;
+					fifo->iso[i].purb->
+					    iso_frame_desc[k].length =
+					    packet_size;
+				}
+			} else {
+				if (ch->debug)
+					printk(KERN_INFO
+						"HFC-S USB: ISO Buffer size to small!\n");
+			}
+		}
+		fifo->bit_line = BITLINE_INF;
+
+		errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL);
+		fifo->active = (errcode >= 0) ? 1 : 0;
+		if (errcode < 0) {
+			if (ch->debug)
+				printk(KERN_INFO "HFC-S USB: %s  URB nr:%d\n",
+					symbolic(urb_errlist, errcode), i);
+		};
+	}
+	return (fifo->active);
+}
+
+/* stops running iso chain and frees their pending urbs */
+static void
+stop_isoc_chain(usb_fifo * fifo)
+{
+	int i;
+	hfcsusb_t *card = fifo->card;
+	channel_t *ch = &card->chan[fifo->ch_idx];
+
+	for (i = 0; i < 2; i++) {
+		if (fifo->iso[i].purb) {
+			if (ch->debug)
+				printk(KERN_INFO
+					"HFC-S USB: %s for fifo %i.%i\n",
+					__FUNCTION__, fifo->fifonum, i);
+			usb_kill_urb(fifo->iso[i].purb);
+			usb_free_urb(fifo->iso[i].purb);
+			fifo->iso[i].purb = NULL;
+		}
+	}
+	if (fifo->urb) {
+		usb_kill_urb(fifo->urb);
+		usb_free_urb(fifo->urb);
+		fifo->urb = NULL;
+	}
+	fifo->active = 0;
+}
+
+/***************************************************/
+/* start the interrupt transfer for the given fifo */
+/***************************************************/
+static void
+start_int_fifo(usb_fifo * fifo)
+{
+	int errcode;
+
+	hfcsusb_t *card = fifo->card;
+	channel_t *ch = &card->chan[fifo->ch_idx];
+
+	if (ch->debug)
+		printk(KERN_INFO "HFC-S USB: starting intr IN fifo:%d\n",
+			fifo->fifonum);
+
+	if (!fifo->urb) {
+		fifo->urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!fifo->urb)
+			return;
+	}
+	usb_fill_int_urb(fifo->urb, fifo->card->dev, fifo->pipe,
+			 fifo->buffer, fifo->usb_packet_maxlen,
+			 (usb_complete_t)rx_int_complete, fifo, fifo->intervall);
+	fifo->active = 1;	/* must be marked active */
+	errcode = usb_submit_urb(fifo->urb, GFP_KERNEL);
+	if (errcode) {
+		if (ch->debug)
+			printk(KERN_INFO
+				"HFC-S USB: submit URB error(start_int_info): status:%i\n",
+				errcode);
+		fifo->active = 0;
+	}
+}
+
+/* Hardware Initialization */
+int
+setup_hfcsusb(hfcsusb_t * card)
+{
+	usb_fifo *fifo;
+	int i, err;
+	u_char b;
+
+	/* check the chip id */
+	if (read_usb(card, HFCUSB_CHIP_ID, &b) != 1) {
+		printk(KERN_INFO "HFC-USB: cannot read chip id\n");
+		return (1);
+	}
+	if (b != HFCUSB_CHIPID) {
+		printk(KERN_INFO "HFC-S USB: Invalid chip id 0x%02x\n", b);
+		return (1);
+	}
+
+	/* first set the needed config, interface and alternate */
+	err = usb_set_interface(card->dev, card->if_used, card->alt_used);
+
+	/* do Chip reset */
+	write_usb(card, HFCUSB_CIRM, 8);
+	/* aux = output, reset off */
+	write_usb(card, HFCUSB_CIRM, 0x10);
+
+	/* set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers */
+	write_usb(card, HFCUSB_USB_SIZE,
+		  (card->packet_size /
+		   8) | ((card->packet_size / 8) << 4));
+
+	/* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */
+	write_usb(card, HFCUSB_USB_SIZE_I, card->iso_packet_size);
+
+	/* enable PCM/GCI master mode */
+	write_usb(card, HFCUSB_MST_MODE1, 0);	/* set default values */
+	write_usb(card, HFCUSB_MST_MODE0, 1);	/* enable master mode */
+
+	/* init the fifos */
+	write_usb(card, HFCUSB_F_THRES,
+		  (HFCUSB_TX_THRESHOLD /
+		   8) | ((HFCUSB_RX_THRESHOLD / 8) << 4));
+
+	fifo = card->fifos;
+	for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
+		write_usb(card, HFCUSB_FIFO, i);	/* select the desired fifo */
+		fifo[i].max_size =
+		    (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
+		fifo[i].last_urblen = 0;
+
+		/* set 2 bit for D- & E-channel */
+		write_usb(card, HFCUSB_HDLC_PAR,
+			  ((i <= HFCUSB_B2_RX) ? 0 : 2));
+
+		/* enable all fifos */
+		if (i == HFCUSB_D_TX) {
+			// enable Interframe Fill for DChannel TX in TE Mode
+			write_usb(card, HFCUSB_CON_HDLC, (card->portmode & PORT_MODE_NT) ? 0x08 : 0x09);
+			// write_usb(card, HFCUSB_CON_HDLC, 0x08);
+		} else {
+			write_usb(card, HFCUSB_CON_HDLC, 0x08);
+		}
+
+		write_usb(card, HFCUSB_INC_RES_F, 2);	/* reset the fifo */
+	}
+
+	if (card->portmode & PORT_MODE_NT) {
+		write_usb(card, HFCUSB_SCTRL, 0x44);		/* disable B transmitters + capacitive mode, enable NT mode */
+		write_usb(card, HFCUSB_SCTRL_E, 0x09);
+		write_usb(card, HFCUSB_CLKDEL, CLKDEL_NT);	/* clock delay value */
+		write_usb(card, HFCUSB_STATES, 1 | 0x10);	/* set deactivated mode */
+		write_usb(card, HFCUSB_STATES, 1);	/* enable state machine */
+	} else {
+		write_usb(card, HFCUSB_SCTRL, 0x40);		/* disable B transmitters + capacitive mode, enable TE mode */
+		write_usb(card, HFCUSB_SCTRL_E, 0x00);
+		write_usb(card, HFCUSB_CLKDEL, CLKDEL_TE);	/* clock delay value */
+		write_usb(card, HFCUSB_STATES, 3 | 0x10);	/* set deactivated mode */
+		write_usb(card, HFCUSB_STATES, 3);	/* enable state machine */
+	}
+
+	write_usb(card, HFCUSB_SCTRL_R, 0);	/* disable both B receivers */
+
+	card->disc_flag = 0;
+	card->led_state = 0;
+	card->old_led_state = 0;
+
+	/* init the background machinery for control requests */
+	card->ctrl_read.bRequestType = 0xc0;
+	card->ctrl_read.bRequest = 1;
+	card->ctrl_read.wLength = cpu_to_le16(1);
+	card->ctrl_write.bRequestType = 0x40;
+	card->ctrl_write.bRequest = 0;
+	card->ctrl_write.wLength = 0;
+	usb_fill_control_urb(card->ctrl_urb,
+			     card->dev,
+			     card->ctrl_out_pipe,
+			     (u_char *) & card->ctrl_write,
+			     NULL, 0, (usb_complete_t)ctrl_complete, card);
+
+	/* Init All Fifos */
+	for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
+		card->fifos[i].iso[0].purb = NULL;
+		card->fifos[i].iso[1].purb = NULL;
+		card->fifos[i].active = 0;
+	}
+
+	/* 3 (+1) INT IN + 3 ISO OUT */
+	if (card->cfg_used == CNF_3INT3ISO
+	    || card->cfg_used == CNF_4INT3ISO) {
+
+		start_int_fifo(card->fifos + HFCUSB_D_RX);
+		/*
+		   if (card->fifos[HFCUSB_PCM_RX].pipe)
+		   start_int_fifo(card->fifos + HFCUSB_PCM_RX);
+		 */
+
+		start_int_fifo(card->fifos + HFCUSB_B1_RX);
+		start_int_fifo(card->fifos + HFCUSB_B2_RX);
+	}
+
+	/* 3 (+1) ISO IN + 3 ISO OUT */
+	if (card->cfg_used == CNF_3ISO3ISO
+	    || card->cfg_used == CNF_4ISO3ISO) {
+		start_isoc_chain(card->fifos + HFCUSB_D_RX, ISOC_PACKETS_D,
+				 (usb_complete_t)rx_iso_complete, 16);
+
+		/*
+		   if (card->fifos[HFCUSB_PCM_RX].pipe)
+		   start_isoc_chain(card->fifos + HFCUSB_PCM_RX,
+		   ISOC_PACKETS_D, rx_iso_complete,
+		   16);
+		 */
+		start_isoc_chain(card->fifos + HFCUSB_B1_RX,
+				 ISOC_PACKETS_B, (usb_complete_t)rx_iso_complete, 16);
+
+		start_isoc_chain(card->fifos + HFCUSB_B2_RX,
+				 ISOC_PACKETS_B, (usb_complete_t)rx_iso_complete, 16);
+	}
+
+
+	start_isoc_chain(card->fifos + HFCUSB_D_TX, ISOC_PACKETS_D,
+			 (usb_complete_t)tx_iso_complete, 1);
+	start_isoc_chain(card->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B,
+			 (usb_complete_t)tx_iso_complete, 1);
+	start_isoc_chain(card->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B,
+			 (usb_complete_t)tx_iso_complete, 1);
+
+	handle_led(card, LED_POWER_ON);
+
+	return (0);
+}
+
+static void
+release_card(hfcsusb_t * card)
+{
+	int	i;
+	u_long	flags;
+
+	if (debug & 0x10000)
+		printk(KERN_DEBUG "%s\n", __FUNCTION__);
+
+	setup_bchannel(&card->chan[B1], ISDN_PID_NONE);
+	setup_bchannel(&card->chan[B2], ISDN_PID_NONE);
+	mISDN_freechannel(&card->chan[B1]);
+	mISDN_freechannel(&card->chan[B2]);
+	mISDN_freechannel(&card->chan[D]);
+	mISDN_ctrl(&card->chan[D].inst, MGR_UNREGLAYER | REQUEST, NULL);
+
+	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+	list_del(&card->list);
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+	schedule_timeout((80 * HZ) / 1000);	/* Timeout 80ms */
+
+	/* tell all fifos to terminate */
+	for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
+		if (card->fifos[i].usb_transfer_mode == USB_ISOC) {
+			if (card->fifos[i].active > 0) {
+				stop_isoc_chain(&card->fifos[i]);
+			}
+		} else {
+			if (card->fifos[i].active > 0) {
+				card->fifos[i].active = 0;
+			}
+			if (card->fifos[i].urb) {
+				usb_kill_urb(card->fifos[i].urb);
+				usb_free_urb(card->fifos[i].urb);
+				card->fifos[i].urb = NULL;
+			}
+		}
+		card->fifos[i].active = 0;
+	}
+
+	/* wait for all URBS to terminate */
+	if (card->ctrl_urb) {
+		usb_kill_urb(card->ctrl_urb);
+		usb_free_urb(card->ctrl_urb);
+		card->ctrl_urb = NULL;
+	}
+	hfcsusb_cnt--;
+	if (card->intf)
+		usb_set_intfdata(card->intf, NULL);
+	kfree(card);
+}
+
+static int
+setup_instance(hfcsusb_t * card)
+{
+	int		i, err;
+	mISDN_pid_t	pid;
+	u_long		flags;
+
+	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+
+	list_add_tail(&card->list, &hw_mISDNObj.ilist);
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+	card->chan[D].debug = debug;
+
+	spin_lock_init(&card->ctrl_lock);
+	spin_lock_init(&card->lock);
+
+	/* link card->fifos[] to card->chan[] */
+	card->fifos[HFCUSB_D_RX].ch_idx = D;
+	card->fifos[HFCUSB_D_TX].ch_idx = D;
+	card->fifos[HFCUSB_B1_RX].ch_idx = B1;
+	card->fifos[HFCUSB_B1_TX].ch_idx = B1;
+	card->fifos[HFCUSB_B2_RX].ch_idx = B2;
+	card->fifos[HFCUSB_B2_TX].ch_idx = B2;
+	card->fifos[HFCUSB_PCM_RX].ch_idx = PCM;
+	card->fifos[HFCUSB_PCM_TX].ch_idx = PCM;
+
+	card->chan[D].channel = D;
+	card->chan[D].state = 0;
+	card->chan[D].inst.hwlock = &card->lock;
+	card->chan[D].inst.pid.layermask = ISDN_LAYER(0);
+	card->chan[D].inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
+	card->chan[D].inst.class_dev.dev = &card->dev->dev;
+	mISDN_init_instance(&card->chan[D].inst, &hw_mISDNObj, card, hfcsusb_l2l1);
+	sprintf(card->chan[D].inst.name, "hfcsusb_%d", hfcsusb_cnt + 1);
+	mISDN_set_dchannel_pid(&pid, protocol[hfcsusb_cnt], layermask[hfcsusb_cnt]);
+	mISDN_initchannel(&card->chan[D], MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
+	card->chan[D].hw = card;
+	card->portmode = 0;
+
+	for (i = B1; i <= B2; i++) {
+		card->chan[i].channel = i;
+		mISDN_init_instance(&card->chan[i].inst, &hw_mISDNObj, card, hfcsusb_l2l1);
+		card->chan[i].inst.pid.layermask = ISDN_LAYER(0);
+		card->chan[i].inst.hwlock = &card->lock;
+		card->chan[i].inst.class_dev.dev = &card->dev->dev;
+		card->chan[i].debug = debug;
+		sprintf(card->chan[i].inst.name, "%s B%d",
+			card->chan[D].inst.name, i + 1);
+		mISDN_initchannel(&card->chan[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM);
+		card->chan[i].hw = card;
+#ifdef FIXME
+		if (card->chan[i].dev) {
+			card->chan[i].dev->wport.pif.func = hfcsusb_l2l1;
+			card->chan[i].dev->wport.pif.fdata = &card->chan[i];
+		}
+#endif
+	}
+
+	card->chan[PCM].channel = PCM;
+
+	if (protocol[hfcsusb_cnt] & 0x10) {
+		// NT Mode
+		printk (KERN_INFO "%s wants NT Mode\n", card->chan[D].inst.name);
+		card->chan[D].inst.pid.protocol[0] = ISDN_PID_L0_NT_S0;
+		card->chan[D].inst.pid.protocol[1] = ISDN_PID_L1_NT_S0;
+		pid.protocol[0] = ISDN_PID_L0_NT_S0;
+		pid.protocol[1] = ISDN_PID_L1_NT_S0;
+		card->chan[D].inst.pid.layermask |= ISDN_LAYER(1);
+		pid.layermask |= ISDN_LAYER(1);
+		if (layermask[i] & ISDN_LAYER(2))
+			pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
+		/* select NT mode with activated NT Timer (T1) */
+		card->portmode |= (PORT_MODE_NT | NT_ACTIVATION_TIMER);
+	} else {
+		printk (KERN_INFO "%s wants TE Mode\n", card->chan[D].inst.name);
+		// TE Mode
+		card->chan[D].inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
+		card->portmode |= PORT_MODE_TE;
+	}
+
+	if (debug)
+		printk(KERN_DEBUG
+		       "hfcsusb card %p dch %p bch1 %p bch2 %p\n", card,
+		       &card->chan[D], &card->chan[B1], &card->chan[B2]);
+
+	err = setup_hfcsusb(card);
+	if (err) {
+		mISDN_freechannel(&card->chan[D]);
+		mISDN_freechannel(&card->chan[B2]);
+		mISDN_freechannel(&card->chan[B1]);
+		spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+		list_del(&card->list);
+		spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+		kfree(card);
+		return (err);
+	}
+	hfcsusb_cnt++;
+	err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &card->chan[D].inst);
+	if (err) {
+		release_card(card);
+		return (err);
+	}
+	for (i = B1; i <= B2; i++) {
+		err = mISDN_ctrl(card->chan[D].inst.st,
+			MGR_NEWSTACK | REQUEST, &card->chan[i].inst);
+		if (err) {
+			printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
+			mISDN_ctrl(card->chan[D].inst.st, MGR_DELSTACK | REQUEST, NULL);
+			return (err);
+		}
+		setup_bchannel(&card->chan[i], -1);
+	}
+	if (debug)
+		printk(KERN_DEBUG "%s lm %x\n", __FUNCTION__, pid.layermask);
+	err = mISDN_ctrl(card->chan[D].inst.st, MGR_SETSTACK | REQUEST, &pid);
+	if (err) {
+		printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", err);
+		mISDN_ctrl(card->chan[D].inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return (err);
+	}
+
+	mISDN_ctrl(card->chan[D].inst.st, MGR_CTRLREADY | INDICATION, NULL);
+	usb_set_intfdata(card->intf, card);
+	return (0);
+}
+
+
+/*************************************************/
+/* function called to probe a new plugged device */
+/*************************************************/
+
+static int
+hfcsusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device		*dev = interface_to_usbdev(intf);
+	hfcsusb_t			*card;
+	struct usb_host_interface	*iface = intf->cur_altsetting;
+	struct usb_host_interface	*iface_used = NULL;
+	struct usb_host_endpoint	*ep;
+	int 				ifnum = iface->desc.bInterfaceNumber;
+	int				i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf,
+					attr, cfg_found, ep_addr;
+	int				cmptbl[16], small_match, iso_packet_size, packet_size, alt_used = 0;
+	hfcsusb_vdata			*driver_info;
+
+	vend_idx = 0xffff;
+	for (i = 0; hfcsusb_idtab[i].idVendor; i++) {
+		if ((le16_to_cpu(dev->descriptor.idVendor) == hfcsusb_idtab[i].idVendor)
+		    && (le16_to_cpu(dev->descriptor.idProduct) == hfcsusb_idtab[i].idProduct)) {
+			vend_idx = i;
+			continue;
+		}
+	}
+
+	printk(KERN_INFO
+	       "HFC-S USB: probing interface(%d) actalt(%d) minor(%d) vend_idx(%d)\n",
+	       ifnum, iface->desc.bAlternateSetting, intf->minor, vend_idx);
+
+	if (vend_idx == 0xffff) {
+		printk(KERN_WARNING
+		       "HFC-S USB: no valid vendor found in USB descriptor\n");
+		return (-EIO);
+	}
+	/* if vendor and product ID is OK, start probing alternate settings */
+	alt_idx = 0;
+	small_match = 0xffff;
+
+	/* default settings */
+	iso_packet_size = 16;
+	packet_size = 64;
+
+	while (alt_idx < intf->num_altsetting) {
+		iface = intf->altsetting + alt_idx;
+		probe_alt_setting = iface->desc.bAlternateSetting;
+		cfg_used = 0;
+
+		/* check for config EOL element */
+		while (validconf[cfg_used][0]) {
+			cfg_found = 1;
+			vcf = validconf[cfg_used];
+			/* first endpoint descriptor */
+			ep = iface->endpoint;
+			memcpy(cmptbl, vcf, 16 * sizeof(int));
+
+			/* check for all endpoints in this alternate setting */
+			for (i = 0; i < iface->desc.bNumEndpoints; i++) {
+				ep_addr = ep->desc.bEndpointAddress;
+				/* get endpoint base */
+				idx = ((ep_addr & 0x7f) - 1) * 2;
+				if (ep_addr & 0x80)
+					idx++;
+				attr = ep->desc.bmAttributes;
+				if (cmptbl[idx] == EP_NUL) {
+					cfg_found = 0;
+				}
+				if (attr == USB_ENDPOINT_XFER_INT
+					&& cmptbl[idx] == EP_INT)
+					cmptbl[idx] = EP_NUL;
+				if (attr == USB_ENDPOINT_XFER_BULK
+					&& cmptbl[idx] == EP_BLK)
+					cmptbl[idx] = EP_NUL;
+				if (attr == USB_ENDPOINT_XFER_ISOC
+					&& cmptbl[idx] == EP_ISO)
+					cmptbl[idx] = EP_NUL;
+
+				/* check if all INT endpoints match minimum interval */
+				if (attr == USB_ENDPOINT_XFER_INT &&
+					ep->desc.bInterval < vcf[17]) {
+					cfg_found = 0;
+				}
+				ep++;
+			}
+			for (i = 0; i < 16; i++) {
+				/* all entries must be EP_NOP or EP_NUL for a valid config */
+				if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL)
+					cfg_found = 0;
+			}
+			if (cfg_found) {
+				if (cfg_used < small_match) {
+					small_match = cfg_used;
+					alt_used = probe_alt_setting;
+					iface_used = iface;
+				}
+			}
+			cfg_used++;
+		}
+		alt_idx++;
+	}	/* (alt_idx < intf->num_altsetting) */
+
+	/* not found a valid USB Ta Endpoint config */
+	if (small_match == 0xffff) {
+		printk(KERN_WARNING
+		       "HFC-S USB: no valid endpoint found in USB descriptor\n");
+		return (-EIO);
+	}
+	iface = iface_used;
+	card = kmalloc(sizeof(hfcsusb_t), GFP_KERNEL);
+	if (!card)
+		return (-ENOMEM);	/* got no mem */
+	memset(card, 0, sizeof(hfcsusb_t));
+
+	ep = iface->endpoint;
+	vcf = validconf[small_match];
+
+	for (i = 0; i < iface->desc.bNumEndpoints; i++) {
+		usb_fifo	*f;
+
+		ep_addr = ep->desc.bEndpointAddress;
+		/* get endpoint base */
+		idx = ((ep_addr & 0x7f) - 1) * 2;
+		if (ep_addr & 0x80)
+			idx++;
+		f = &card->fifos[idx & 7];
+
+		/* init Endpoints */
+		if (vcf[idx] == EP_NOP || vcf[idx] == EP_NUL) {
+			ep++;
+			continue;
+		}
+		switch (ep->desc.bmAttributes) {
+			case USB_ENDPOINT_XFER_INT:
+				f->pipe = usb_rcvintpipe(dev,
+					ep->desc.bEndpointAddress);
+				f->usb_transfer_mode = USB_INT;
+				packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
+				break;
+			case USB_ENDPOINT_XFER_BULK:
+				if (ep_addr & 0x80)
+					f->pipe = usb_rcvbulkpipe(dev,
+						ep->desc.bEndpointAddress);
+				else
+					f->pipe = usb_sndbulkpipe(dev,
+						ep->desc.bEndpointAddress);
+				f->usb_transfer_mode = USB_BULK;
+				packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
+				break;
+			case USB_ENDPOINT_XFER_ISOC:
+				if (ep_addr & 0x80)
+					f->pipe = usb_rcvisocpipe(dev,
+						ep->desc.bEndpointAddress);
+				else
+					f->pipe = usb_sndisocpipe(dev,
+						ep->desc.bEndpointAddress);
+				f->usb_transfer_mode = USB_ISOC;
+				iso_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
+				break;
+			default:
+				f->pipe = 0;
+		}	/* switch attribute */
+
+		if (f->pipe) {
+			f->fifonum = idx & 7;
+			f->card = card;
+			f->usb_packet_maxlen = le16_to_cpu(ep->desc.wMaxPacketSize);
+			f->intervall = ep->desc.bInterval;
+		}
+		ep++;
+	}
+	card->dev = dev;	/* save device */
+	card->if_used = ifnum;	/* save used interface */
+	card->alt_used = alt_used;	/* and alternate config */
+	card->ctrl_paksize = dev->descriptor.bMaxPacketSize0;	/* control size */
+	card->cfg_used = vcf[16];	/* store used config */
+	card->vend_idx = vend_idx;	/* store found vendor */
+	card->packet_size = packet_size;
+	card->iso_packet_size = iso_packet_size;
+
+	/* create the control pipes needed for register access */
+	card->ctrl_in_pipe = usb_rcvctrlpipe(card->dev, 0);
+	card->ctrl_out_pipe = usb_sndctrlpipe(card->dev, 0);
+	card->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+	driver_info = (hfcsusb_vdata *) hfcsusb_idtab[vend_idx].driver_info;
+	printk(KERN_INFO "HFC-S USB: detected \"%s\"\n",
+		driver_info->vend_name);
+	printk(KERN_INFO "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d)\n",
+		conf_str[small_match], ifnum, alt_used);
+
+	card->intf = intf;
+	if (setup_instance(card)) {
+		return (-EIO);
+	}
+	return (0);
+}
+
+/****************************************************/
+/* function called when an active device is removed */
+/****************************************************/
+static void
+hfcsusb_disconnect(struct usb_interface *intf)
+{
+	hfcsusb_t *card = usb_get_intfdata(intf);
+
+	printk(KERN_INFO "HFC-S USB: device disconnect\n");
+	if (!card) {
+		if (debug & 0x10000)
+			printk(KERN_DEBUG "%s : NO CONTEXT!\n", __FUNCTION__);
+		return;
+	}
+	if (debug & 0x10000)
+		printk(KERN_DEBUG "%s\n", __FUNCTION__);
+	card->disc_flag = 1;
+	mISDN_ctrl(card->chan[D].inst.st, MGR_DELSTACK | REQUEST, NULL);
+//	release_card(card);
+	usb_set_intfdata(intf, NULL);
+}				/* hfcsusb_disconnect */
+
+
+/************************************/
+/* our driver information structure */
+/************************************/
+static struct usb_driver hfcsusb_drv = {
+	.name = DRIVER_NAME,
+	.id_table = hfcsusb_idtab,
+	.probe = hfcsusb_probe,
+	.disconnect = hfcsusb_disconnect,
+};
+
+
+static int __init
+hfcsusb_init(void)
+{
+	int err;
+
+	// debug = 0xFFFF;
+	printk(KERN_INFO "hfcsusb driver Rev. %s (debug=%i)\n",
+	       mISDN_getrev(hfcsusb_rev), debug);
+
+#ifdef MODULE
+	hw_mISDNObj.owner = THIS_MODULE;
+#endif
+	spin_lock_init(&hw_mISDNObj.lock);
+	INIT_LIST_HEAD(&hw_mISDNObj.ilist);
+	hw_mISDNObj.name = DRIVER_NAME;
+	hw_mISDNObj.own_ctrl = hfcsusb_manager;
+
+	hw_mISDNObj.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0 |
+					 ISDN_PID_L0_NT_S0;
+	hw_mISDNObj.DPROTO.protocol[1] = ISDN_PID_L1_NT_S0;
+	hw_mISDNObj.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS |
+					 ISDN_PID_L1_B_64HDLC;
+	hw_mISDNObj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS |
+					 ISDN_PID_L2_B_RAWDEV;
+
+	if ((err = mISDN_register(&hw_mISDNObj))) {
+		printk(KERN_ERR "Can't register hfcsusb error(%d)\n", err);
+		return (err);
+	}
+	if (usb_register(&hfcsusb_drv)) {
+		printk(KERN_INFO
+		       "hfcsusb: Unable to register hfcsusb module at usb stack\n");
+		goto out;
+	}
+
+	mISDN_module_register(THIS_MODULE);
+
+	return 0;
+
+      out:
+	mISDN_unregister(&hw_mISDNObj);
+	return err;
+}
+
+static void __exit
+hfcsusb_cleanup(void)
+{
+	int err;
+	hfcsusb_t *card, *next;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if (debug & 0x10000)
+		printk(KERN_DEBUG "%s\n", __FUNCTION__);
+
+	list_for_each_entry_safe(card, next, &hw_mISDNObj.ilist, list) {
+		handle_led(card, LED_POWER_OFF);
+	}
+	if ((err = mISDN_unregister(&hw_mISDNObj))) {
+		printk(KERN_ERR "Can't unregister hfcsusb error(%d)\n",
+		       err);
+	}
+	/* unregister Hardware */
+	usb_deregister(&hfcsusb_drv);	/* release our driver */
+}
+
+module_init(hfcsusb_init);
+module_exit(hfcsusb_cleanup);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_usb.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_usb.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcs_usb.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,263 @@
+/*
+* hfcs_usb.h, HFC-S USB mISDN driver
+* $Id: hfcs_usb.h,v 1.6 2006/11/13 16:27:19 mbachem Exp $ 
+*
+*/
+
+#ifndef __HFCS_USB_H__
+#define __HFCS_USB_H__
+
+#define DRIVER_AUTHOR   "Martin Bachem / Peter Sprenger"
+#define DRIVER_DESC     "HFC-S USB based HiSAX ISDN driver"
+
+/* DEBUG flags, use combined value for module parameter debug=x */
+#define DEBUG_HFC_INIT		0x0001
+#define DEBUG_HFC_MODE		0x0002
+#define DEBUG_HFC_S0_STATES	0x0004
+#define DEBUG_HFC_IRQ		0x0008
+#define DEBUG_HFC_FIFO_ERR	0x0010
+#define DEBUG_HFC_DTRACE	0x2000
+#define DEBUG_HFC_BTRACE	0x4000	/* very(!) heavy messageslog load */
+#define DEBUG_HFC_FIFO		0x8000	/* very(!) heavy messageslog load */
+
+
+/***********/
+/* defines */
+/***********/
+#define HFC_CTRL_TIMEOUT 20	/* 5ms timeout writing/reading regs */
+#define CLKDEL_TE	0x0f	/* CLKDEL in TE mode */
+#define CLKDEL_NT	0x6c	/* CLKDEL in NT mode */
+
+/* hfcsusb Layer1 commands */
+#define HFC_L1_ACTIVATE_TE	0x01
+#define HFC_L1_ACTIVATE_NT	0x02
+#define HFC_L1_DEACTIVATE_NT	0x03
+#define HFC_L1_FORCE_DEACTIVATE_TE 0x04
+
+/* cmd FLAGS in HFCUSB_STATES register */
+#define HFCUSB_LOAD_STATE	0x10
+#define HFCUSB_ACTIVATE		0x20
+#define HFCUSB_DO_ACTION	0x40
+#define HFCUSB_NT_G2_G3		0x80
+
+/* bits in hw_mode */
+#define PORT_MODE_TE		0x01
+#define PORT_MODE_NT		0x02
+#define NT_ACTIVATION_TIMER	0x04 /* enables NT mode activation Timer */
+#define NT_T1_COUNT		10
+
+#define MAX_BCH_SIZE 2048	/* allowed B-channel packet size */
+
+#define HFCUSB_RX_THRESHOLD 64	/* threshold for fifo report bit rx */
+#define HFCUSB_TX_THRESHOLD 64	/* threshold for fifo report bit tx */
+
+#define HFCUSB_CHIP_ID		0x16	/* Chip ID register index */
+#define HFCUSB_CIRM		0x00	/* cirm register index */
+#define HFCUSB_USB_SIZE		0x07	/* int length register */
+#define HFCUSB_USB_SIZE_I	0x06	/* iso length register */
+#define HFCUSB_F_CROSS		0x0b	/* bit order register */
+#define HFCUSB_CLKDEL		0x37	/* bit delay register */
+#define HFCUSB_CON_HDLC		0xfa	/* channel connect register */
+#define HFCUSB_HDLC_PAR		0xfb
+#define HFCUSB_SCTRL		0x31	/* S-bus control register (tx) */
+#define HFCUSB_SCTRL_E		0x32	/* same for E and special funcs */
+#define HFCUSB_SCTRL_R		0x33	/* S-bus control register (rx) */
+#define HFCUSB_F_THRES		0x0c	/* threshold register */
+#define HFCUSB_FIFO		0x0f	/* fifo select register */
+#define HFCUSB_F_USAGE		0x1a	/* fifo usage register */
+#define HFCUSB_MST_MODE0	0x14
+#define HFCUSB_MST_MODE1	0x15
+#define HFCUSB_P_DATA		0x1f
+#define HFCUSB_INC_RES_F	0x0e
+#define HFCUSB_STATES		0x30
+
+#define HFCUSB_CHIPID		0x40	/* ID value of HFC-S USB */
+
+/******************/
+/* fifo registers */
+/******************/
+#define HFCUSB_NUM_FIFOS	8	/* maximum number of fifos */
+#define HFCUSB_B1_TX		0	/* index for B1 transmit bulk/int */
+#define HFCUSB_B1_RX		1	/* index for B1 receive bulk/int */
+#define HFCUSB_B2_TX		2
+#define HFCUSB_B2_RX		3
+#define HFCUSB_D_TX		4
+#define HFCUSB_D_RX		5
+#define HFCUSB_PCM_TX		6
+#define HFCUSB_PCM_RX		7
+
+/*************/
+/* Chan idx  */
+/*************/
+#define B1	0
+#define B2	1
+#define D	2
+#define PCM	3
+#define MAX_CHAN 4
+
+/*
+* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
+* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
+*/
+#define USB_INT		0
+#define USB_BULK	1
+#define USB_ISOC	2
+
+#define ISOC_PACKETS_D	8
+#define ISOC_PACKETS_B	8
+#define ISO_BUFFER_SIZE	128
+
+/* defines how much ISO packets are handled in one URB */
+static int iso_packets[8] =
+    { ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B,
+	ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D
+};
+
+
+// ISO send definitions
+#define SINK_MAX	68
+#define SINK_MIN	48
+#define SINK_DMIN	12
+#define SINK_DMAX	18
+#define BITLINE_INF	(-64*8)
+
+
+/**********/
+/* macros */
+/**********/
+#define write_usb(a,b,c)usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT)
+#define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
+
+
+/*******************/
+/* Debugging Flags */
+/*******************/
+#define USB_DBG   1
+#define ISDN_DBG  2
+
+
+/* *********************/
+/* USB related defines */
+/***********************/
+#define HFC_CTRL_BUFSIZE 32
+
+
+/*************************************************/
+/* entry and size of output/input control buffer */
+/*************************************************/
+typedef struct {
+	__u8 hfcs_reg;		/* register number */
+	__u8 reg_val;		/* value to be written (or read) */
+} ctrl_buft;
+
+
+/********************/
+/* URB error codes: */
+/********************/
+/* Used to represent a list of values and their respective symbolic names */
+struct hfcusb_symbolic_list {
+	const int num;
+	const char *name;
+};
+
+static struct hfcusb_symbolic_list urb_errlist[] = {
+	{-ENOMEM, "No memory for allocation of internal structures"},
+	{-ENOSPC, "The host controller's bandwidth is already consumed"},
+	{-ENOENT, "URB was canceled by unlink_urb"},
+	{-EXDEV, "ISO transfer only partially completed"},
+	{-EAGAIN, "Too match scheduled for the future"},
+	{-ENXIO, "URB already queued"},
+	{-EFBIG, "Too much ISO frames requested"},
+	{-ENOSR, "Buffer error (overrun)"},
+	{-EPIPE, "Specified endpoint is stalled (device not responding)"},
+	{-EOVERFLOW, "Babble (bad cable?)"},
+	{-EPROTO, "Bit-stuff error (bad cable?)"},
+	{-EILSEQ, "CRC/Timeout"},
+	{-ETIMEDOUT, "NAK (device does not respond)"},
+	{-ESHUTDOWN, "Device unplugged"},
+	{-1, NULL}
+};
+
+
+static inline const char *
+symbolic(struct hfcusb_symbolic_list list[], const int num)
+{
+	int i;
+	for (i = 0; list[i].name != NULL; i++)
+		if (list[i].num == num)
+			return (list[i].name);
+	return "<unkown>";
+}
+
+
+/*****************************************************/
+/* device dependant information to support different */
+/* ISDN Ta's using the HFC-S USB chip                */
+/*****************************************************/
+
+/* USB descriptor need to contain one of the following EndPoint combination: */
+#define CNF_4INT3ISO	1	// 4 INT IN, 3 ISO OUT
+#define CNF_3INT3ISO	2	// 3 INT IN, 3 ISO OUT
+#define CNF_4ISO3ISO	3	// 4 ISO IN, 3 ISO OUT
+#define CNF_3ISO3ISO	4	// 3 ISO IN, 3 ISO OUT
+
+#define EP_NUL 1		// Endpoint at this position not allowed
+#define EP_NOP 2		// all type of endpoints allowed at this position
+#define EP_ISO 3		// Isochron endpoint mandatory at this position
+#define EP_BLK 4		// Bulk endpoint mandatory at this position
+#define EP_INT 5		// Interrupt endpoint mandatory at this position
+
+/* this array represents all endpoints possible in the HCF-USB the last
+* 3 entries are the configuration number, the minimum interval for
+* Interrupt endpoints & boolean if E-channel logging possible
+*/
+int validconf[][19] = {
+	// INT in, ISO out config
+	{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
+	 EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
+	 CNF_4INT3ISO, 2, 1},
+	{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL,
+	 EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
+	 CNF_3INT3ISO, 2, 0},
+	// ISO in, ISO out config
+	{EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
+	 EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO,
+	 CNF_4ISO3ISO, 2, 1},
+	{EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
+	 EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL,
+	 CNF_3ISO3ISO, 2, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}	// EOL element
+};
+
+// string description of chosen config
+char *conf_str[] = {
+	"4 Interrupt IN + 3 Isochron OUT",
+	"3 Interrupt IN + 3 Isochron OUT",
+	"4 Isochron IN + 3 Isochron OUT",
+	"3 Isochron IN + 3 Isochron OUT"
+};
+
+
+#define LED_OFF      0		// no LED support
+#define LED_SCHEME1  1		// LED standard scheme
+#define LED_SCHEME2  2		// not used yet...
+
+#define LED_POWER_ON	1
+#define LED_POWER_OFF	2
+#define LED_S0_ON	3
+#define LED_S0_OFF	4
+#define LED_B1_ON	5
+#define LED_B1_OFF	6
+#define LED_B1_DATA	7
+#define LED_B2_ON	8
+#define LED_B2_OFF	9
+#define LED_B2_DATA	10
+
+#define LED_NORMAL   0		// LEDs are normal
+#define LED_INVERTED 1		// LEDs are inverted
+
+/* time in ms to perform a Flashing LED when B-Channel has traffic */
+#define LED_TIME      250
+
+
+#endif	/* __HFCS_USB_H__ */

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcsmcc.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcsmcc.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcsmcc.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1100 @@
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/*  (C) Copyright Cologne Chip AG, 2005                                              */
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+
+/*                                                                                   */
+/*  File name:     hfcsmcc.h                                                         */
+/*  File content:  This file contains the HFC-S mini register definitions.           */
+/*  Creation date: 24.10.2005 10:45                                                  */
+/*  Creator:       Genero 3.2                                                        */
+/*  Data base:     HFC XML 1.6 for HFC-S mini and HFC-S USB (unreleased)             */
+/*  Address range: 0x00 - 0xFC                                                       */
+/*                                                                                   */
+/*  The information presented can not be considered as assured characteristics.      */
+/*  Data can change without notice. Please check version numbers in case of doubt.   */
+/*                                                                                   */
+/*  For further information or questions please contact support at CologneChip.com      */
+/*                                                                                   */
+/*                                                                                   */
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/*  WARNING: This file has been generated automatically and should not be            */
+/*           changed to maintain compatibility with later versions.                  */
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+
+
+#ifndef _HFCSMCC_H_
+#define _HFCSMCC_H_
+
+
+typedef unsigned char BYTE;
+
+typedef BYTE REGWORD;       // maximum register length (standard)
+typedef BYTE REGADDR;       // address width
+
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/*  The following definitions are only used for multi-register access and can be     */
+/*  switched off. Define MULTIREG below if you want to use multi-register accesses.  */
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+#define MULTIREG
+/*___________________________________________________________________________________*/
+
+#ifdef MULTIREG
+	typedef unsigned short REGWORD16; // multi-register access, 2 registers
+	typedef unsigned int REGWORD32;   // multi-register access, 4 registers
+#endif
+
+
+
+typedef enum {no=0, yes} REGBOOL;
+
+
+typedef enum
+{
+	// register and bitmap access modes:
+	writeonly=0,		// write only
+	readonly,		// read only
+	readwrite,		// read/write
+	// following modes only for mixed mode registers:
+	readwrite_write,	// read/write and write only
+	readwrite_read,		// read/write and read only
+	write_read,		// write only and read only
+	readwrite_write_read	// read/write, write only and read only
+} ACCESSMODE;
+
+
+
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/* common chip information:                                                          */
+/*___________________________________________________________________________________*/
+
+	#define CHIP_NAME		"HFC-S mini"
+	#define CHIP_TITLE		"ISDN HDLC FIFO controller with S/T interface and integrated FIFOs"
+	#define CHIP_MANUFACTURER	"Cologne Chip"
+	#define CHIP_ID			0x05
+	#define CHIP_REGISTER_COUNT	71
+	#define CHIP_DATABASE		"Version HFC-XMLHFC XML 1.6 for HFC-S mini and HFC-S USB (unreleased) -GeneroGenero 3.2 "
+
+
+
+
+
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/*  Begin of HFC-S mini register definitions.                                        */
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+
+#define R_CIRM 0x00 // register access
+	#define M_SRES 0x08 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_28:3;
+		REGWORD v_sres:1;
+		REGWORD reserved_29:4;
+	} bit_r_cirm; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_cirm bit;} reg_r_cirm; // register and bitmap access
+
+
+#define A_Z1 0x04 // register access
+	#define M_Z1 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_z1:8;
+	} bit_a_z1; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_z1 bit;} reg_a_z1; // register and bitmap access
+
+
+#define A_Z2 0x06 // register access
+	#define M_Z2 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_z2:8;
+	} bit_a_z2; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_z2 bit;} reg_a_z2; // register and bitmap access
+
+
+#define R_RAM_ADDR0 0x08 // register access
+	#define M_RAM_ADDR0 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ram_addr0:8;
+	} bit_r_ram_addr0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ram_addr0 bit;} reg_r_ram_addr0; // register and bitmap access
+
+
+#define R_RAM_ADDR1 0x09 // register access
+	#define M_RAM_ADDR1 0x07 // bitmap mask (3bit)
+		#define M1_RAM_ADDR1 0x01
+	#define M_ADDR_RES 0x40 // bitmap mask (1bit)
+	#define M_ADDR_INC 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ram_addr1:3;
+		REGWORD reserved_0:3;
+		REGWORD v_addr_res:1;
+		REGWORD v_addr_inc:1;
+	} bit_r_ram_addr1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ram_addr1 bit;} reg_r_ram_addr1; // register and bitmap access
+
+
+#define R_FIFO_REV 0x0B // register access
+	#define M_FIFO0_TX_REV 0x01 // bitmap mask (1bit)
+	#define M_FIFO0_RX_REV 0x02 // bitmap mask (1bit)
+	#define M_FIFO1_TX_REV 0x04 // bitmap mask (1bit)
+	#define M_FIFO1_RX_REV 0x08 // bitmap mask (1bit)
+	#define M_FIFO2_TX_REV 0x10 // bitmap mask (1bit)
+	#define M_FIFO2_RX_REV 0x20 // bitmap mask (1bit)
+	#define M_FIFO3_TX_REV 0x40 // bitmap mask (1bit)
+	#define M_FIFO3_RX_REV 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo0_tx_rev:1;
+		REGWORD v_fifo0_rx_rev:1;
+		REGWORD v_fifo1_tx_rev:1;
+		REGWORD v_fifo1_rx_rev:1;
+		REGWORD v_fifo2_tx_rev:1;
+		REGWORD v_fifo2_rx_rev:1;
+		REGWORD v_fifo3_tx_rev:1;
+		REGWORD v_fifo3_rx_rev:1;
+	} bit_r_fifo_rev; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo_rev bit;} reg_r_fifo_rev; // register and bitmap access
+
+
+#define A_F1 0x0C // register access
+	#define M_F1 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_f1:8;
+	} bit_a_f1; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_f1 bit;} reg_a_f1; // register and bitmap access
+
+
+#define R_FIFO_THRES 0x0C // register access
+	#define M_THRES_TX 0x0F // bitmap mask (4bit)
+		#define M1_THRES_TX 0x01
+	#define M_THRES_RX 0xF0 // bitmap mask (4bit)
+		#define M1_THRES_RX 0x10
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_thres_tx:4;
+		REGWORD v_thres_rx:4;
+	} bit_r_fifo_thres; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo_thres bit;} reg_r_fifo_thres; // register and bitmap access
+
+
+#define A_F2 0x0D // register access
+	#define M_F2 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_f2:8;
+	} bit_a_f2; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_f2 bit;} reg_a_f2; // register and bitmap access
+
+
+#define R_DF_MD 0x0D // register access
+	#define M_CSM 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_1:7;
+		REGWORD v_csm:1;
+	} bit_r_df_md; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_df_md bit;} reg_r_df_md; // register and bitmap access
+
+
+#define A_INC_RES_FIFO 0x0E // register access
+	#define M_INC_F 0x01 // bitmap mask (1bit)
+	#define M_RES_FIFO 0x02 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_inc_f:1;
+		REGWORD v_res_fifo:1;
+		REGWORD reserved_2:6;
+	} bit_a_inc_res_fifo; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_inc_res_fifo bit;} reg_a_inc_res_fifo; // register and bitmap access
+
+
+#define R_FIFO 0x0F // register access
+	#define M_FIFO_DIR 0x01 // bitmap mask (1bit)
+	#define M_FIFO_NUM 0x06 // bitmap mask (2bit)
+		#define M1_FIFO_NUM 0x02
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_dir:1;
+		REGWORD v_fifo_num:2;
+		REGWORD reserved_3:5;
+	} bit_r_fifo; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo bit;} reg_r_fifo; // register and bitmap access
+
+
+#define R_FIFO_IRQ 0x10 // register access
+	#define M_FIFO0_TX_IRQ 0x01 // bitmap mask (1bit)
+	#define M_FIFO0_RX_IRQ 0x02 // bitmap mask (1bit)
+	#define M_FIFO1_TX_IRQ 0x04 // bitmap mask (1bit)
+	#define M_FIFO1_RX_IRQ 0x08 // bitmap mask (1bit)
+	#define M_FIFO2_TX_IRQ 0x10 // bitmap mask (1bit)
+	#define M_FIFO2_RX_IRQ 0x20 // bitmap mask (1bit)
+	#define M_FIFO3_TX_IRQ 0x40 // bitmap mask (1bit)
+	#define M_FIFO3_RX_IRQ 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo0_tx_irq:1;
+		REGWORD v_fifo0_rx_irq:1;
+		REGWORD v_fifo1_tx_irq:1;
+		REGWORD v_fifo1_rx_irq:1;
+		REGWORD v_fifo2_tx_irq:1;
+		REGWORD v_fifo2_rx_irq:1;
+		REGWORD v_fifo3_tx_irq:1;
+		REGWORD v_fifo3_rx_irq:1;
+	} bit_r_fifo_irq; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo_irq bit;} reg_r_fifo_irq; // register and bitmap access
+
+
+#define R_MISC_IRQ 0x11 // register access
+	#define M_ST_IRQ 0x01 // bitmap mask (1bit)
+	#define M_TI_IRQ 0x02 // bitmap mask (1bit)
+	#define M_PROC_IRQ 0x04 // bitmap mask (1bit)
+	#define M_CI_IRQ 0x08 // bitmap mask (1bit)
+	#define M_MON_RX_IRQ 0x10 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_irq:1;
+		REGWORD v_ti_irq:1;
+		REGWORD v_proc_irq:1;
+		REGWORD v_ci_irq:1;
+		REGWORD v_mon_rx_irq:1;
+		REGWORD reserved_31:3;
+	} bit_r_misc_irq; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_misc_irq bit;} reg_r_misc_irq; // register and bitmap access
+
+
+#define R_PCM_MD0 0x14 // register access
+	#define M_PCM_MD 0x01 // bitmap mask (1bit)
+	#define M_C4_POL 0x02 // bitmap mask (1bit)
+	#define M_F0_NEG 0x04 // bitmap mask (1bit)
+	#define M_F0_LEN 0x08 // bitmap mask (1bit)
+	#define M_SL_CODECA 0x30 // bitmap mask (2bit)
+		#define M1_SL_CODECA 0x10
+	#define M_SL_CODECB 0xC0 // bitmap mask (2bit)
+		#define M1_SL_CODECB 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_pcm_md:1;
+		REGWORD v_c4_pol:1;
+		REGWORD v_f0_neg:1;
+		REGWORD v_f0_len:1;
+		REGWORD v_sl_codeca:2;
+		REGWORD v_sl_codecb:2;
+	} bit_r_pcm_md0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pcm_md0 bit;} reg_r_pcm_md0; // register and bitmap access
+
+
+#define R_PCM_MD1 0x15 // register access
+	#define M_AUX1_MIR 0x01 // bitmap mask (1bit)
+	#define M_AUX2_MIR 0x02 // bitmap mask (1bit)
+	#define M_PLL_ADJ 0x0C // bitmap mask (2bit)
+		#define M1_PLL_ADJ 0x04
+	#define M_PCM_DR 0x30 // bitmap mask (2bit)
+		#define M1_PCM_DR 0x10
+	#define M_PCM_LOOP 0x40 // bitmap mask (1bit)
+	#define M_GCI_EN 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_aux1_mir:1;
+		REGWORD v_aux2_mir:1;
+		REGWORD v_pll_adj:2;
+		REGWORD v_pcm_dr:2;
+		REGWORD v_pcm_loop:1;
+		REGWORD v_gci_en:1;
+	} bit_r_pcm_md1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pcm_md1 bit;} reg_r_pcm_md1; // register and bitmap access
+
+
+#define R_PCM_MD2 0x16 // register access
+	#define M_OKI_CODECA 0x01 // bitmap mask (1bit)
+	#define M_OKI_CODECB 0x02 // bitmap mask (1bit)
+	#define M_SYNC_SRC 0x04 // bitmap mask (1bit)
+	#define M_SYNC_OUT 0x08 // bitmap mask (1bit)
+	#define M_SL_BL 0x30 // bitmap mask (2bit)
+		#define M1_SL_BL 0x10
+	#define M_PLL_ICR 0x40 // bitmap mask (1bit)
+	#define M_PLL_MAN 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_oki_codeca:1;
+		REGWORD v_oki_codecb:1;
+		REGWORD v_sync_src:1;
+		REGWORD v_sync_out:1;
+		REGWORD v_sl_bl:2;
+		REGWORD v_pll_icr:1;
+		REGWORD v_pll_man:1;
+	} bit_r_pcm_md2; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pcm_md2 bit;} reg_r_pcm_md2; // register and bitmap access
+
+
+#define R_CHIP_ID 0x16 // register access
+	#define M_CHIP_ID 0xF0 // bitmap mask (4bit)
+		#define M1_CHIP_ID 0x10
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_22:4;
+		REGWORD v_chip_id:4;
+	} bit_r_chip_id; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_chip_id bit;} reg_r_chip_id; // register and bitmap access
+
+
+#define R_F0_CNTL 0x18 // register access
+	#define M_F0_CNTL 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_f0_cntl:8;
+	} bit_r_f0_cntl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_f0_cntl bit;} reg_r_f0_cntl; // register and bitmap access
+
+
+#define R_F0_CNTH 0x19 // register access
+	#define M_F0_CNTH 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_f0_cnth:8;
+	} bit_r_f0_cnth; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_f0_cnth bit;} reg_r_f0_cnth; // register and bitmap access
+
+
+#define A_USAGE 0x1A // register access
+	#define M_USAGE 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_usage:8;
+	} bit_a_usage; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_usage bit;} reg_a_usage; // register and bitmap access
+
+
+#define R_FIFO_IRQMSK 0x1A // register access
+	#define M_FIFO0_TX_IRQMSK 0x01 // bitmap mask (1bit)
+	#define M_FIFO0_RX_IRQMSK 0x02 // bitmap mask (1bit)
+	#define M_FIFO1_TX_IRQMSK 0x04 // bitmap mask (1bit)
+	#define M_FIFO1_RX_IRQMSK 0x08 // bitmap mask (1bit)
+	#define M_FIFO2_TX_IRQMSK 0x10 // bitmap mask (1bit)
+	#define M_FIFO2_RX_IRQMSK 0x20 // bitmap mask (1bit)
+	#define M_FIFO3_TX_IRQMSK 0x40 // bitmap mask (1bit)
+	#define M_FIFO3_RX_IRQMSK 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo0_tx_irqmsk:1;
+		REGWORD v_fifo0_rx_irqmsk:1;
+		REGWORD v_fifo1_tx_irqmsk:1;
+		REGWORD v_fifo1_rx_irqmsk:1;
+		REGWORD v_fifo2_tx_irqmsk:1;
+		REGWORD v_fifo2_rx_irqmsk:1;
+		REGWORD v_fifo3_tx_irqmsk:1;
+		REGWORD v_fifo3_rx_irqmsk:1;
+	} bit_r_fifo_irqmsk; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo_irqmsk bit;} reg_r_fifo_irqmsk; // register and bitmap access
+
+
+#define R_FILL 0x1B // register access
+	#define M_FIFO0_TX_FILL 0x01 // bitmap mask (1bit)
+	#define M_FIFO0_RX_FILL 0x02 // bitmap mask (1bit)
+	#define M_FIFO1_TX_FILL 0x04 // bitmap mask (1bit)
+	#define M_FIFO1_RX_FILL 0x08 // bitmap mask (1bit)
+	#define M_FIFO2_TX_FILL 0x10 // bitmap mask (1bit)
+	#define M_FIFO2_RX_FILL 0x20 // bitmap mask (1bit)
+	#define M_FIFO3_TX_FILL 0x40 // bitmap mask (1bit)
+	#define M_FIFO3_RX_FILL 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo0_tx_fill:1;
+		REGWORD v_fifo0_rx_fill:1;
+		REGWORD v_fifo1_tx_fill:1;
+		REGWORD v_fifo1_rx_fill:1;
+		REGWORD v_fifo2_tx_fill:1;
+		REGWORD v_fifo2_rx_fill:1;
+		REGWORD v_fifo3_tx_fill:1;
+		REGWORD v_fifo3_rx_fill:1;
+	} bit_r_fill; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fill bit;} reg_r_fill; // register and bitmap access
+
+
+#define R_MISC_IRQMSK 0x1B // register access
+	#define M_ST_IRQMSK 0x01 // bitmap mask (1bit)
+	#define M_TI_IRQMSK 0x02 // bitmap mask (1bit)
+	#define M_PROC_IRQMSK 0x04 // bitmap mask (1bit)
+	#define M_CI_IRQMSK 0x08 // bitmap mask (1bit)
+	#define M_MON_IRQMSK 0x10 // bitmap mask (1bit)
+	#define M_IRQ_REV 0x40 // bitmap mask (1bit)
+	#define M_IRQ_EN 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_irqmsk:1;
+		REGWORD v_ti_irqmsk:1;
+		REGWORD v_proc_irqmsk:1;
+		REGWORD v_ci_irqmsk:1;
+		REGWORD v_mon_irqmsk:1;
+		REGWORD reserved_4:1;
+		REGWORD v_irq_rev:1;
+		REGWORD v_irq_en:1;
+	} bit_r_misc_irqmsk; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_misc_irqmsk bit;} reg_r_misc_irqmsk; // register and bitmap access
+
+
+#define R_TI 0x1C // register access
+	#define M_EV_TS 0x0F // bitmap mask (4bit)
+		#define M1_EV_TS 0x01
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ev_ts:4;
+		REGWORD reserved_30:4;
+	} bit_r_ti; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ti bit;} reg_r_ti; // register and bitmap access
+
+
+#define R_STATUS 0x1C // register access
+	#define M_BUSY 0x01 // bitmap mask (1bit)
+	#define M_PROC 0x02 // bitmap mask (1bit)
+	#define M_AWAKE_IN 0x08 // bitmap mask (1bit)
+	#define M_SYNC_IN 0x10 // bitmap mask (1bit)
+	#define M_MISC_IRQSTA 0x40 // bitmap mask (1bit)
+	#define M_FIFO_IRQSTA 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_busy:1;
+		REGWORD v_proc:1;
+		REGWORD reserved_32:1;
+		REGWORD v_awake_in:1;
+		REGWORD v_sync_in:1;
+		REGWORD reserved_33:1;
+		REGWORD v_misc_irqsta:1;
+		REGWORD v_fifo_irqsta:1;
+	} bit_r_status; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_status bit;} reg_r_status; // register and bitmap access
+
+
+#define R_B1_TX_SL 0x20 // register access
+	#define M_B1_TX_SL 0x1F // bitmap mask (5bit)
+		#define M1_B1_TX_SL 0x01
+	#define M_B1_TX_ROUT 0xC0 // bitmap mask (2bit)
+		#define M1_B1_TX_ROUT 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b1_tx_sl:5;
+		REGWORD reserved_5:1;
+		REGWORD v_b1_tx_rout:2;
+	} bit_r_b1_tx_sl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_b1_tx_sl bit;} reg_r_b1_tx_sl; // register and bitmap access
+
+
+#define R_B2_TX_SL 0x21 // register access
+	#define M_B2_TX_SL 0x1F // bitmap mask (5bit)
+		#define M1_B2_TX_SL 0x01
+	#define M_B2_TX_ROUT 0xC0 // bitmap mask (2bit)
+		#define M1_B2_TX_ROUT 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b2_tx_sl:5;
+		REGWORD reserved_6:1;
+		REGWORD v_b2_tx_rout:2;
+	} bit_r_b2_tx_sl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_b2_tx_sl bit;} reg_r_b2_tx_sl; // register and bitmap access
+
+
+#define R_AUX1_TX_SL 0x22 // register access
+	#define M_AUX1_TX_SL 0x1F // bitmap mask (5bit)
+		#define M1_AUX1_TX_SL 0x01
+	#define M_AUX1_TX_ROUT 0xC0 // bitmap mask (2bit)
+		#define M1_AUX1_TX_ROUT 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_aux1_tx_sl:5;
+		REGWORD reserved_7:1;
+		REGWORD v_aux1_tx_rout:2;
+	} bit_r_aux1_tx_sl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_aux1_tx_sl bit;} reg_r_aux1_tx_sl; // register and bitmap access
+
+
+#define R_AUX2_TX_SL 0x23 // register access
+	#define M_AUX2_TX_SL 0x1F // bitmap mask (5bit)
+		#define M1_AUX2_TX_SL 0x01
+	#define M_AUX2_TX_ROUT 0xC0 // bitmap mask (2bit)
+		#define M1_AUX2_TX_ROUT 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_aux2_tx_sl:5;
+		REGWORD reserved_8:1;
+		REGWORD v_aux2_tx_rout:2;
+	} bit_r_aux2_tx_sl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_aux2_tx_sl bit;} reg_r_aux2_tx_sl; // register and bitmap access
+
+
+#define R_B1_RX_SL 0x24 // register access
+	#define M_B1_RX_SL 0x1F // bitmap mask (5bit)
+		#define M1_B1_RX_SL 0x01
+	#define M_B1_RX_ROUT 0xC0 // bitmap mask (2bit)
+		#define M1_B1_RX_ROUT 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b1_rx_sl:5;
+		REGWORD reserved_9:1;
+		REGWORD v_b1_rx_rout:2;
+	} bit_r_b1_rx_sl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_b1_rx_sl bit;} reg_r_b1_rx_sl; // register and bitmap access
+
+
+#define R_B2_RX_SL 0x25 // register access
+	#define M_B2_RX_SL 0x1F // bitmap mask (5bit)
+		#define M1_B2_RX_SL 0x01
+	#define M_B2_RX_ROUT 0xC0 // bitmap mask (2bit)
+		#define M1_B2_RX_ROUT 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b2_rx_sl:5;
+		REGWORD reserved_10:1;
+		REGWORD v_b2_rx_rout:2;
+	} bit_r_b2_rx_sl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_b2_rx_sl bit;} reg_r_b2_rx_sl; // register and bitmap access
+
+
+#define R_AUX1_RX_SL 0x26 // register access
+	#define M_AUX1_RX_SL 0x1F // bitmap mask (5bit)
+		#define M1_AUX1_RX_SL 0x01
+	#define M_AUX1_RX_ROUT 0xC0 // bitmap mask (2bit)
+		#define M1_AUX1_RX_ROUT 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_aux1_rx_sl:5;
+		REGWORD reserved_11:1;
+		REGWORD v_aux1_rx_rout:2;
+	} bit_r_aux1_rx_sl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_aux1_rx_sl bit;} reg_r_aux1_rx_sl; // register and bitmap access
+
+
+#define R_AUX2_RX_SL 0x27 // register access
+	#define M_AUX2_RX_SL 0x1F // bitmap mask (5bit)
+		#define M1_AUX2_RX_SL 0x01
+	#define M_AUX2_RX_ROUT 0xC0 // bitmap mask (2bit)
+		#define M1_AUX2_RX_ROUT 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_aux2_rx_sl:5;
+		REGWORD reserved_12:1;
+		REGWORD v_aux2_rx_rout:2;
+	} bit_r_aux2_rx_sl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_aux2_rx_sl bit;} reg_r_aux2_rx_sl; // register and bitmap access
+
+
+#define R_CI_RX 0x28 // register access
+	#define M_GCI_I 0x0F // bitmap mask (4bit)
+		#define M1_GCI_I 0x01
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gci_i:4;
+		REGWORD reserved_23:4;
+	} bit_r_ci_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ci_rx bit;} reg_r_ci_rx; // register and bitmap access
+
+
+#define R_CI_TX 0x28 // register access
+	#define M_GCI_C 0x0F // bitmap mask (4bit)
+		#define M1_GCI_C 0x01
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gci_c:4;
+		REGWORD reserved_13:4;
+	} bit_r_ci_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ci_tx bit;} reg_r_ci_tx; // register and bitmap access
+
+
+#define R_PCM_GCI_STA 0x29 // register access
+	#define M_MON_RXR 0x01 // bitmap mask (1bit)
+	#define M_MON_TXR 0x02 // bitmap mask (1bit)
+	#define M_STIO2_IN 0x40 // bitmap mask (1bit)
+	#define M_STIO1_IN 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mon_rxr:1;
+		REGWORD v_mon_txr:1;
+		REGWORD reserved_24:4;
+		REGWORD v_stio2_in:1;
+		REGWORD v_stio1_in:1;
+	} bit_r_pcm_gci_sta; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pcm_gci_sta bit;} reg_r_pcm_gci_sta; // register and bitmap access
+
+
+#define R_MON1_RX 0x2A // register access
+	#define M_MON1_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mon1_rx:8;
+	} bit_r_mon1_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_mon1_rx bit;} reg_r_mon1_rx; // register and bitmap access
+
+
+#define R_MON1_TX 0x2A // register access
+	#define M_MON1_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mon1_tx:8;
+	} bit_r_mon1_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_mon1_tx bit;} reg_r_mon1_tx; // register and bitmap access
+
+
+#define R_MON2_RX 0x2B // register access
+	#define M_MON2_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mon2_rx:8;
+	} bit_r_mon2_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_mon2_rx bit;} reg_r_mon2_rx; // register and bitmap access
+
+
+#define R_MON2_TX 0x2B // register access
+	#define M_MON2_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mon2_tx:8;
+	} bit_r_mon2_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_mon2_tx bit;} reg_r_mon2_tx; // register and bitmap access
+
+
+#define R_B1_RX 0x2C // register access
+	#define M_B1_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b1_rx:8;
+	} bit_r_b1_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_b1_rx bit;} reg_r_b1_rx; // register and bitmap access
+
+
+#define R_B1_TX 0x2C // register access
+	#define M_B1_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b1_tx:8;
+	} bit_r_b1_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_b1_tx bit;} reg_r_b1_tx; // register and bitmap access
+
+
+#define R_B2_RX 0x2D // register access
+	#define M_B2_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b2_rx:8;
+	} bit_r_b2_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_b2_rx bit;} reg_r_b2_rx; // register and bitmap access
+
+
+#define R_B2_TX 0x2D // register access
+	#define M_B2_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b2_tx:8;
+	} bit_r_b2_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_b2_tx bit;} reg_r_b2_tx; // register and bitmap access
+
+
+#define R_AUX1_RX 0x2E // register access
+	#define M_AUX1_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_aux1_rx:8;
+	} bit_r_aux1_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_aux1_rx bit;} reg_r_aux1_rx; // register and bitmap access
+
+
+#define R_AUX1_TX 0x2E // register access
+	#define M_AUX1_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_aux1_tx:8;
+	} bit_r_aux1_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_aux1_tx bit;} reg_r_aux1_tx; // register and bitmap access
+
+
+#define R_AUX2_RX 0x2F // register access
+	#define M_AUX2_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_aux2_rx:8;
+	} bit_r_aux2_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_aux2_rx bit;} reg_r_aux2_rx; // register and bitmap access
+
+
+#define R_AUX2_TX 0x2F // register access
+	#define M_AUX2_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_aux2_tx:8;
+	} bit_r_aux2_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_aux2_tx bit;} reg_r_aux2_tx; // register and bitmap access
+
+
+#define R_ST_RD_STA 0x30 // register access
+	#define M_ST_STA 0x0F // bitmap mask (4bit)
+		#define M1_ST_STA 0x01
+	#define M_FR_SYNC 0x10 // bitmap mask (1bit)
+	#define M_T2_EXP 0x20 // bitmap mask (1bit)
+	#define M_INFO0 0x40 // bitmap mask (1bit)
+	#define M_G2_G3 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_sta:4;
+		REGWORD v_fr_sync:1;
+		REGWORD v_t2_exp:1;
+		REGWORD v_info0:1;
+		REGWORD v_g2_g3:1;
+	} bit_r_st_rd_sta; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_rd_sta bit;} reg_r_st_rd_sta; // register and bitmap access
+
+
+#define R_ST_WR_STA 0x30 // register access
+	#define M_ST_SET_STA 0x0F // bitmap mask (4bit)
+		#define M1_ST_SET_STA 0x01
+	#define M_ST_LD_STA 0x10 // bitmap mask (1bit)
+	#define M_ST_ACT 0x60 // bitmap mask (2bit)
+		#define M1_ST_ACT 0x20
+	#define M_SET_G2_G3 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_set_sta:4;
+		REGWORD v_st_ld_sta:1;
+		REGWORD v_st_act:2;
+		REGWORD v_set_g2_g3:1;
+	} bit_r_st_wr_sta; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_wr_sta bit;} reg_r_st_wr_sta; // register and bitmap access
+
+
+#define R_ST_CTRL0 0x31 // register access
+	#define M_B1_EN 0x01 // bitmap mask (1bit)
+	#define M_B2_EN 0x02 // bitmap mask (1bit)
+	#define M_ST_MD 0x04 // bitmap mask (1bit)
+	#define M_D_PRIO 0x08 // bitmap mask (1bit)
+	#define M_SQ_EN 0x10 // bitmap mask (1bit)
+	#define M_96KHZ 0x20 // bitmap mask (1bit)
+	#define M_TX_LI 0x40 // bitmap mask (1bit)
+	#define M_ST_STOP 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b1_en:1;
+		REGWORD v_b2_en:1;
+		REGWORD v_st_md:1;
+		REGWORD v_d_prio:1;
+		REGWORD v_sq_en:1;
+		REGWORD v_96khz:1;
+		REGWORD v_tx_li:1;
+		REGWORD v_st_stop:1;
+	} bit_r_st_ctrl0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_ctrl0 bit;} reg_r_st_ctrl0; // register and bitmap access
+
+
+#define R_ST_CTRL1 0x32 // register access
+	#define M_G2_G3_EN 0x01 // bitmap mask (1bit)
+	#define M_D_RES 0x04 // bitmap mask (1bit)
+	#define M_E_IGNO 0x08 // bitmap mask (1bit)
+	#define M_E_LO 0x10 // bitmap mask (1bit)
+	#define M_B12_SWAP 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_g2_g3_en:1;
+		REGWORD reserved_14:1;
+		REGWORD v_d_res:1;
+		REGWORD v_e_igno:1;
+		REGWORD v_e_lo:1;
+		REGWORD reserved_15:2;
+		REGWORD v_b12_swap:1;
+	} bit_r_st_ctrl1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_ctrl1 bit;} reg_r_st_ctrl1; // register and bitmap access
+
+
+#define R_ST_CTRL2 0x33 // register access
+	#define M_B1_RX_EN 0x01 // bitmap mask (1bit)
+	#define M_B2_RX_EN 0x02 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b1_rx_en:1;
+		REGWORD v_b2_rx_en:1;
+		REGWORD reserved_16:6;
+	} bit_r_st_ctrl2; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_ctrl2 bit;} reg_r_st_ctrl2; // register and bitmap access
+
+
+#define R_ST_SQ_RD 0x34 // register access
+	#define M_ST_SQ_RD 0x0F // bitmap mask (4bit)
+		#define M1_ST_SQ_RD 0x01
+	#define M_MF_RX_RDY 0x10 // bitmap mask (1bit)
+	#define M_MF_TX_RDY 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_sq_rd:4;
+		REGWORD v_mf_rx_rdy:1;
+		REGWORD reserved_25:2;
+		REGWORD v_mf_tx_rdy:1;
+	} bit_r_st_sq_rd; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_sq_rd bit;} reg_r_st_sq_rd; // register and bitmap access
+
+
+#define R_ST_SQ_WR 0x34 // register access
+	#define M_ST_SQ_WR 0x0F // bitmap mask (4bit)
+		#define M1_ST_SQ_WR 0x01
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_sq_wr:4;
+		REGWORD reserved_17:4;
+	} bit_r_st_sq_wr; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_sq_wr bit;} reg_r_st_sq_wr; // register and bitmap access
+
+
+#define R_ST_CLK_DLY 0x37 // register access
+	#define M_ST_CLK_DLY 0x0F // bitmap mask (4bit)
+		#define M1_ST_CLK_DLY 0x01
+	#define M_ST_SMPL 0x70 // bitmap mask (3bit)
+		#define M1_ST_SMPL 0x10
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_clk_dly:4;
+		REGWORD v_st_smpl:3;
+		REGWORD reserved_18:1;
+	} bit_r_st_clk_dly; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_clk_dly bit;} reg_r_st_clk_dly; // register and bitmap access
+
+
+#define R_ST_B1_RX 0x3C // register access
+	#define M_ST_B1_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_b1_rx:8;
+	} bit_r_st_b1_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_b1_rx bit;} reg_r_st_b1_rx; // register and bitmap access
+
+
+#define R_ST_B1_TX 0x3C // register access
+	#define M_ST_B1_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_b1_tx:8;
+	} bit_r_st_b1_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_b1_tx bit;} reg_r_st_b1_tx; // register and bitmap access
+
+
+#define R_ST_B2_RX 0x3D // register access
+	#define M_ST_B2_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_b2_rx:8;
+	} bit_r_st_b2_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_b2_rx bit;} reg_r_st_b2_rx; // register and bitmap access
+
+
+#define R_ST_B2_TX 0x3D // register access
+	#define M_ST_B2_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_b2_tx:8;
+	} bit_r_st_b2_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_b2_tx bit;} reg_r_st_b2_tx; // register and bitmap access
+
+
+#define R_ST_D_RX 0x3E // register access
+	#define M_ST_D_RX 0xC0 // bitmap mask (2bit)
+		#define M1_ST_D_RX 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_26:6;
+		REGWORD v_st_d_rx:2;
+	} bit_r_st_d_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_d_rx bit;} reg_r_st_d_rx; // register and bitmap access
+
+
+#define R_ST_D_TX 0x3E // register access
+	#define M_ST_D_TX 0xC0 // bitmap mask (2bit)
+		#define M1_ST_D_TX 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_19:6;
+		REGWORD v_st_d_tx:2;
+	} bit_r_st_d_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_d_tx bit;} reg_r_st_d_tx; // register and bitmap access
+
+
+#define R_ST_E_RX 0x3F // register access
+	#define M_ST_E_RX 0xC0 // bitmap mask (2bit)
+		#define M1_ST_E_RX 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_27:6;
+		REGWORD v_st_e_rx:2;
+	} bit_r_st_e_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_st_e_rx bit;} reg_r_st_e_rx; // register and bitmap access
+
+
+#define A_FIFO_DATA 0x80 // register access
+	#define M_FIFO_DATA 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_data:8;
+	} bit_a_fifo_data; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_fifo_data bit;} reg_a_fifo_data; // register and bitmap access
+
+
+#define A_FIFO_DATA_NOINC 0x84 // register access
+	#define M_FIFO_DATA_NOINC 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_data_noinc:8;
+	} bit_a_fifo_data_noinc; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_fifo_data_noinc bit;} reg_a_fifo_data_noinc; // register and bitmap access
+
+
+#define R_RAM_DATA 0xC0 // register access
+	#define M_RAM_DATA 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ram_data:8;
+	} bit_r_ram_data; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ram_data bit;} reg_r_ram_data; // register and bitmap access
+
+
+#define A_CH_MSK 0xF4 // register access
+	#define M_CH_MSK 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ch_msk:8;
+	} bit_a_ch_msk; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_ch_msk bit;} reg_a_ch_msk; // register and bitmap access
+
+
+#define A_CON_HDLC 0xFA // register access
+	#define M_IFF 0x01 // bitmap mask (1bit)
+	#define M_HDLC_TRP 0x02 // bitmap mask (1bit)
+	#define M_TRP_IRQ 0x0C // bitmap mask (2bit)
+		#define M1_TRP_IRQ 0x04
+	#define M_DATA_FLOW 0xE0 // bitmap mask (3bit)
+		#define M1_DATA_FLOW 0x20
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_iff:1;
+		REGWORD v_hdlc_trp:1;
+		REGWORD v_trp_irq:2;
+		REGWORD reserved_20:1;
+		REGWORD v_data_flow:3;
+	} bit_a_con_hdlc; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_con_hdlc bit;} reg_a_con_hdlc; // register and bitmap access
+
+
+#define A_HDLC_PAR 0xFB // register access
+	#define M_BIT_CNT 0x07 // bitmap mask (3bit)
+		#define M1_BIT_CNT 0x01
+	#define M_START_BIT 0x38 // bitmap mask (3bit)
+		#define M1_START_BIT 0x08
+	#define M_LOOP_FIFO 0x40 // bitmap mask (1bit)
+	#define M_INV_DATA 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_bit_cnt:3;
+		REGWORD v_start_bit:3;
+		REGWORD v_loop_fifo:1;
+		REGWORD v_inv_data:1;
+	} bit_a_hdlc_par; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_hdlc_par bit;} reg_a_hdlc_par; // register and bitmap access
+
+
+#define A_CHANNEL 0xFC // register access
+	#define M_CH_DIR 0x01 // bitmap mask (1bit)
+	#define M_CH_NUM 0x06 // bitmap mask (2bit)
+		#define M1_CH_NUM 0x02
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ch_dir:1;
+		REGWORD v_ch_num:2;
+		REGWORD reserved_21:5;
+	} bit_a_channel; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_channel bit;} reg_a_channel; // register and bitmap access
+
+
+#endif /* _HFCSMCC_H_ */
+
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/*  End of HFC-S mini register definitions.                                          */
+/*                                                                                   */
+/*  Total number of registers processed: 71 of 71                                    */
+/*  Total number of bitmaps processed  : 209                                         */
+/*                                                                                   */
+/*___________________________________________________________________________________*/
+/*                                                                                   */


Property changes on: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/hfcsmcc.h
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/i4l_mISDN.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/i4l_mISDN.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/i4l_mISDN.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1586 @@
+/* $Id: i4l_mISDN.c,v 1.12 2007/02/13 10:43:45 crich Exp $
+ *
+ * interface for old I4L hardware drivers to the CAPI driver
+ *
+ * Copyright  (C) 2003 Karsten Keil (kkeil at suse.de)
+ *
+ * Author     Karsten Keil (kkeil at suse.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/isdnif.h>
+#include <linux/delay.h>
+#include <asm/semaphore.h>
+#include <linux/mISDNif.h>
+#include "fsm.h"
+#include "helper.h"
+#include "dss1.h"
+#include "debug.h"
+
+static char *i4lcapi_revision = "$Revision: 1.12 $";
+
+/* data struct */
+typedef struct _i4l_channel	i4l_channel_t;
+typedef struct _i4l_capi	i4l_capi_t;
+
+struct _i4l_channel {
+	mISDNinstance_t		inst;
+	i4l_capi_t		*drv;
+	int			nr;
+	u_int			Flags;
+	int			cause_loc;
+	int			cause_val;
+	u_int			l4id;
+	struct FsmInst		i4lm;
+	struct sk_buff_head	sendq;
+	struct sk_buff_head	ackq;
+};
+
+struct _i4l_capi {
+	i4l_capi_t		*prev;
+	i4l_capi_t		*next;
+	isdn_if			*interface;
+	mISDNinstance_t		inst;
+	mISDN_pid_t		pid;
+	int			idx;
+	int			locks;
+	int			debug;
+	int			nr_ch;
+	i4l_channel_t		*ch;
+};
+
+#define I4L_FLG_LOCK		0
+#define	I4L_FLG_L1TRANS		1
+#define I4L_FLG_L1HDLC		2
+#define I4L_FLG_LAYER1		3
+#define I4L_FLG_BREADY		4
+#define I4L_FLG_BCONN		5
+#define	I4L_FLG_HANGUP		6
+
+static
+struct Fsm i4lfsm_s =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_NULL,
+	ST_ICALL,
+	ST_OCALL,
+	ST_PROCEED,
+	ST_ALERT,
+	ST_WAITDCONN,
+	ST_ACTIVD,
+	ST_BREADY,
+	ST_ACTIVB,
+	ST_HANGUP,
+};
+
+#define STATE_COUNT (ST_HANGUP+1)
+
+static char *strI4LState[] =
+{
+	"ST_NULL",
+	"ST_ICALL",
+	"ST_OCALL",
+	"ST_PROCEED",
+	"ST_ALERT",
+	"ST_WAITDCONN",
+	"ST_ACTIVD",
+	"ST_BREADY",
+	"ST_ACTIVB",
+	"ST_HANGUP",
+};
+
+enum {
+	EV_I4L_ICALL,
+	EV_I4L_DCONN,
+	EV_I4L_BCONN,
+	EV_I4L_DHUP,
+	EV_I4L_BHUP,
+	EV_I4L_L1ERR,
+	EV_STACKREADY,
+	EV_CAPI_OCALL,
+	EV_CAPI_ALERT,
+	EV_CAPI_PROCEED,
+	EV_CAPI_DCONNECT,
+	EV_CAPI_ESTABLISHB,
+	EV_CAPI_RELEASEB,
+	EV_CAPI_DISCONNECT,
+	EV_CAPI_RELEASE,
+};
+
+#define EVENT_COUNT (EV_CAPI_RELEASE + 1)
+
+static char *strI4LEvent[] =
+{
+	"EV_I4L_ICALL",
+	"EV_I4L_DCONN",
+	"EV_I4L_BCONN",
+	"EV_I4L_DHUP",
+	"EV_I4L_BHUP",
+	"EV_I4L_L1ERR",
+	"EV_STACKREADY",
+	"EV_CAPI_OCALL",
+	"EV_CAPI_ALERT",
+	"EV_CAPI_PROCEED",
+	"EV_CAPI_DCONNECT",
+	"EV_CAPI_ESTABLISHB",
+	"EV_CAPI_RELEASEB",
+	"EV_CAPI_DISCONNECT",
+	"EV_CAPI_RELEASE",
+};
+
+static void
+i4lm_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	logdata_t	log;
+
+	va_start(log.args, fmt);
+	log.fmt = fmt;
+	log.head = ch->inst.name;
+	ch->inst.obj->ctrl(&ch->inst, MGR_DEBUGDATA | REQUEST, &log);
+	va_end(log.args);
+}
+
+#define MAX_CARDS	8
+static i4l_capi_t	*drvmap[MAX_CARDS];
+static mISDNobject_t	I4Lcapi;
+
+static int debug;
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+#endif
+
+static void
+i4l_lock_drv(i4l_capi_t *ic)
+{
+	isdn_ctrl cmd;
+
+	cmd.driver = ic->idx;
+	cmd.arg = 0;
+	cmd.command = ISDN_CMD_LOCK;
+	ic->interface->command(&cmd);
+	ic->locks++;
+}
+
+static void
+i4l_unlock_drv(i4l_capi_t *ic)
+{
+	isdn_ctrl cmd;
+
+	cmd.driver = ic->idx;
+	cmd.arg = 0;
+	cmd.command = ISDN_CMD_UNLOCK;
+	ic->interface->command(&cmd);
+	ic->locks--;
+}
+
+static int
+i4l_cmd(i4l_capi_t *ic, int arg, int cmd)
+{
+	isdn_ctrl ctrl;
+
+	ctrl.driver = ic->idx;
+	ctrl.arg = arg;
+	ctrl.command = cmd;
+	return(ic->interface->command(&ctrl));
+}
+
+static void
+init_channel(i4l_capi_t *ic, int nr)
+{
+	i4l_channel_t	*ch;
+
+	ch = ic->ch + nr;
+	memset(ch, 0, sizeof(i4l_channel_t));
+	ch->nr = nr;
+	ch->drv = ic;
+	ch->i4lm.debug = debug & 0x8;
+	ch->i4lm.userdata = ch;
+	ch->i4lm.userint = 0;
+	ch->i4lm.printdebug = i4lm_debug;
+	ch->i4lm.fsm = &i4lfsm_s;
+	ch->i4lm.state = ST_NULL;
+	skb_queue_head_init(&ch->sendq);
+	skb_queue_head_init(&ch->ackq);
+	ch->inst.obj = &I4Lcapi;
+	ch->inst.data = ch;
+	ch->inst.pid.layermask = ISDN_LAYER(0);
+	ch->inst.up.owner = &ch->inst;
+	ch->inst.down.owner = &ch->inst;
+	mISDN_ctrl(NULL, MGR_DISCONNECT | REQUEST, &ch->inst.down);
+	sprintf(ch->inst.name, "%s B%d", ic->inst.name, nr+1);
+}
+
+static void
+reset_channel(i4l_channel_t *ch)
+{
+	ch->cause_loc = 0;
+	ch->cause_val = 0;
+	ch->l4id = 0;
+	skb_queue_purge(&ch->sendq);
+	skb_queue_purge(&ch->ackq);
+	if (test_and_clear_bit(I4L_FLG_LOCK, &ch->Flags))
+		i4l_unlock_drv(ch->drv);
+	ch->Flags = 0;
+}
+
+static void
+release_card(int idx) {
+	i4l_capi_t	*ic = drvmap[idx];
+	i4l_channel_t	*ch;
+	int		i;
+	mISDNinstance_t	*inst;
+
+	if (!ic)
+		return;
+	drvmap[idx] = NULL;
+	ch = ic->ch;
+	for (i=0; i<ic->nr_ch; i++) {
+		inst = &ch->inst;
+		if (inst->up.peer)
+			inst->up.peer->obj->ctrl(inst->up.peer,
+				MGR_DISCONNECT | REQUEST, &inst->up);
+		reset_channel(ch);
+		ch++;
+	}
+	inst = &ic->inst;
+	if (inst->up.peer) {
+		inst->up.peer->obj->ctrl(inst->up.peer,
+			MGR_DISCONNECT | REQUEST, &inst->up);
+	}
+	REMOVE_FROM_LISTBASE(ic, ((i4l_capi_t *)I4Lcapi.ilist));
+	while (ic->locks > 0)
+		i4l_unlock_drv(ic);
+	kfree(ic->ch);
+	ic->ch = NULL;
+	kfree(ic);
+	I4Lcapi.refcnt--;
+}
+
+static int
+sendup(i4l_channel_t *ch, int Dchannel, int prim, struct sk_buff *skb)
+{
+	int		ret;
+	mISDN_headext_t	*hhe;
+	mISDNinstance_t	*I;
+
+	if (!skb) {
+		skb = alloc_skb(8, GFP_ATOMIC);
+		if (!skb)
+			return(-ENOMEM);
+	}
+	hhe = mISDN_HEADEXT_P(skb);
+	hhe->prim = prim;
+	hhe->dinfo = ch->l4id;
+	if (ch->drv->debug & 0x4)
+		mISDN_LogL3Msg(skb);
+	if (Dchannel)
+		I = &ch->drv->inst;
+	else
+		I = &ch->inst;
+	if (!I->up.func) {
+		int_error();
+		dev_kfree_skb(skb);
+		return(-EUNATCH);
+	}
+	if (in_interrupt()) {
+		hhe->func.iff = I->up.func;
+		hhe->data[0] = &I->up;
+		ret = I->obj->ctrl(NULL, MGR_QUEUEIF | REQUEST, skb);
+	} else
+		ret = I->up.func(&I->up, skb);
+	if (ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+static int
+sendqueued(i4l_channel_t *ch)
+{
+	struct sk_buff	*skb, *s_skb;
+	int		len, ret;
+
+	if (!test_bit(I4L_FLG_BCONN, &ch->Flags)) {
+		if (ch->drv->debug & 0x40)
+			printk(KERN_DEBUG "%s: bc%d not ready\n", __FUNCTION__, ch->nr);
+		return(0);
+	}
+	while ((skb = skb_dequeue(&ch->sendq))) {
+		s_skb = skb_clone(skb, GFP_ATOMIC);
+		len = s_skb->len;
+		skb_queue_tail(&ch->ackq, skb);
+		ret = ch->drv->interface->writebuf_skb(ch->drv->idx, ch->nr, 1, s_skb);
+		if (ch->drv->debug & 0x800)
+			printk(KERN_DEBUG "bc%d sent skb(%p) %d(%d)\n", ch->nr, skb, ret, len);
+		if (ret == len) {
+			continue;
+		} else if (ret > 0) {
+			skb_queue_head(&ch->sendq, s_skb);
+			break;
+		} else {
+			skb_unlink(skb);
+			skb_queue_head(&ch->sendq, skb);
+			if (!ret)
+				dev_kfree_skb(s_skb);
+			break;
+		}
+	}
+	return(0);
+}
+
+static u_char *
+EncodeASyncParams(u_char * p, u_char si2)
+{				// 7c 06 88  90 21 42 00 bb
+	p[0] = 0;
+	p[1] = 0x40;		// Intermediate rate: 16 kbit/s jj 2000.02.19
+	p[2] = 0x80;
+	if (si2 & 32)		// 7 data bits
+		p[2] += 16;
+	else			// 8 data bits
+		p[2] += 24;
+
+	if (si2 & 16)		// 2 stop bits
+		p[2] += 96;
+	else			// 1 stop bit
+		p[2] += 32;
+	if (si2 & 8)		// even parity
+		p[2] += 2;
+	else			// no parity
+		p[2] += 3;
+	switch (si2 & 0x07) {
+		case 0:
+			p[0] = 66;	// 1200 bit/s
+			break;
+		case 1:
+			p[0] = 88;	// 1200/75 bit/s
+			break;
+		case 2:
+			p[0] = 87;	// 75/1200 bit/s
+			break;
+		case 3:
+			p[0] = 67;	// 2400 bit/s
+			break;
+		case 4:
+			p[0] = 69;	// 4800 bit/s
+			break;
+		case 5:
+			p[0] = 72;	// 9600 bit/s
+			break;
+		case 6:
+			p[0] = 73;	// 14400 bit/s
+			break;
+		case 7:
+			p[0] = 75;	// 19200 bit/s
+			break;
+	}
+	return p + 3;
+}
+
+static  u_char
+EncodeSyncParams(u_char si2, u_char ai)
+{
+	switch (si2) {
+		case 0:
+			return ai + 2;	// 1200 bit/s
+		case 1:
+			return ai + 24;	// 1200/75 bit/s
+		case 2:
+			return ai + 23;	// 75/1200 bit/s
+		case 3:
+			return ai + 3;	// 2400 bit/s
+		case 4:
+			return ai + 5;	// 4800 bit/s
+		case 5:
+			return ai + 8;	// 9600 bit/s
+		case 6:
+			return ai + 9;	// 14400 bit/s
+		case 7:
+			return ai + 11;	// 19200 bit/s
+		case 8:
+			return ai + 14;	// 48000 bit/s
+		case 9:
+			return ai + 15;	// 56000 bit/s
+		case 15:
+			return ai + 40;	// negotiate bit/s
+		default:
+			break;
+	}
+	return ai;
+}
+
+static u_char
+DecodeASyncParams(u_char si2, u_char * p)
+{
+	u_char info;
+
+	switch (p[5]) {
+		case 66:	// 1200 bit/s
+			break;	// si2 don't change
+		case 88:	// 1200/75 bit/s
+			si2 += 1;
+			break;
+		case 87:	// 75/1200 bit/s
+			si2 += 2;
+			break;
+		case 67:	// 2400 bit/s
+			si2 += 3;
+			break;
+		case 69:	// 4800 bit/s
+			si2 += 4;
+			break;
+		case 72:	// 9600 bit/s
+			si2 += 5;
+			break;
+		case 73:	// 14400 bit/s
+			si2 += 6;
+			break;
+		case 75:	// 19200 bit/s
+			si2 += 7;
+			break;
+	}
+	info = p[7] & 0x7f;
+	if ((info & 16) && (!(info & 8)))	// 7 data bits
+		si2 += 32;	// else 8 data bits
+	if ((info & 96) == 96)	// 2 stop bits
+		si2 += 16;	// else 1 stop bit
+	if ((info & 2) && (!(info & 1)))	// even parity
+		si2 += 8;	// else no parity
+	return si2;
+}
+
+
+static u_char
+DecodeSyncParams(u_char si2, u_char info)
+{
+	switch (info & 0x7f) {
+		case 40:	// bit/s negotiation failed  ai := 165 not 175!
+			return si2 + 15;
+		case 15:	// 56000 bit/s failed, ai := 0 not 169 !
+			return si2 + 9;
+		case 14:	// 48000 bit/s
+			return si2 + 8;
+		case 11:	// 19200 bit/s
+			return si2 + 7;
+		case 9:	// 14400 bit/s
+			return si2 + 6;
+		case 8:	// 9600  bit/s
+			return si2 + 5;
+		case 5:	// 4800  bit/s
+			return si2 + 4;
+		case 3:	// 2400  bit/s
+			return si2 + 3;
+		case 23:	// 75/1200 bit/s
+			return si2 + 2;
+		case 24:	// 1200/75 bit/s
+			return si2 + 1;
+		default:	// 1200 bit/s
+			return si2;
+	}
+}
+
+static u_char
+DecodeSI2(u_char *p)
+{
+
+	if (p) {
+		switch (p[4] & 0x0f) {
+			case 0x01:
+				if (p[1] == 0x04)	// sync. Bitratenadaption
+					return DecodeSyncParams(160, p[5]);	// V.110/X.30
+				else if (p[1] == 0x06)	// async. Bitratenadaption
+					return DecodeASyncParams(192, p);	// V.110/X.30
+				break;
+			case 0x08:	// if (p[5] == 0x02) // sync. Bitratenadaption
+				if (p[1] > 3) 
+					return DecodeSyncParams(176, p[5]);	// V.120
+				break;
+		}
+	}
+	return 0;
+}
+
+static void
+i4l_l1err(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+
+	sendup(ch, 1, DL_RELEASE | INDICATION, NULL);
+	reset_channel(ch);
+	mISDN_FsmChangeState(fi, ST_NULL);
+}
+
+static void
+i4l_dhup(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	struct sk_buff	*skb;
+	u_char		tmp[8];
+
+	skb = mISDN_alloc_l3msg(8, MT_RELEASE);
+	if (!skb)
+		return;
+
+	tmp[0] = IE_CAUSE;
+	tmp[1] = 2;
+	if (ch->cause_val) {
+		tmp[2] = ch->cause_loc;
+		tmp[3] = ch->cause_val;
+	} else {
+		tmp[2] = 0x80;
+		tmp[3] = 0x9f; /* normal, unspecified */
+	}
+	mISDN_AddvarIE(skb, tmp);
+	sendup(ch, 1, CC_RELEASE | INDICATION, skb);
+	reset_channel(ch);
+	mISDN_FsmChangeState(fi, ST_NULL);
+}
+
+static void
+i4l_icall(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	setup_parm	*setup = arg;
+	u_char		tmp[36], *p;
+	struct sk_buff	*skb;
+	int		i,j;
+
+	test_and_set_bit(I4L_FLG_LOCK, &ch->Flags);
+	i4l_lock_drv(ch->drv);
+	if ((skb = alloc_skb(sizeof(int *) + 8, GFP_ATOMIC))) {
+		int	**idp = (int **)skb_put(skb, sizeof(idp));
+		mISDN_head_t *hh = mISDN_HEAD_P(skb);
+
+		*idp = &ch->l4id;
+		hh->prim = CC_NEW_CR | INDICATION;
+		i = ch->drv->inst.up.func(&ch->drv->inst.up, skb);
+		if (i) {
+			int_error();
+			dev_kfree_skb(skb);
+			return;
+		}
+		if (ch->drv->debug & 0x2)
+			printk(KERN_DEBUG "%s: l4id(%x) ch(%p)->nr %d\n", __FUNCTION__, ch->l4id, ch, ch->nr);
+	} else
+		return;
+	skb = mISDN_alloc_l3msg(260, MT_SETUP);
+	if (!skb)
+		return;
+	p = tmp;
+        switch (setup->si1) {
+		case 1:			/* Telephony                        */
+			*p++ = IE_BEARER;
+			*p++ = 0x3;	/* Length                           */
+			*p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio */
+			*p++ = 0x90;	/* Circuit-Mode 64kbps              */
+			*p++ = 0xa3;	/* A-Law Audio                      */
+			break;
+		case 5:			/* Datatransmission 64k, BTX        */
+		case 7:			/* Datatransmission 64k             */
+		default:
+			*p++ = IE_BEARER;
+			*p++ = 0x2;	/* Length                           */
+			*p++ = 0x88;	/* Coding CCITT, unrestr. dig. Info.*/
+			*p++ = 0x90;	/* Circuit-Mode 64kbps              */
+			break;
+	}
+	mISDN_AddvarIE(skb, tmp);
+	tmp[0] = IE_CHANNEL_ID;
+	tmp[1] = 1;
+	tmp[2] = 0x85 + ch->nr;
+	mISDN_AddvarIE(skb, tmp);
+	if (setup->phone[0]) {
+		i = 1;
+		if (setup->plan) {
+			tmp[i++] = setup->plan;
+			if (!(setup->plan & 0x80))
+				tmp[i++] = setup->screen;
+		} else
+			tmp[i++] = 0x81;
+		j = 0;
+		while (setup->phone[j]) {
+			if (setup->phone[j] == '.') /* subaddress */
+				break;
+			tmp[i++] = setup->phone[j++];
+		}
+		tmp[0] = i-1;
+		mISDN_AddIE(skb, IE_CALLING_PN, tmp);
+		if (setup->phone[j] == '.') {
+			i = 1;
+			tmp[i++] = 0x80;
+			j++;
+			while (setup->phone[j])
+				tmp[i++] = setup->phone[j++];
+			tmp[0] = i-1;
+			mISDN_AddIE(skb, IE_CALLING_SUB, tmp);
+		}
+	}
+	if (setup->eazmsn[0]) {
+		i = 1;
+		tmp[i++] = 0x81;
+		j = 0;
+		while (setup->eazmsn[j]) {
+			if (setup->eazmsn[j] == '.') /* subaddress */
+				break;
+			tmp[i++] = setup->eazmsn[j++];
+		}
+		tmp[0] = i-1;
+		mISDN_AddIE(skb, IE_CALLED_PN, tmp);
+		if (setup->eazmsn[j] == '.') {
+			i = 1;
+			tmp[i++] = 0x80;
+			j++;
+			while (setup->eazmsn[j])
+				tmp[i++] = setup->eazmsn[j++];
+			tmp[0] = i-1;
+			mISDN_AddIE(skb, IE_CALLED_SUB, tmp);
+		}
+	}
+	p = tmp;
+	*p++ = IE_LLC;
+	if ((setup->si2 >= 160) && (setup->si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
+		*p++ = 0x04;
+		*p++ = 0x88;
+		*p++ = 0x90;
+		*p++ = 0x21;
+		*p++ = EncodeSyncParams(setup->si2 - 160, 0x80);
+		test_and_set_bit(I4L_FLG_L1TRANS, &ch->Flags);
+	} else if ((setup->si2 >= 176) && (setup->si2 <= 191)) { // sync. Bitratenadaption, V.120
+		*p++ = 0x05;
+		*p++ = 0x88;
+		*p++ = 0x90;
+		*p++ = 0x28;
+		*p++ = EncodeSyncParams(setup->si2 - 176, 0);
+		*p++ = 0x82;
+		test_and_set_bit(I4L_FLG_L1TRANS, &ch->Flags);
+	} else if (setup->si2 >= 192) { // async. Bitratenadaption, V.110/X.30
+		*p++ = 0x06;
+		*p++ = 0x88;
+		*p++ = 0x90;
+		*p++ = 0x21;
+		p = EncodeASyncParams(p, setup->si2 - 192);
+		test_and_set_bit(I4L_FLG_L1TRANS, &ch->Flags);
+	} else {
+		switch(setup->si1) {
+			case 1:
+				*p++ = 0x3;
+				*p++ = 0x90;
+				*p++ = 0x90;
+				*p++ = 0xa3;
+				test_and_set_bit(I4L_FLG_L1TRANS, &ch->Flags);
+				break;
+			case 5:
+			case 7:
+			default:
+				*p++ = 0x2;
+				*p++ = 0x88;
+				*p++ = 0x90;
+				test_and_set_bit(I4L_FLG_L1HDLC, &ch->Flags);
+				break;
+		}
+	}
+	mISDN_AddvarIE(skb, tmp);
+	mISDN_FsmChangeState(fi, ST_ICALL);
+	sendup(ch, 1, CC_SETUP | INDICATION, skb);
+}
+
+static void
+i4l_dconn_out(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	struct sk_buff	*skb;
+	u_char		tmp[4];
+
+	skb = mISDN_alloc_l3msg(4, MT_CONNECT);
+	if (!skb)
+		return;
+
+	tmp[0] = IE_CHANNEL_ID;
+	tmp[1] = 1;
+	tmp[2] = 0x85 + ch->nr;
+	mISDN_AddvarIE(skb, tmp);
+	sendup(ch, 1, CC_CONNECT | INDICATION, skb);
+	mISDN_FsmChangeState(fi, ST_ACTIVD);
+}
+
+static void
+i4l_dconn_in(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+
+	sendup(ch, 1, CC_CONNECT_ACKNOWLEDGE | INDICATION, NULL);
+	mISDN_FsmChangeState(fi, ST_ACTIVD);
+}
+
+static void
+i4l_bconn_notready(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+
+	test_and_set_bit(I4L_FLG_BCONN, &ch->Flags);
+}
+
+static void
+i4l_bconn(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	int		prim = test_bit(I4L_FLG_LAYER1, &ch->Flags) ? PH_ACTIVATE : DL_ESTABLISH;
+
+	sendup(ch, 0, prim | INDICATION, NULL);
+	test_and_set_bit(I4L_FLG_BCONN, &ch->Flags);
+	mISDN_FsmChangeState(fi, ST_ACTIVB);
+	if (skb_queue_len(&ch->sendq))
+		sendqueued(ch);
+}
+
+static void
+i4l_bhup(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	int		prim = test_bit(I4L_FLG_LAYER1, &ch->Flags) ? PH_DEACTIVATE : DL_RELEASE;
+
+	mISDN_FsmChangeState(fi, ST_ACTIVD);
+	sendup(ch, 0, prim | INDICATION, NULL);
+}
+
+static void
+stackready(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_BREADY);
+	test_and_set_bit(I4L_FLG_BREADY, &ch->Flags);
+	if (test_bit(I4L_FLG_BCONN, &ch->Flags))
+		mISDN_FsmEvent(&ch->i4lm, EV_I4L_BCONN, NULL);
+}
+
+static void
+capi_ocall(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	struct sk_buff	*skb = arg;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	u_char		*p, *ps = skb->data;
+	isdn_ctrl	ctrl;
+	int		i,l;
+
+	mISDN_FsmChangeState(fi, ST_OCALL);
+	test_and_set_bit(I4L_FLG_LOCK, &ch->Flags);
+	i4l_lock_drv(ch->drv);
+	ps += L3_EXTRA_SIZE;
+	ctrl.parm.setup.si1 = 0;
+	ctrl.parm.setup.si2 = 0;
+	if (qi->bearer_capability) {
+		p = ps + qi->bearer_capability;
+		if ((p[1] > 1) && (p[1] < 11)) {
+			switch (p[2] & 0x7f) {
+				case 0x00: /* Speech */
+				case 0x10: /* 3.1 Khz audio */
+					ctrl.parm.setup.si1 = 1;
+					break;
+				case 0x08: /* Unrestricted digital information */
+					ctrl.parm.setup.si1 = 7;
+					if (qi->llc) 
+						ctrl.parm.setup.si2 = DecodeSI2(ps + qi->llc);
+					break;
+				case 0x09: /* Restricted digital information */
+					ctrl.parm.setup.si1 = 2;
+					break;
+				case 0x11:
+					/* Unrestr. digital information  with 
+					 * tones/announcements ( or 7 kHz audio)
+					 */
+					ctrl.parm.setup.si1 = 3;
+					break;
+				case 0x18: /* Video */
+					ctrl.parm.setup.si1 = 4;
+					break;
+			}
+			switch (p[3] & 0x7f) {
+				case 0x40: /* packed mode */
+					ctrl.parm.setup.si1 = 8;
+					break;
+			}
+		}
+	}
+	if ((ctrl.parm.setup.si1 == 7) && (ctrl.parm.setup.si2 < 160))
+		test_and_set_bit(I4L_FLG_L1HDLC, &ch->Flags);
+	else
+		test_and_set_bit(I4L_FLG_L1TRANS, &ch->Flags);
+	i = 0;
+	if (qi->calling_nr) {
+		p = ps + qi->calling_nr + 1;
+		l = *p++;
+		ctrl.parm.setup.plan = *p;
+		l--;
+		if (!(*p & 0x80)) {
+			p++;
+			ctrl.parm.setup.screen = *p;
+			l--;
+		} else
+			ctrl.parm.setup.screen = 0;
+		p++;
+		while(i<l)
+			ctrl.parm.setup.eazmsn[i++] = *p++;
+		ctrl.parm.setup.eazmsn[i] = 0;
+	} else
+		ctrl.parm.setup.eazmsn[0] = 0;
+	if (qi->calling_sub) {
+		p = ps + qi->calling_sub + 1;
+		l = *p++;
+		l--;
+		p++;
+		if (l>0)
+			ctrl.parm.setup.eazmsn[i++] = '.';
+		while(l>0) {
+			ctrl.parm.setup.eazmsn[i++] = *p++;
+			l--;
+		}
+		ctrl.parm.setup.eazmsn[i] = 0;
+	}
+	i = 0;
+	if (qi->called_nr) {
+		p = ps + qi->called_nr + 1;
+		l = *p++;
+		p++;
+		l--;
+		while(i<l)
+			ctrl.parm.setup.phone[i++] = *p++;
+		ctrl.parm.setup.phone[i] = 0;
+	} else
+		ctrl.parm.setup.phone[0] = 0;
+	if (qi->called_sub) {
+		p = ps + qi->called_sub + 1;
+		l = *p++;
+		l--;
+		p++;
+		if (l>0)
+			ctrl.parm.setup.phone[i++] = '.';
+		while(l>0) {
+			ctrl.parm.setup.phone[i++] = *p++;
+			l--;
+		}
+		ctrl.parm.setup.phone[i] = 0;
+	}
+	if (test_bit(I4L_FLG_L1TRANS, &ch->Flags)) {
+		i4l_cmd(ch->drv, ch->nr | (ISDN_PROTO_L2_TRANS << 8), ISDN_CMD_SETL2);
+		i4l_cmd(ch->drv, ch->nr | (ISDN_PROTO_L3_TRANS << 8), ISDN_CMD_SETL3);
+	} else {
+		i4l_cmd(ch->drv, ch->nr | (ISDN_PROTO_L2_HDLC << 8), ISDN_CMD_SETL2);
+		i4l_cmd(ch->drv, ch->nr | (ISDN_PROTO_L3_TRANS << 8), ISDN_CMD_SETL3);
+	}
+	if (ch->drv->debug & 0x4)
+		printk(KERN_DEBUG "ocall from %s, si(%d/%d) -> %s\n", ctrl.parm.setup.eazmsn,
+			ctrl.parm.setup.si1, ctrl.parm.setup.si2, ctrl.parm.setup.phone);
+	ctrl.driver = ch->drv->idx;
+	ctrl.arg = ch->nr;
+	ctrl.command = ISDN_CMD_DIAL;
+	ch->drv->interface->command(&ctrl);
+	dev_kfree_skb(skb);
+}
+
+static void
+capi_alert(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	mISDN_FsmChangeState(fi, ST_ALERT);
+	i4l_cmd(ch->drv, ch->nr, ISDN_CMD_ALERT);
+	if (skb)
+		dev_kfree_skb(skb);
+}
+
+static void
+capi_connect(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	if (test_bit(I4L_FLG_L1TRANS, &ch->Flags)) {
+		i4l_cmd(ch->drv, ch->nr | (ISDN_PROTO_L2_TRANS << 8), ISDN_CMD_SETL2);
+		i4l_cmd(ch->drv, ch->nr | (ISDN_PROTO_L3_TRANS << 8), ISDN_CMD_SETL3);
+	} else {
+		i4l_cmd(ch->drv, ch->nr | (ISDN_PROTO_L2_HDLC << 8), ISDN_CMD_SETL2);
+		i4l_cmd(ch->drv, ch->nr | (ISDN_PROTO_L3_TRANS << 8), ISDN_CMD_SETL3);
+	}
+	mISDN_FsmChangeState(fi, ST_WAITDCONN);
+	i4l_cmd(ch->drv, ch->nr, ISDN_CMD_ACCEPTD);
+	if (skb)
+		dev_kfree_skb(skb);
+}
+
+static void
+capi_disconnect(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	mISDN_FsmChangeState(fi, ST_HANGUP);
+	test_and_set_bit(I4L_FLG_HANGUP, &ch->Flags);
+	i4l_cmd(ch->drv, ch->nr, ISDN_CMD_HANGUP);
+	if (skb)
+		dev_kfree_skb(skb);
+}
+
+static void
+capi_release(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	if (!test_and_clear_bit(I4L_FLG_HANGUP, &ch->Flags))
+		i4l_cmd(ch->drv, ch->nr, ISDN_CMD_HANGUP);
+	if (skb)
+		dev_kfree_skb(skb);
+	reset_channel(ch);
+	mISDN_FsmChangeState(fi, ST_NULL);
+}
+
+static void
+capi_establishb(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+
+	i4l_cmd(ch->drv, ch->nr, ISDN_CMD_ACCEPTB);
+}
+
+static void
+capi_releaseb(struct FsmInst *fi, int event, void *arg)
+{
+	i4l_channel_t	*ch = fi->userdata;
+
+	test_and_clear_bit(I4L_FLG_BREADY, &ch->Flags);
+	mISDN_FsmChangeState(fi, ST_ACTIVD);
+}
+
+static int
+Dchannel_i4l(mISDNif_t *hif, struct sk_buff *skb)
+{
+	int		i, ret = -EINVAL;
+	mISDN_head_t	*hh;
+	i4l_capi_t	*ic;
+	i4l_channel_t	*ch;
+
+	if (!hif || !skb)
+		return(ret);
+	ic = hif->fdata;
+	hh = mISDN_HEAD_P(skb);
+	if (ic->debug & 0x2)
+		printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", __FUNCTION__, hh->prim, hh->dinfo);
+	if (!ic)
+		return(ret);
+	if ((DL_ESTABLISH | REQUEST) == hh->prim) {
+		// FIXME
+		dev_kfree_skb(skb);
+		return(0);
+	}
+	ch = ic->ch;
+	for (i=0; i < ic->nr_ch; i++) {
+		if (ch->l4id == hh->dinfo)
+			break;
+		ch++;
+	}
+	if (i == ic->nr_ch)
+		ch = NULL;
+	if ((CC_NEW_CR | REQUEST) == hh->prim) {
+		if (ch) {
+			printk(KERN_WARNING "%s: ch%x in use\n", __FUNCTION__, ch->nr);
+			ret = -EBUSY;
+		} else {
+			ch = ic->ch;
+			for (i=0; i < ic->nr_ch; i++) {
+				if (ch->l4id == 0)
+					break;
+				ch++;
+			}
+			if (i == ic->nr_ch) {
+				ret = -EBUSY;
+			} else {
+				ch->l4id = hh->dinfo;
+				ret = 0;
+				dev_kfree_skb(skb);
+			}
+		}
+		return(ret);
+	}
+	if (!ch) {
+		printk(KERN_WARNING "%s: no channel prim(%x) id(%x)\n", __FUNCTION__, hh->prim, hh->dinfo);
+		return(ret);
+	}
+	if (ch->drv->debug & 0x4)
+		mISDN_LogL3Msg(skb);
+	switch(hh->prim) {
+		case CC_SETUP | REQUEST:
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_OCALL, skb);
+			break;
+		case CC_ALERTING | REQUEST:
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_ALERT, skb);
+			break;
+		case CC_CONNECT | REQUEST:
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_DCONNECT, skb);
+			break;
+		case CC_DISCONNECT | REQUEST:
+		case CC_RELEASE | REQUEST:
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_DISCONNECT, skb);
+			break;
+		case CC_RELEASE_COMPLETE | REQUEST:
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_RELEASE, skb);
+			break;
+		default:
+			if (debug)
+				printk(KERN_DEBUG "%s: ch%x prim(%x) id(%x) not handled\n",
+					__FUNCTION__, ch->nr, hh->prim, hh->dinfo);
+			break;
+	}
+	return(ret);
+}
+
+static int
+Bchannel_i4l(mISDNif_t *hif, struct sk_buff *skb)
+{
+	i4l_channel_t	*ch;
+	int		ret = -EINVAL;
+	mISDN_head_t	*hh;
+
+	if (!hif || !skb)
+		return(ret);
+	ch = hif->fdata;
+	hh = mISDN_HEAD_P(skb);
+	if (ch->drv->debug & 0x20)
+		printk(KERN_DEBUG  "%s: prim(%x)\n", __FUNCTION__, hh->prim);
+	switch(hh->prim) {
+		case PH_ACTIVATE | REQUEST:
+		case DL_ESTABLISH | REQUEST:
+			mISDN_FsmEvent(&ch->i4lm, EV_CAPI_ESTABLISHB, NULL);
+			skb_trim(skb, 0);
+			ret = if_newhead(&ch->inst.up, hh->prim | CONFIRM, 0, skb);
+			break;
+		case PH_DEACTIVATE | REQUEST:
+		case DL_RELEASE | REQUEST:
+			mISDN_FsmEvent(&ch->i4lm, EV_CAPI_RELEASEB, NULL);
+			skb_trim(skb, 0);
+			ret = if_newhead(&ch->inst.up, hh->prim | CONFIRM, 0, skb);
+			break;
+		case PH_DATA | REQUEST:
+		case DL_DATA | REQUEST:
+			skb_queue_tail(&ch->sendq, skb);
+			ret = sendqueued(ch);
+			break;
+		default:
+			if (debug)
+				printk(KERN_DEBUG "%s: ch%x prim(%x) id(%x) not handled\n",
+					__FUNCTION__, ch->nr, hh->prim, hh->dinfo);
+			break;
+	}
+	return(ret);
+}
+
+
+/*
+ * Receive a packet from B-Channel. (Called from low-level-module)
+ */
+static void
+I4Lcapi_receive_skb_callback(int drvidx, int channel, struct sk_buff *skb)
+{
+	i4l_capi_t	*ic = drvmap[drvidx];
+	i4l_channel_t	*ch;
+	mISDN_headext_t	*hhe = mISDN_HEADEXT_P(skb);
+	int		ret;
+
+	if (!ic) {
+		int_error();
+		return;
+	}
+	ch = ic->ch + channel;
+	if (!test_bit(I4L_FLG_BREADY, &ch->Flags)) {
+		if (ic->debug & 0x10)
+			printk(KERN_WARNING "I4Lcapi_receive_skb_callback: bc%d/%d not ready\n", channel, ch->nr);
+		dev_kfree_skb(skb);
+		return;
+	}
+	hhe->prim = test_bit(I4L_FLG_LAYER1, &ch->Flags) ? PH_DATA_IND : DL_DATA_IND;
+	if (!ch->inst.up.func) {
+		dev_kfree_skb(skb);
+		int_error();
+		return;
+	}
+	if (in_interrupt()) {
+		hhe->func.iff = ch->inst.up.func;
+		hhe->data[0] = &ch->inst.up;
+		ret = ch->inst.obj->ctrl(NULL, MGR_QUEUEIF | REQUEST, skb);
+	} else
+		ret = ch->inst.up.func(&ch->inst.up, skb);
+	if (ret)
+		dev_kfree_skb(skb);
+}
+
+static int
+i4l_stat_run(i4l_capi_t *ic) {
+	int	err;
+
+	err = mISDN_ctrl(ic->inst.st, MGR_SETSTACK | REQUEST, &ic->pid);
+	if (err) {
+		printk(KERN_ERR  "MGR_SETSTACK REQUEST dch err(%d)\n", err);
+		mISDN_ctrl(ic->inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return(err);
+	}
+	return(0);
+}
+
+static int
+i4l_sent_pkt(i4l_capi_t *drv, isdn_ctrl *c)
+{
+	i4l_channel_t	*ch = drv->ch;
+	struct sk_buff	*skb;
+	int		ret;
+	mISDN_headext_t	*hhe;
+
+	if (c->arg < 0)
+		return -1;
+	ch += c->arg;
+	skb = skb_dequeue(&ch->ackq);
+	if (!skb) {
+		int_error();
+		return(-1);
+	}
+	if (drv->debug & 0x800)
+		printk(KERN_DEBUG "bc%ld ack skb(%p)\n", c->arg, skb);
+	if (skb_queue_len(&ch->sendq))
+		sendqueued(ch);
+	skb_trim(skb, 0);
+	hhe = mISDN_HEADEXT_P(skb);
+	hhe->prim |= CONFIRM;
+	if (in_interrupt()) {
+		hhe->func.iff = ch->inst.up.func;
+		hhe->data[0] = &ch->inst.up;
+		ret = ch->inst.obj->ctrl(NULL, MGR_QUEUEIF | REQUEST, skb);
+	} else
+		ret = ch->inst.up.func(&ch->inst.up, skb);
+	if (ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+#define I4L_LOGBUF_SIZE	256
+static char	logbuf[I4L_LOGBUF_SIZE];
+
+static int
+i4l_stavail(i4l_capi_t *drv, isdn_ctrl *c)
+{
+	int		len = c->arg;
+
+	if (drv->interface->readstat) {
+		while(len>0) {
+			if (len < I4L_LOGBUF_SIZE) {
+				drv->interface->readstat(logbuf, len, 0, drv->idx, 0);
+				logbuf[len] = 0;
+			} else {
+				drv->interface->readstat(logbuf, I4L_LOGBUF_SIZE - 1, 0, drv->idx, 0);
+				logbuf[I4L_LOGBUF_SIZE] = 0;
+			}
+			if (drv->debug & 0x1)
+				printk(KERN_DEBUG "%s", logbuf);
+			len -= (I4L_LOGBUF_SIZE -1);
+		}
+	}
+	return(0);
+}
+
+static int
+I4Lcapi_status_callback(isdn_ctrl *c)
+{
+	i4l_capi_t	*drv = drvmap[c->driver];
+	i4l_channel_t	*ch;
+	int		i, ret = -1;
+
+	if (!drv)
+		return(-1);
+	if (c->command == ISDN_STAT_BSENT)
+		return(i4l_sent_pkt(drv, c));
+	if (c->command == ISDN_STAT_STAVAIL)
+		return(i4l_stavail(drv, c));
+	ch = drv->ch;
+	if (drv->debug & 0x8)
+		printk(KERN_DEBUG "drv%d cmd(%d) arg(%ld)\n",
+			c->driver, c->command, c->arg);
+	switch (c->command) {
+		case ISDN_STAT_RUN:
+			ret = i4l_stat_run(drv);
+			break;
+		case ISDN_STAT_STOP:
+			// FIXME
+			ret = 0;
+			break;
+		case ISDN_STAT_ICALL:
+			if (c->arg < 0)
+				return -1;
+			ch += c->arg;
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_ICALL, &c->parm.setup);
+			break;
+		case ISDN_STAT_CINF:
+			if (c->arg < 0)
+				return -1;
+			// FIXME
+			ret = 0;
+			break;
+		case ISDN_STAT_CAUSE:
+			if (c->arg < 0)
+				return -1;
+			ch += c->arg;
+			if ((c->parm.num[0] == 'E') || (c->parm.num[0] == 'L'))
+				i = 1;
+			else
+				i = 0;
+			sscanf(&c->parm.num[i], "%2X%2X", &ch->cause_loc, &ch->cause_val);
+			ch->cause_loc |= 0x80;
+			ch->cause_val |= 0x80;
+			if (drv->debug & 0x1)
+				printk(KERN_DEBUG "isdn: ch%ld cause: %s %02x%02x\n",
+					c->arg, c->parm.num, ch->cause_loc, ch->cause_val);
+			ret = 0;
+			break;
+		case ISDN_STAT_DISPLAY:
+			// FIXME
+			ret = 0;
+			break;
+		case ISDN_STAT_DCONN:
+			if (c->arg < 0)
+				return -1;
+			ch += c->arg;
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_DCONN, NULL);
+			break;
+		case ISDN_STAT_DHUP:
+			if (c->arg < 0)
+				return -1;
+			ch += c->arg;
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_DHUP, NULL);
+			break;
+		case ISDN_STAT_BCONN:
+			if (c->arg < 0)
+				return -1;
+			ch += c->arg;
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_BCONN, NULL);
+			break;
+		case ISDN_STAT_BHUP:
+			if (c->arg < 0)
+				return -1;
+			ch += c->arg;
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_BHUP, NULL);
+			break;
+		case ISDN_STAT_NODCH:
+		case ISDN_STAT_L1ERR:
+			if (c->arg < 0)
+				return -1;
+			ch += c->arg;
+			ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_L1ERR, NULL);
+			break;
+		case ISDN_STAT_ADDCH:
+		case ISDN_STAT_DISCH:
+			// FIXME
+			ret = 0;
+			break;
+		case ISDN_STAT_UNLOAD:
+			ret = mISDN_ctrl(drv->inst.st, MGR_DELSTACK | REQUEST, NULL);
+			MOD_DEC_USE_COUNT;
+			break;
+		case CAPI_PUT_MESSAGE:
+			// FIXME
+			break;
+		case ISDN_STAT_FAXIND:
+			// FIXME
+			break;
+		case ISDN_STAT_AUDIO:
+			// FIXME
+			break;
+	        case ISDN_STAT_PROT:
+	        case ISDN_STAT_REDIR:
+	        	// FIXME
+			break;	        	
+		default:
+			break;
+	}
+	return(ret);
+}  
+
+static int
+I4Lcapi_manager(void *data, u_int prim, void *arg) {
+	i4l_capi_t	*card = I4Lcapi.ilist;
+	mISDNinstance_t	*inst = data;
+	i4l_channel_t	*channel = NULL;
+	int		nr_ch = -2;
+
+	if (debug & 0x100)
+		printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n",
+			__FUNCTION__, data, prim, arg);
+	if (prim == (MGR_HASPROTOCOL | REQUEST))
+		return(mISDN_HasProtocolP(&I4Lcapi, arg));
+	if (!data) {
+		printk(KERN_ERR "I4Lcapi_manager no data prim %x arg %p\n",
+			prim, arg);
+		return(-EINVAL);
+	}
+	while(card) {
+		if (&card->inst == inst) {
+			nr_ch = -1;
+			break;
+		}
+		channel = card->ch;
+		for (nr_ch = 0; nr_ch < card->nr_ch; nr_ch++) {
+			if (&channel->inst == inst)
+				break;
+			channel++;
+		}
+		if (nr_ch != card->nr_ch)
+			break;
+		card = card->next;
+		channel = NULL;
+		nr_ch = -2;
+	}
+	if (nr_ch == -2) {
+		printk(KERN_ERR "I4Lcapi_manager no channel data %p prim %x arg %p\n",
+			data, prim, arg);
+		return(-EINVAL);
+	}
+	switch(prim) {
+	    case MGR_REGLAYER | CONFIRM:
+		break;
+	    case MGR_UNREGLAYER | REQUEST:
+		mISDN_ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up);
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+		break;
+	    case MGR_RELEASE | INDICATION:
+		if (nr_ch == -1) {
+			release_card(card->idx);
+		} else {
+			I4Lcapi.refcnt--;
+		}
+		break;
+	    case MGR_CONNECT | REQUEST:
+		return(mISDN_ConnectIF(inst, arg));
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+		if (nr_ch == -1)
+			return(mISDN_SetIF(inst, arg, prim, Dchannel_i4l, NULL, card));
+		else
+			return(mISDN_SetIF(inst, arg, prim, Bchannel_i4l, NULL, channel));
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		return(mISDN_DisConnectIF(inst, arg));
+	    case MGR_SETSTACK | INDICATION:
+	    	if (nr_ch >= 0) {
+			if (inst->pid.protocol[2] != ISDN_PID_L2_B_TRANS)
+				test_and_set_bit(I4L_FLG_LAYER1, &channel->Flags);
+			mISDN_FsmEvent(&channel->i4lm, EV_STACKREADY, NULL);
+		}
+		break;
+	    default:
+		if (debug)
+			printk(KERN_DEBUG "I4Lcapi_manager prim %x not handled\n", prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+static i4l_capi_reg_t	I4Lcapireg;
+
+static int
+I4Lcapi_register(isdn_if *iif)
+{
+	int		drvidx = 0;
+	int		i, err;
+	i4l_channel_t	*ch;
+
+	if (!iif->writebuf_skb) {
+		printk(KERN_ERR "I4Lcapi_register: No write routine given.\n");
+		return 0;
+	}
+	for (drvidx=0; drvidx<MAX_CARDS; drvidx++) {
+		if (drvmap[drvidx] == NULL)
+			break;
+	}
+	if (drvidx == MAX_CARDS) {
+		printk(KERN_ERR "I4Lcapi_register: no driver slot this card\n");
+		return(0);
+	}
+	drvmap[drvidx] = kmalloc(sizeof(i4l_capi_t), GFP_KERNEL);
+	if (!drvmap[drvidx]) {
+		printk(KERN_ERR "I4Lcapi_register: no memory for i4l_capi_t\n");
+		return(0);
+	}
+	memset(drvmap[drvidx], 0, sizeof(i4l_capi_t));
+	drvmap[drvidx]->ch = kmalloc(iif->channels * sizeof(i4l_channel_t), GFP_KERNEL);
+	if (!drvmap[drvidx]->ch) {
+		printk(KERN_ERR "I4Lcapi_register: no memory for i4l_channel_t\n");
+		kfree(drvmap[drvidx]);
+		drvmap[drvidx] = NULL;
+		return(0);
+	}
+	drvmap[drvidx]->idx = drvidx;
+	drvmap[drvidx]->interface = iif;
+	drvmap[drvidx]->nr_ch = iif->channels;
+	iif->channels = drvidx;
+
+	iif->rcvcallb_skb = I4Lcapi_receive_skb_callback;
+	iif->statcallb = I4Lcapi_status_callback;
+
+	APPEND_TO_LIST(drvmap[drvidx], ((i4l_capi_t *)I4Lcapi.ilist));
+	drvmap[drvidx]->debug = debug;
+	drvmap[drvidx]->inst.pid.layermask = ISDN_LAYER(0) | ISDN_LAYER(1) | ISDN_LAYER(2) | ISDN_LAYER(3);
+	drvmap[drvidx]->inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
+	drvmap[drvidx]->inst.pid.protocol[1] = ISDN_PID_L1_TE_S0;
+	drvmap[drvidx]->inst.pid.protocol[2] = ISDN_PID_L2_LAPD;
+	drvmap[drvidx]->inst.pid.protocol[3] = ISDN_PID_L3_DSS1USER;
+	mISDN_init_instance(&drvmap[drvidx]->inst, &I4Lcapi, drvmap[drvidx]);
+	sprintf(drvmap[drvidx]->inst.name, "Fritz%d", drvidx+1);
+	mISDN_set_dchannel_pid(&drvmap[drvidx]->pid, 2, 0);
+	for (i=0; i < drvmap[drvidx]->nr_ch; i++) {
+		init_channel(drvmap[drvidx], i);
+	}
+	err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &drvmap[drvidx]->inst);
+	if (err) {
+		release_card(drvidx);
+		return(err);
+	}
+	ch = drvmap[drvidx]->ch;
+	for (i=0; i < drvmap[drvidx]->nr_ch; i++) {
+		err = mISDN_ctrl(drvmap[drvidx]->inst.st, MGR_NEWSTACK | REQUEST, &ch->inst);
+		if (err) {
+			printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
+			mISDN_ctrl(drvmap[drvidx]->inst.st, MGR_DELSTACK | REQUEST, NULL);
+			return(err);
+		}
+		ch++;
+	}
+	MOD_INC_USE_COUNT;
+	return(1);
+}
+
+static struct FsmNode I4LFnList[] =
+{
+	{ST_NULL,	EV_I4L_ICALL,		i4l_icall},
+	{ST_NULL,	EV_CAPI_OCALL,		capi_ocall},
+	{ST_ICALL,	EV_I4L_DHUP,		i4l_dhup},
+	{ST_ICALL,	EV_I4L_L1ERR,		i4l_l1err},
+	{ST_ICALL,	EV_CAPI_ALERT,		capi_alert},
+	{ST_ICALL,	EV_CAPI_DCONNECT,	capi_connect},
+	{ST_ICALL,	EV_CAPI_DISCONNECT,	capi_disconnect},
+	{ST_ICALL,	EV_CAPI_RELEASE,	capi_release},
+	{ST_OCALL,	EV_I4L_DHUP,		i4l_dhup},
+	{ST_OCALL,	EV_I4L_L1ERR,		i4l_l1err},
+	{ST_OCALL,	EV_CAPI_DISCONNECT,	capi_disconnect},
+	{ST_OCALL,	EV_CAPI_RELEASE,	capi_release},
+	{ST_OCALL,	EV_I4L_DCONN,		i4l_dconn_out},
+	{ST_PROCEED,	EV_I4L_DHUP,		i4l_dhup},
+	{ST_PROCEED,	EV_I4L_L1ERR,		i4l_l1err},
+	{ST_PROCEED,	EV_CAPI_ALERT,		capi_alert},
+	{ST_PROCEED,	EV_CAPI_DCONNECT,	capi_connect},
+	{ST_PROCEED,	EV_CAPI_DISCONNECT,	capi_disconnect},
+	{ST_PROCEED,	EV_CAPI_RELEASE,	capi_release},
+	{ST_ALERT,	EV_I4L_DHUP,		i4l_dhup},
+	{ST_ALERT,	EV_I4L_L1ERR,		i4l_l1err},
+	{ST_ALERT,	EV_CAPI_DCONNECT,	capi_connect},
+	{ST_ALERT,	EV_CAPI_DISCONNECT,	capi_disconnect},
+	{ST_ALERT,	EV_CAPI_RELEASE,	capi_release},
+	{ST_WAITDCONN,	EV_I4L_DCONN,		i4l_dconn_in},
+	{ST_WAITDCONN,	EV_CAPI_DISCONNECT,	capi_disconnect},
+	{ST_WAITDCONN,	EV_CAPI_RELEASE,	capi_release},
+	{ST_WAITDCONN,	EV_I4L_DHUP,		i4l_dhup},
+	{ST_ACTIVD,	EV_I4L_DHUP,		i4l_dhup},
+	{ST_ACTIVD,	EV_I4L_L1ERR,		i4l_l1err},
+	{ST_ACTIVD,	EV_CAPI_DISCONNECT,	capi_disconnect},
+	{ST_ACTIVD,	EV_CAPI_RELEASE,	capi_release},
+	{ST_ACTIVD,	EV_I4L_BCONN,		i4l_bconn_notready},
+	{ST_ACTIVD,	EV_STACKREADY,		stackready},
+	{ST_BREADY,	EV_CAPI_ESTABLISHB,	capi_establishb},
+	{ST_BREADY,	EV_I4L_BCONN,		i4l_bconn},
+	{ST_BREADY,	EV_I4L_DHUP,		i4l_dhup},
+	{ST_BREADY,	EV_I4L_BHUP,		i4l_bhup},
+	{ST_BREADY,	EV_I4L_L1ERR,		i4l_l1err},
+	{ST_BREADY,	EV_CAPI_RELEASEB,	capi_releaseb},
+	{ST_BREADY,	EV_CAPI_DISCONNECT,	capi_disconnect},
+	{ST_BREADY,	EV_CAPI_RELEASE,	capi_release},
+	{ST_ACTIVB,	EV_I4L_DHUP,		i4l_dhup},
+	{ST_ACTIVB,	EV_I4L_BHUP,		i4l_bhup},
+	{ST_ACTIVB,	EV_I4L_L1ERR,		i4l_l1err},
+	{ST_ACTIVB,	EV_CAPI_DISCONNECT,	capi_disconnect},
+	{ST_ACTIVB,	EV_CAPI_RELEASE,	capi_release},
+	{ST_ACTIVB,	EV_CAPI_RELEASEB,	capi_releaseb},
+	{ST_HANGUP,	EV_I4L_DHUP,		i4l_dhup},
+	{ST_HANGUP,	EV_I4L_L1ERR,		i4l_l1err},
+	{ST_HANGUP,	EV_CAPI_RELEASE,	capi_release},
+};
+
+#define I4L_FN_COUNT	(sizeof(I4LFnList)/sizeof(struct FsmNode))
+
+static char	*I4L_capi_name = "I4L CAPI";
+
+int
+I4Lcapi_init(void)
+{
+	int err;
+
+	printk(KERN_INFO "I4L CAPI interface modul version %s\n", mISDN_getrev(i4lcapi_revision));
+#ifdef MODULE
+	I4Lcapi.owner = THIS_MODULE;
+#endif
+	I4Lcapi.name = I4L_capi_name;
+	I4Lcapi.own_ctrl = I4Lcapi_manager;
+	I4Lcapi.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0;
+	I4Lcapi.DPROTO.protocol[1] = ISDN_PID_L1_TE_S0;
+	I4Lcapi.DPROTO.protocol[2] = ISDN_PID_L2_LAPD | ISDN_PID_L2_DF_PTP;
+	I4Lcapi.DPROTO.protocol[3] = ISDN_PID_L3_DSS1USER | ISDN_PID_L3_DF_PTP;
+	I4Lcapi.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS | ISDN_PID_L1_B_64HDLC;
+	I4Lcapi.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS;
+	I4Lcapi.prev = NULL;
+	I4Lcapi.next = NULL;
+	
+	i4lfsm_s.state_count = STATE_COUNT;
+	i4lfsm_s.event_count = EVENT_COUNT;
+	i4lfsm_s.strEvent = strI4LEvent;
+	i4lfsm_s.strState = strI4LState;
+	mISDN_FsmNew(&i4lfsm_s, I4LFnList, I4L_FN_COUNT);
+	if ((err = mISDN_register(&I4Lcapi))) {
+		printk(KERN_ERR "Can't register I4L CAPI error(%d)\n", err);
+		mISDN_FsmFree(&i4lfsm_s);
+		return(err);
+	}
+	I4Lcapireg.register_func = I4Lcapi_register;
+	strcpy(I4Lcapireg.name, "I4L CAPI");
+	err = register_i4lcapi(&I4Lcapireg);
+	printk(KERN_INFO "registered I4L CAPI %s err(%d)\n", i4lcapi_revision, err);
+	return(0);
+}
+
+#ifdef MODULE
+void
+I4Lcapi_cleanup(void)
+{
+	
+	int err;
+	if ((err = mISDN_unregister(&I4Lcapi))) {
+		printk(KERN_ERR "Can't unregister I4Lcapi error(%d)\n", err);
+		return;
+	}
+	while(I4Lcapi.ilist) {
+		printk(KERN_ERR "I4Lcapi card struct not empty refs %d\n",
+			I4Lcapi.refcnt);
+		release_card(((i4l_capi_t *)I4Lcapi.ilist)->idx);
+	}
+	mISDN_FsmFree(&i4lfsm_s);
+	unregister_i4lcapi();
+	return;
+}
+
+module_init(I4Lcapi_init);
+module_exit(I4Lcapi_cleanup);
+
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isac.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isac.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isac.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,838 @@
+/* $Id: isac.c,v 1.18 2006/12/21 15:25:06 nadi Exp $
+ *
+ * isac.c   ISAC specific routines
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ *		This file is (c) under GNU PUBLIC LICENSE
+ */
+
+#include <linux/module.h>
+#include "core.h"
+#include "channel.h"
+#include "isac.h"
+#include "arcofi.h"
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+
+#define DBUSY_TIMER_VALUE	80
+#define ARCOFI_USE		1
+
+const char *isac_revision = "$Revision: 1.18 $";
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+EXPORT_SYMBOL(mISDN_isac_init);
+EXPORT_SYMBOL(mISDN_isac_free);
+EXPORT_SYMBOL(mISDN_isac_interrupt);
+EXPORT_SYMBOL(mISDN_clear_isac);
+EXPORT_SYMBOL(mISDN_ISAC_l1hw);
+#endif
+
+static inline void
+ph_command(channel_t *dch, unsigned int command)
+{
+	if (dch->debug & L1_DEB_ISAC)
+		mISDN_debugprint(&dch->inst, "ph_command %x", command);
+	if (dch->type & ISAC_TYPE_ISACSX)
+		dch->write_reg(dch->inst.privat, ISACSX_CIX0, (command << 4) | 0xE);
+	else
+		dch->write_reg(dch->inst.privat, ISAC_CIX0, (command << 2) | 3);
+}
+
+static void
+isac_ph_state_change(channel_t *dch)
+{
+	u_int		prim = PH_SIGNAL | INDICATION;
+	u_int		para = 0;
+
+	switch (dch->state) {
+		case (ISAC_IND_RS):
+		case (ISAC_IND_EI):
+			ph_command(dch, ISAC_CMD_DUI);
+			prim = PH_CONTROL | INDICATION;
+			para = HW_RESET;
+			break;
+		case (ISAC_IND_DID):
+			prim = PH_CONTROL | CONFIRM;
+			para = HW_DEACTIVATE;
+			break;
+		case (ISAC_IND_DR):
+			prim = PH_CONTROL | INDICATION;
+			para = HW_DEACTIVATE;
+			break;
+		case (ISAC_IND_PU):
+			prim = PH_CONTROL | INDICATION;
+			para = HW_POWERUP;
+			break;
+		case (ISAC_IND_RSY):
+			para = ANYSIGNAL;
+			break;
+		case (ISAC_IND_ARD):
+			para = INFO2;
+			break;
+		case (ISAC_IND_AI8):
+			para = INFO4_P8;
+			break;
+		case (ISAC_IND_AI10):
+			para = INFO4_P10;
+			break;
+		default:
+			return;
+	}
+	mISDN_queue_data(&dch->inst, FLG_MSG_UP, prim, para, 0, NULL, 0);
+}
+
+#ifdef OBSOLETE
+static void
+isac_hwbh(channel_t *dch)
+{
+	if (dch->debug)
+		printk(KERN_DEBUG "%s: event %lx\n", __FUNCTION__, dch->event);
+	if (test_and_clear_bit(D_L1STATECHANGE, &dch->event))
+		isac_new_ph(dch);		
+#if ARCOFI_USE
+	if (!(ISAC_TYPE_ARCOFI & dch->type))
+		return;
+	if (test_and_clear_bit(D_RX_MON1, &dch->event))
+		arcofi_fsm(dch, ARCOFI_RX_END, NULL);
+	if (test_and_clear_bit(D_TX_MON1, &dch->event))
+		arcofi_fsm(dch, ARCOFI_TX_END, NULL);
+#endif
+}
+#endif
+
+void
+isac_empty_fifo(channel_t *dch, int count)
+{
+	u_char *ptr;
+
+	if ((dch->debug & L1_DEB_ISAC) && !(dch->debug & L1_DEB_ISAC_FIFO))
+		mISDN_debugprint(&dch->inst, "isac_empty_fifo");
+
+	if (!dch->rx_skb) {
+		if (!(dch->rx_skb = alloc_stack_skb(MAX_DFRAME_LEN_L1, dch->up_headerlen))) {
+			printk(KERN_WARNING "mISDN: D receive out of memory\n");
+			dch->write_reg(dch->inst.privat, ISAC_CMDR, 0x80);
+			return;
+		}
+	}
+	if ((dch->rx_skb->len + count) >= MAX_DFRAME_LEN_L1) {
+		if (dch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&dch->inst, "isac_empty_fifo overrun %d",
+				dch->rx_skb->len + count);
+		dch->write_reg(dch->inst.privat, ISAC_CMDR, 0x80);
+		return;
+	}
+	ptr = skb_put(dch->rx_skb, count);
+	dch->read_fifo(dch->inst.privat, ptr, count);
+	dch->write_reg(dch->inst.privat, ISAC_CMDR, 0x80);
+	if (dch->debug & L1_DEB_ISAC_FIFO) {
+		char *t = dch->log;
+
+		t += sprintf(t, "isac_empty_fifo cnt %d", count);
+		mISDN_QuickHex(t, ptr, count);
+		mISDN_debugprint(&dch->inst, dch->log);
+	}
+}
+
+static void
+isac_fill_fifo(channel_t *dch)
+{
+	int count, more;
+	u_char *ptr;
+
+	if ((dch->debug & L1_DEB_ISAC) && !(dch->debug & L1_DEB_ISAC_FIFO))
+		mISDN_debugprint(&dch->inst, "isac_fill_fifo");
+	if (!dch->tx_skb)
+		return;
+	count = dch->tx_skb->len - dch->tx_idx;
+	if (count <= 0)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = dch->tx_skb->data + dch->tx_idx;
+	dch->tx_idx += count;
+	dch->write_fifo(dch->inst.privat, ptr, count);
+	dch->write_reg(dch->inst.privat, ISAC_CMDR, more ? 0x8 : 0xa);
+	if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) {
+		mISDN_debugprint(&dch->inst, "isac_fill_fifo dbusytimer running");
+		del_timer(&dch->timer);
+	}
+	init_timer(&dch->timer);
+	dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+	add_timer(&dch->timer);
+	if (dch->debug & L1_DEB_ISAC_FIFO) {
+		char *t = dch->log;
+
+		t += sprintf(t, "isac_fill_fifo cnt %d", count);
+		mISDN_QuickHex(t, ptr, count);
+		mISDN_debugprint(&dch->inst, dch->log);
+	}
+}
+
+static void
+isac_rme_irq(channel_t *dch)
+{
+	u_char	val;
+	u_int	count;
+
+	val = dch->read_reg(dch->inst.privat, ISAC_RSTA);
+	if ((val & 0x70) != 0x20) {
+		if (val & 0x40) {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "ISAC RDO");
+#ifdef ERROR_STATISTIC
+			dch->err_rx++;
+#endif
+		}
+		if (!(val & 0x20)) {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "ISAC CRC error");
+#ifdef ERROR_STATISTIC
+			dch->err_crc++;
+#endif
+		}
+		dch->write_reg(dch->inst.privat, ISAC_CMDR, 0x80);
+		if (dch->rx_skb)
+			dev_kfree_skb(dch->rx_skb);
+	} else {
+		count = dch->read_reg(dch->inst.privat, ISAC_RBCL) & 0x1f;
+		if (count == 0)
+			count = 32;
+		isac_empty_fifo(dch, count);
+		if (dch->rx_skb)
+			if (unlikely(mISDN_queueup_newhead(&dch->inst, 0, PH_DATA_IND, MISDN_ID_ANY, dch->rx_skb))) {
+				int_error();
+				dev_kfree_skb(dch->rx_skb);
+			}
+	}
+	dch->rx_skb = NULL;
+}
+
+static void
+isac_xpr_irq(channel_t *dch)
+{
+	if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+		del_timer(&dch->timer);
+	if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len) {
+		isac_fill_fifo(dch);
+	} else {
+		if (dch->tx_skb)
+			dev_kfree_skb(dch->tx_skb);
+		if (test_bit(FLG_TX_NEXT, &dch->Flags)) {
+			dch->tx_skb = dch->next_skb;
+			if (dch->tx_skb) {
+				mISDN_head_t	*hh = mISDN_HEAD_P(dch->tx_skb);
+
+				dch->next_skb = NULL;
+				test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+				dch->tx_idx = 0;
+				queue_ch_frame(dch, CONFIRM, hh->dinfo, NULL);
+				isac_fill_fifo(dch);
+			} else {
+				printk(KERN_WARNING "isac tx irq TX_NEXT without skb\n");
+				test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+				test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+			}
+		} else {
+			dch->tx_skb = NULL;
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+		}
+	}
+}
+
+static void
+isac_retransmit(channel_t *dch)
+{
+	if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+		del_timer(&dch->timer);
+	if (test_bit(FLG_TX_BUSY, &dch->Flags)) {
+		/* Restart frame */
+		dch->tx_idx = 0;
+		isac_fill_fifo(dch);
+	} else if (dch->tx_skb) { /* should not happen */
+		int_error();
+		test_and_set_bit(FLG_TX_BUSY, &dch->Flags);
+		dch->tx_idx = 0;
+		isac_fill_fifo(dch);
+	} else {
+		printk(KERN_WARNING "mISDN: ISAC XDU no TX_BUSY\n");
+		mISDN_debugprint(&dch->inst, "ISAC XDU no TX_BUSY");
+		if (test_bit(FLG_TX_NEXT, &dch->Flags)) {
+			dch->tx_skb = dch->next_skb;
+			if (dch->tx_skb) {
+				mISDN_head_t	*hh = mISDN_HEAD_P(dch->next_skb);
+
+				dch->next_skb = NULL;
+				test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+				dch->tx_idx = 0;
+				queue_ch_frame(dch, CONFIRM, hh->dinfo, NULL);
+				isac_fill_fifo(dch);
+			} else {
+				printk(KERN_WARNING "isac xdu irq TX_NEXT without skb\n");
+				test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+			}
+		}
+	}
+}
+
+static void
+isac_mos_irq(channel_t *dch)
+{
+	u_char		val;
+	isac_chip_t	*isac = dch->hw;
+
+	val = dch->read_reg(dch->inst.privat, ISAC_MOSR);
+	if (dch->debug & L1_DEB_MONITOR)
+		mISDN_debugprint(&dch->inst, "ISAC MOSR %02x", val);
+#if ARCOFI_USE
+	if (val & 0x08) {
+		if (!isac->mon_rx) {
+			if (!(isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+				if (dch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&dch->inst, "ISAC MON RX out of memory!");
+				isac->mocr &= 0xf0;
+				isac->mocr |= 0x0a;
+				dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+				goto afterMONR0;
+			} else
+				isac->mon_rxp = 0;
+		}
+		if (isac->mon_rxp >= MAX_MON_FRAME) {
+			isac->mocr &= 0xf0;
+			isac->mocr |= 0x0a;
+			dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+			isac->mon_rxp = 0;
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "ISAC MON RX overflow!");
+			goto afterMONR0;
+		}
+		isac->mon_rx[isac->mon_rxp++] = dch->read_reg(dch->inst.privat, ISAC_MOR0);
+		if (dch->debug & L1_DEB_MONITOR)
+			mISDN_debugprint(&dch->inst, "ISAC MOR0 %02x", isac->mon_rx[isac->mon_rxp -1]);
+		if (isac->mon_rxp == 1) {
+			isac->mocr |= 0x04;
+			dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+		}
+	}
+afterMONR0:
+	if (val & 0x80) {
+		if (!isac->mon_rx) {
+			if (!(isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+				if (dch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&dch->inst, "ISAC MON RX out of memory!");
+				isac->mocr &= 0x0f;
+				isac->mocr |= 0xa0;
+				dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+				goto afterMONR1;
+			} else
+				isac->mon_rxp = 0;
+		}
+		if (isac->mon_rxp >= MAX_MON_FRAME) {
+			isac->mocr &= 0x0f;
+			isac->mocr |= 0xa0;
+			dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+			isac->mon_rxp = 0;
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "ISAC MON RX overflow!");
+			goto afterMONR1;
+		}
+		isac->mon_rx[isac->mon_rxp++] = dch->read_reg(dch->inst.privat, ISAC_MOR1);
+		if (dch->debug & L1_DEB_MONITOR)
+			mISDN_debugprint(&dch->inst, "ISAC MOR1 %02x", isac->mon_rx[isac->mon_rxp -1]);
+		isac->mocr |= 0x40;
+		dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+	}
+afterMONR1:
+	if (val & 0x04) {
+		isac->mocr &= 0xf0;
+		dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+		isac->mocr |= 0x0a;
+		dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+		mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION, D_RX_MON0,
+			isac->mon_rxp, isac->mon_rx, 0);
+	}
+	if (val & 0x40) {
+		isac->mocr &= 0x0f;
+		dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+		isac->mocr |= 0xa0;
+		dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+		mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION, D_RX_MON1,
+			isac->mon_rxp, isac->mon_rx, 0);
+	}
+	if (val & 0x02) {
+		if ((!isac->mon_tx) || (isac->mon_txc && 
+			(isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) {
+			isac->mocr &= 0xf0;
+			dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+			isac->mocr |= 0x0a;
+			dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+			if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc))
+				mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION,
+					D_TX_MON0, 0, NULL, 0);
+			goto AfterMOX0;
+		}
+		if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
+			mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION,
+				D_TX_MON0, 0, NULL, 0);
+			goto AfterMOX0;
+		}
+		dch->write_reg(dch->inst.privat, ISAC_MOX0,
+		isac->mon_tx[isac->mon_txp++]);
+		if (dch->debug & L1_DEB_MONITOR)
+			mISDN_debugprint(&dch->inst, "ISAC %02x -> MOX0", isac->mon_tx[isac->mon_txp -1]);
+	}
+AfterMOX0:
+	if (val & 0x20) {
+		if ((!isac->mon_tx) || (isac->mon_txc && 
+			(isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) {
+			isac->mocr &= 0x0f;
+			dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+			isac->mocr |= 0xa0;
+			dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
+			if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc))
+				mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION,
+					D_TX_MON1, 0, NULL, 0);
+			goto AfterMOX1;
+		}
+		if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
+			mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION,
+				D_TX_MON1, 0, NULL, 0);
+			goto AfterMOX1;
+		}
+		dch->write_reg(dch->inst.privat, ISAC_MOX1,
+		isac->mon_tx[isac->mon_txp++]);
+		if (dch->debug & L1_DEB_MONITOR)
+			mISDN_debugprint(&dch->inst, "ISAC %02x -> MOX1", isac->mon_tx[isac->mon_txp -1]);
+	}
+AfterMOX1:
+	val = 0; /* dummy to avoid warning */
+#endif
+}
+
+static void
+isac_cisq_irq(channel_t *dch) {
+	unsigned char val;
+
+	val = dch->read_reg(dch->inst.privat, ISAC_CIR0);
+	if (dch->debug & L1_DEB_ISAC)
+		mISDN_debugprint(&dch->inst, "ISAC CIR0 %02X", val);
+	if (val & 2) {
+		if (dch->debug & L1_DEB_ISAC)
+			mISDN_debugprint(&dch->inst, "ph_state change %x->%x",
+				dch->state, (val >> 2) & 0xf);
+		dch->state = (val >> 2) & 0xf;
+		isac_ph_state_change(dch);
+	}
+	if (val & 1) {
+		val = dch->read_reg(dch->inst.privat, ISAC_CIR1);
+		if (dch->debug & L1_DEB_ISAC)
+			mISDN_debugprint(&dch->inst, "ISAC CIR1 %02X", val );
+	}
+}
+
+static void
+isacsx_cic_irq(channel_t *dch)
+{
+	unsigned char val;
+
+	val = dch->read_reg(dch->inst.privat, ISACSX_CIR0);
+	if (dch->debug & L1_DEB_ISAC)
+		mISDN_debugprint(&dch->inst, "ISACSX CIR0 %02X", val);
+	if (val & ISACSX_CIR0_CIC0) {
+		if (dch->debug & L1_DEB_ISAC)
+			mISDN_debugprint(&dch->inst, "ph_state change %x->%x",
+				dch->state, val >> 4);
+		dch->state = val >> 4;
+		isac_ph_state_change(dch);
+	}
+}
+
+static void
+isacsx_rme_irq(channel_t *dch)
+{
+	int count;
+	unsigned char val;
+
+	val = dch->read_reg(dch->inst.privat, ISACSX_RSTAD);
+	if ((val & (ISACSX_RSTAD_VFR | 
+		    ISACSX_RSTAD_RDO | 
+		    ISACSX_RSTAD_CRC | 
+		    ISACSX_RSTAD_RAB)) 
+	    != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
+	    	if (dch->debug & L1_DEB_WARN)
+	    		mISDN_debugprint(&dch->inst, "RSTAD %#x, dropped", val);
+#ifdef ERROR_STATISTIC
+		if (val & ISACSX_RSTAD_CRC)
+			dch->err_rx++;
+		else
+			dch->err_crc++;
+#endif
+	    	dch->write_reg(dch->inst.privat, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
+		if (dch->rx_skb)
+			dev_kfree_skb(dch->rx_skb);
+	} else {
+		count = dch->read_reg(dch->inst.privat, ISACSX_RBCLD) & 0x1f;
+		if (count == 0)
+			count = 32;
+		isac_empty_fifo(dch, count);
+		if (dch->rx_skb) {
+			skb_trim(dch->rx_skb, dch->rx_skb->len - 1);
+			if (unlikely(mISDN_queueup_newhead(&dch->inst, 0, PH_DATA_IND, MISDN_ID_ANY, dch->rx_skb))) {
+				int_error();
+				dev_kfree_skb(dch->rx_skb);
+			}
+		}
+	}
+	dch->rx_skb = NULL;
+}
+
+void
+mISDN_isac_interrupt(channel_t *dch, u_char val)
+{
+	if (dch->debug & L1_DEB_ISAC)
+		mISDN_debugprint(&dch->inst, "ISAC interrupt %02x", val);
+	if (dch->type & ISAC_TYPE_ISACSX) {
+		if (val & ISACSX_ISTA_CIC)
+			isacsx_cic_irq(dch);
+		if (val & ISACSX_ISTA_ICD) {
+			val = dch->read_reg(dch->inst.privat, ISACSX_ISTAD);
+			if (dch->debug & L1_DEB_ISAC)
+				mISDN_debugprint(&dch->inst, "ISTAD %02x", val);
+			if (val & ISACSX_ISTAD_XDU) {
+				if (dch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&dch->inst, "ISAC XDU");
+#ifdef ERROR_STATISTIC
+				dch->err_tx++;
+#endif
+				isac_retransmit(dch);
+			}
+			if (val & ISACSX_ISTAD_XMR) {
+				if (dch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&dch->inst, "ISAC XMR");
+#ifdef ERROR_STATISTIC
+				dch->err_tx++;
+#endif
+				isac_retransmit(dch);
+			}
+			if (val & ISACSX_ISTAD_XPR)
+				isac_xpr_irq(dch);
+			if (val & ISACSX_ISTAD_RFO) {
+				if (dch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&dch->inst, "ISAC RFO");
+				dch->write_reg(dch->inst.privat, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
+			}
+			if (val & ISACSX_ISTAD_RME)
+				isacsx_rme_irq(dch);
+			if (val & ISACSX_ISTAD_RPF)
+				isac_empty_fifo(dch, 0x20);
+		}
+	} else {
+		if (val & 0x80)	/* RME */
+			isac_rme_irq(dch);
+		if (val & 0x40)	/* RPF */
+			isac_empty_fifo(dch, 32);
+		if (val & 0x10)	/* XPR */
+			isac_xpr_irq(dch);
+		if (val & 0x04)	/* CISQ */
+			isac_cisq_irq(dch);
+		if (val & 0x20)	/* RSC - never */
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "ISAC RSC interrupt");
+		if (val & 0x02)	/* SIN - never */
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "ISAC SIN interrupt");
+		if (val & 0x01) {	/* EXI */
+			val = dch->read_reg(dch->inst.privat, ISAC_EXIR);
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "ISAC EXIR %02x", val);
+			if (val & 0x80)	/* XMR */
+				mISDN_debugprint(&dch->inst, "ISAC XMR");
+			if (val & 0x40) { /* XDU */
+				if (dch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&dch->inst, "ISAC XDU");
+#ifdef ERROR_STATISTIC
+				dch->err_tx++;
+#endif
+				isac_retransmit(dch);
+			}
+			if (val & 0x04)	/* MOS */
+				isac_mos_irq(dch);
+		}
+	}
+}
+
+int
+mISDN_ISAC_l1hw(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*dch;
+	int		ret = 0;
+	mISDN_head_t	*hh;
+	u_long		flags;
+
+	hh = mISDN_HEAD_P(skb);
+	dch = container_of(inst, channel_t, inst);
+	if (hh->prim == PH_DATA_REQ) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		ret = channel_senddata(dch, hh->dinfo, skb);
+		if (ret > 0) { /* direct TX */
+			isac_fill_fifo(dch);
+			ret = 0;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		return(ret);
+	} else if (hh->prim == (PH_SIGNAL | REQUEST)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		if (hh->dinfo == INFO3_P8)
+			ph_command(dch, ISAC_CMD_AR8);
+		else if (hh->dinfo == INFO3_P10)
+			ph_command(dch, ISAC_CMD_AR10);
+		else
+			ret = -EINVAL;
+		spin_unlock_irqrestore(inst->hwlock, flags);
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		if (hh->dinfo == HW_RESET) {
+			if ((dch->state == ISAC_IND_EI) ||
+				(dch->state == ISAC_IND_DR) ||
+				(dch->state == ISAC_IND_RS))
+			        ph_command(dch, ISAC_CMD_TIM);
+			else
+				ph_command(dch, ISAC_CMD_RS);
+		} else if (hh->dinfo == HW_POWERUP) {
+			ph_command(dch, ISAC_CMD_TIM);
+		} else if (hh->dinfo == HW_DEACTIVATE) {
+			if (dch->next_skb) {
+				dev_kfree_skb(dch->next_skb);
+				dch->next_skb = NULL;
+			}
+			test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+			if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+				del_timer(&dch->timer);
+		} else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) {
+			u_char		tl;
+			if (dch->type & ISAC_TYPE_ISACSX) {
+			/* TODO */
+			} else {
+				tl = 0;
+				if (1 & hh->dinfo)
+					tl |= 0x0c;
+				if (2 & hh->dinfo)
+					tl |= 0x3;
+				if (ISAC_TYPE_IOM1 & dch->type) {
+					/* IOM 1 Mode */
+					if (!tl) {
+						dch->write_reg(dch->inst.privat, ISAC_SPCR, 0xa);
+						dch->write_reg(dch->inst.privat, ISAC_ADF1, 0x2);
+					} else {
+						dch->write_reg(dch->inst.privat, ISAC_SPCR, tl);
+						dch->write_reg(dch->inst.privat, ISAC_ADF1, 0xa);
+					}
+				} else {
+					/* IOM 2 Mode */
+					dch->write_reg(dch->inst.privat, ISAC_SPCR, tl);
+					if (tl)
+						dch->write_reg(dch->inst.privat, ISAC_ADF1, 0x8);
+					else
+						dch->write_reg(dch->inst.privat, ISAC_ADF1, 0x0);
+				}
+			}
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "isac_l1hw unknown ctrl %x",
+					hh->dinfo);
+			ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+	} else if (hh->prim == (PH_SIGNAL | INDICATION)) {
+#if ARCOFI_USE
+		if ((ISAC_TYPE_ARCOFI & dch->type)) {
+			if (hh->dinfo == D_RX_MON1) {
+				arcofi_fsm(dch, ARCOFI_RX_END, skb);
+			} else if (hh->dinfo == D_TX_MON1) {
+				arcofi_fsm(dch, ARCOFI_TX_END, NULL);
+			}
+		}
+#endif
+		ret = 0;
+	} else if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS)
+		ret = -EAGAIN;
+	else {
+		if (dch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&dch->inst, "isac_l1hw unknown prim %x",
+				hh->prim);
+		ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+void 
+mISDN_isac_free(channel_t *dch) {
+	isac_chip_t     *isac = dch->hw;
+
+	if (dch->timer.function != NULL) {
+		del_timer(&dch->timer);
+		dch->timer.function = NULL;
+	}
+	if (!isac)
+		return;
+	kfree(isac->mon_rx);
+	isac->mon_rx = NULL;
+	kfree(isac->mon_tx);
+	isac->mon_tx = NULL;
+}
+
+static void
+dbusy_timer_handler(channel_t *dch)
+{
+	int	rbch, star;
+	u_long	flags;
+
+	if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) {
+		spin_lock_irqsave(dch->inst.hwlock, flags);
+		rbch = dch->read_reg(dch->inst.privat, ISAC_RBCH);
+		star = dch->read_reg(dch->inst.privat, ISAC_STAR);
+		if (dch->debug) 
+			mISDN_debugprint(&dch->inst, "D-Channel Busy RBCH %02x STAR %02x",
+				rbch, star);
+		if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */
+			test_and_set_bit(FLG_L1_BUSY, &dch->Flags);
+		} else {
+			/* discard frame; reset transceiver */
+			test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags);
+			if (dch->tx_idx) {
+				dch->tx_idx = 0;
+			} else {
+				printk(KERN_WARNING "mISDN: ISAC D-Channel Busy no tx_idx\n");
+				mISDN_debugprint(&dch->inst, "D-Channel Busy no tx_idx");
+			}
+			/* Transmitter reset */
+			dch->write_reg(dch->inst.privat, ISAC_CMDR, 0x01);
+		}
+		spin_unlock_irqrestore(dch->inst.hwlock, flags);
+	}
+}
+
+static char *ISACVer[] =
+{"2086/2186 V1.1", "2085 B1", "2085 B2",
+ "2085 V2.3"};
+
+int
+mISDN_isac_init(channel_t *dch)
+{
+	isac_chip_t	*isac = dch->hw;
+	u_char		val;
+
+
+  	if (!isac)
+  		return(-EINVAL);
+	isac->mon_tx = NULL;
+	isac->mon_rx = NULL;
+	dch->timer.function = (void *) dbusy_timer_handler;
+	dch->timer.data = (long) dch;
+	init_timer(&dch->timer);
+  	isac->mocr = 0xaa;
+	if (dch->type & ISAC_TYPE_ISACSX) {
+		// clear LDD
+		dch->write_reg(dch->inst.privat, ISACSX_TR_CONF0, 0x00);
+		// enable transmitter
+		dch->write_reg(dch->inst.privat, ISACSX_TR_CONF2, 0x00);
+		// transparent mode 0, RAC, stop/go
+		dch->write_reg(dch->inst.privat, ISACSX_MODED, 0xc9);
+		// all HDLC IRQ unmasked
+		dch->write_reg(dch->inst.privat, ISACSX_MASKD, 0x03);
+		// unmask ICD, CID IRQs
+		dch->write_reg(dch->inst.privat, ISACSX_MASK, ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
+		printk(KERN_INFO "mISDN_isac_init: ISACSX\n");
+		isac_ph_state_change(dch);		
+		ph_command(dch, ISAC_CMD_RS);
+	} else { /* old isac */
+	  	dch->write_reg(dch->inst.privat, ISAC_MASK, 0xff);
+		val = dch->read_reg(dch->inst.privat, ISAC_RBCH);
+		printk(KERN_INFO "mISDN_isac_init: ISAC version (%x): %s\n", val, ISACVer[(val >> 5) & 3]);
+		dch->type |= ((val >> 5) & 3);
+		if (ISAC_TYPE_IOM1 & dch->type) {
+			/* IOM 1 Mode */
+			dch->write_reg(dch->inst.privat, ISAC_ADF2, 0x0);
+			dch->write_reg(dch->inst.privat, ISAC_SPCR, 0xa);
+			dch->write_reg(dch->inst.privat, ISAC_ADF1, 0x2);
+			dch->write_reg(dch->inst.privat, ISAC_STCR, 0x70);
+			dch->write_reg(dch->inst.privat, ISAC_MODE, 0xc9);
+		} else {
+			/* IOM 2 Mode */
+			if (!isac->adf2)
+				isac->adf2 = 0x80;
+			dch->write_reg(dch->inst.privat, ISAC_ADF2, isac->adf2);
+			dch->write_reg(dch->inst.privat, ISAC_SQXR, 0x2f);
+			dch->write_reg(dch->inst.privat, ISAC_SPCR, 0x00);
+			dch->write_reg(dch->inst.privat, ISAC_STCR, 0x70);
+			dch->write_reg(dch->inst.privat, ISAC_MODE, 0xc9);
+			dch->write_reg(dch->inst.privat, ISAC_TIMR, 0x00);
+			dch->write_reg(dch->inst.privat, ISAC_ADF1, 0x00);
+		}
+		isac_ph_state_change(dch);
+		ph_command(dch, ISAC_CMD_RS);
+		dch->write_reg(dch->inst.privat, ISAC_MASK, 0x0);
+	}
+	return 0;
+}
+
+void
+mISDN_clear_isac(channel_t *dch)
+{
+	isac_chip_t	*isac = dch->hw;
+	u_int		val, eval;
+
+	if (!isac)
+		return;
+	/* Disable all IRQ */
+	dch->write_reg(dch->inst.privat, ISAC_MASK, 0xFF);
+	val = dch->read_reg(dch->inst.privat, ISAC_STAR);
+	mISDN_debugprint(&dch->inst, "ISAC STAR %x", val);
+	val = dch->read_reg(dch->inst.privat, ISAC_MODE);
+	mISDN_debugprint(&dch->inst, "ISAC MODE %x", val);
+	val = dch->read_reg(dch->inst.privat, ISAC_ADF2);
+	mISDN_debugprint(&dch->inst, "ISAC ADF2 %x", val);
+	val = dch->read_reg(dch->inst.privat, ISAC_ISTA);
+	mISDN_debugprint(&dch->inst, "ISAC ISTA %x", val);
+	if (val & 0x01) {
+		eval = dch->read_reg(dch->inst.privat, ISAC_EXIR);
+		mISDN_debugprint(&dch->inst, "ISAC EXIR %x", eval);
+	}
+	val = dch->read_reg(dch->inst.privat, ISAC_CIR0);
+	mISDN_debugprint(&dch->inst, "ISAC CIR0 %x", val);
+	dch->state = (val >> 2) & 0xf;
+}
+
+#ifdef MODULE
+static int isac_mod_init(void)
+{
+	printk(KERN_INFO "ISAC module %s\n", isac_revision);
+	mISDN_module_register(THIS_MODULE);
+	return(0);
+}
+
+static void isac_mod_cleanup(void)
+{
+	mISDN_module_unregister(THIS_MODULE);
+	printk(KERN_INFO "ISAC module unloaded\n");
+}
+module_init(isac_mod_init);
+module_exit(isac_mod_cleanup);
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isac.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isac.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isac.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,136 @@
+/* $Id: isac.h,v 1.5 2006/03/06 12:52:07 keil Exp $
+ *
+ * isac.h   ISAC specific defines
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+/* privat isac data */
+
+typedef struct isac_chip {
+	u_char			*mon_tx;
+	u_char			*mon_rx;
+	int			mon_txp;
+	int			mon_txc;
+	int			mon_rxp;
+	struct arcofi_msg	*arcofi_list;
+	struct timer_list	arcofitimer;
+	wait_queue_head_t	arcofi_wait;
+	u_char			arcofi_bc;
+	u_char			arcofi_state;
+	u_char			mocr;
+	u_char			adf2;
+} isac_chip_t;
+
+#define ISAC_TYPE_ISAC		0x0010
+#define ISAC_TYPE_IPAC		0x0020
+#define ISAC_TYPE_ISACSX	0x0040
+#define ISAC_TYPE_IPACSX	0x0080
+#define ISAC_TYPE_IOM1		0x0100
+#define ISAC_TYPE_ARCOFI	0x1000
+
+
+/* All Registers original Siemens Spec  */
+
+#define ISAC_MASK 0x20
+#define ISAC_ISTA 0x20
+#define ISAC_STAR 0x21
+#define ISAC_CMDR 0x21
+#define ISAC_EXIR 0x24
+#define ISAC_ADF2 0x39
+#define ISAC_SPCR 0x30
+#define ISAC_ADF1 0x38
+#define ISAC_CIR0 0x31
+#define ISAC_CIX0 0x31
+#define ISAC_CIR1 0x33
+#define ISAC_CIX1 0x33
+#define ISAC_STCR 0x37
+#define ISAC_MODE 0x22
+#define ISAC_RSTA 0x27
+#define ISAC_RBCL 0x25
+#define ISAC_RBCH 0x2A
+#define ISAC_TIMR 0x23
+#define ISAC_SQXR 0x3b
+#define ISAC_MOSR 0x3a
+#define ISAC_MOCR 0x3a
+#define ISAC_MOR0 0x32
+#define ISAC_MOX0 0x32
+#define ISAC_MOR1 0x34
+#define ISAC_MOX1 0x34
+
+#define ISAC_RBCH_XAC 0x80
+
+#define ISAC_CMD_TIM	0x0
+#define ISAC_CMD_RS	0x1
+#define ISAC_CMD_SCZ	0x4
+#define ISAC_CMD_SSZ	0x2
+#define ISAC_CMD_AR8	0x8
+#define ISAC_CMD_AR10	0x9
+#define ISAC_CMD_ARL	0xA
+#define ISAC_CMD_DUI	0xF
+
+#define ISAC_IND_RS	0x1
+#define ISAC_IND_PU	0x7
+#define ISAC_IND_DR	0x0
+#define ISAC_IND_SD	0x2
+#define ISAC_IND_DIS	0x3
+#define ISAC_IND_EI	0x6
+#define ISAC_IND_RSY	0x4
+#define ISAC_IND_ARD	0x8
+#define ISAC_IND_TI	0xA
+#define ISAC_IND_ATI	0xB
+#define ISAC_IND_AI8	0xC
+#define ISAC_IND_AI10	0xD
+#define ISAC_IND_DID	0xF
+
+/* the new ISACX */
+#define ISACSX_MASK       0x60
+#define ISACSX_ISTA       0x60
+#define ISACSX_ISTA_ICD   0x01
+#define ISACSX_ISTA_CIC   0x10
+
+#define ISACSX_MASKD      0x20
+#define ISACSX_ISTAD      0x20
+#define ISACSX_ISTAD_XDU  0x04
+#define ISACSX_ISTAD_XMR  0x08
+#define ISACSX_ISTAD_XPR  0x10
+#define ISACSX_ISTAD_RFO  0x20
+#define ISACSX_ISTAD_RPF  0x40
+#define ISACSX_ISTAD_RME  0x80
+
+#define ISACSX_CMDRD      0x21
+#define ISACSX_CMDRD_XRES 0x01
+#define ISACSX_CMDRD_XME  0x02
+#define ISACSX_CMDRD_XTF  0x08
+#define ISACSX_CMDRD_RRES 0x40
+#define ISACSX_CMDRD_RMC  0x80
+
+#define ISACSX_MODED      0x22
+
+#define ISACSX_RBCLD      0x26
+
+#define ISACSX_RSTAD      0x28
+#define ISACSX_RSTAD_RAB  0x10
+#define ISACSX_RSTAD_CRC  0x20
+#define ISACSX_RSTAD_RDO  0x40
+#define ISACSX_RSTAD_VFR  0x80
+
+#define ISACSX_CIR0       0x2e
+#define ISACSX_CIR0_CIC0  0x08
+#define ISACSX_CIX0       0x2e
+
+#define ISACSX_TR_CONF0   0x30
+
+#define ISACSX_TR_CONF2   0x32
+
+/* interface for the isac module */
+
+extern int mISDN_isac_init(channel_t *);
+extern void mISDN_isac_free(channel_t *);
+
+extern void mISDN_isac_interrupt(channel_t *, u_char);
+extern void mISDN_clear_isac(channel_t *);
+extern int mISDN_ISAC_l1hw(mISDNinstance_t *, struct sk_buff *);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isar.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isar.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isar.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1781 @@
+/* $Id: isar.c,v 1.22 2006/06/27 13:24:07 keil Exp $
+ *
+ * isar.c   ISAR (Siemens PSB 7110) specific routines
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include "layer1.h"
+#include "channel.h"
+#include "isar.h"
+#include "debug.h"
+
+#define DBG_LOADFIRM	0
+#define DUMP_MBOXFRAME	2
+
+#define MIN(a,b) ((a<b)?a:b)
+
+static char *ISAR_revision = "$Revision: 1.22 $";
+
+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(channel_t *);
+static void isar_pump_cmd(channel_t *, int, u_char);
+
+static int firmwaresize = 0;
+static u_char *firmware;
+static u_char *fw_p;
+
+static inline int
+waitforHIA(channel_t *bch, int timeout)
+{
+
+	while ((bch->read_reg(bch->inst.privat, ISAR_HIA) & 1) && timeout) {
+		udelay(1);
+		timeout--;
+	}
+	if (!timeout)
+		printk(KERN_WARNING "mISDN: ISAR waitforHIA timeout\n");
+	return(timeout);
+}
+
+
+int
+sendmsg(channel_t *bch, u_char his, u_char creg, u_char len,
+	u_char *msg)
+{
+	int i;
+	
+	if (!waitforHIA(bch, 4000))
+		return(0);
+#if DUMP_MBOXFRAME
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "sendmsg(%02x,%02x,%d)", his, creg, len);
+#endif
+	bch->write_reg(bch->inst.privat, ISAR_CTRL_H, creg);
+	bch->write_reg(bch->inst.privat, ISAR_CTRL_L, len);
+	bch->write_reg(bch->inst.privat, ISAR_WADR, 0);
+	if (msg && len) {
+		bch->write_fifo(bch->inst.privat, msg, len);
+#if DUMP_MBOXFRAME>1
+		if (bch->debug & L1_DEB_HSCX_FIFO) {
+			char *t;
+			
+			i = len;
+			while (i>0) {
+				t = bch->log;
+				t += sprintf(t, "sendmbox cnt %d", len);
+				mISDN_QuickHex(t, &msg[len-i], (i>64) ? 64:i);
+				mISDN_debugprint(&bch->inst, bch->log);
+				i -= 64;
+			}
+		}
+#endif
+	}
+	bch->write_reg(bch->inst.privat, ISAR_HIS, his);
+	waitforHIA(bch, 10000);
+	return(1);
+}
+
+/* Call only with IRQ disabled !!! */
+inline void
+rcv_mbox(channel_t *bch, isar_reg_t *ireg, u_char *msg)
+{
+	int i;
+
+	bch->write_reg(bch->inst.privat, ISAR_RADR, 0);
+	if (msg && ireg->clsb) {
+		bch->read_fifo(bch->inst.privat, msg, ireg->clsb);
+#if DUMP_MBOXFRAME>1
+		if (bch->debug & L1_DEB_HSCX_FIFO) {
+			char *t;
+			
+			i = ireg->clsb;
+			while (i>0) {
+				t = bch->log;
+				t += sprintf(t, "rcv_mbox cnt %d", ireg->clsb);
+				mISDN_QuickHex(t, &msg[ireg->clsb-i], (i>64) ? 64:i);
+				mISDN_debugprint(&bch->inst, bch->log);
+				i -= 64;
+			}
+		}
+#endif
+	}
+	bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+}
+
+/* Call only with IRQ disabled !!! */
+inline void
+get_irq_infos(channel_t *bch, isar_reg_t *ireg)
+{
+	ireg->iis = bch->read_reg(bch->inst.privat, ISAR_IIS);
+	ireg->cmsb = bch->read_reg(bch->inst.privat, ISAR_CTRL_H);
+	ireg->clsb = bch->read_reg(bch->inst.privat, ISAR_CTRL_L);
+#if DUMP_MBOXFRAME
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "rcv_mbox(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
+			ireg->clsb);
+#endif
+}
+
+int
+waitrecmsg(channel_t *bch, u_char *len,
+	u_char *msg, int maxdelay)
+{
+	int timeout = 0;
+	isar_hw_t *ih = bch->hw;
+	
+	
+	while((!(bch->read_reg(bch->inst.privat, ISAR_IRQBIT) & ISAR_IRQSTA)) &&
+		(timeout++ < maxdelay))
+		udelay(1);
+	if (timeout >= maxdelay) {
+		printk(KERN_WARNING"isar recmsg IRQSTA timeout\n");
+		return(0);
+	}
+	get_irq_infos(bch, ih->reg);
+	rcv_mbox(bch, ih->reg, msg);
+	*len = ih->reg->clsb;
+	return(1);
+}
+
+int
+ISARVersion(channel_t *bch, char *s)
+{
+	int ver;
+	u_char msg[] = ISAR_MSG_HWVER;
+	u_char tmp[64];
+	u_char len;
+	isar_hw_t *ih = bch->hw;
+	int debug;
+
+//	bch->cardmsg(bch->inst.privat, CARD_RESET,  NULL);
+	/* disable ISAR IRQ */
+	bch->write_reg(bch->inst.privat, ISAR_IRQBIT, 0);
+	debug = bch->debug;
+	bch->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
+	if (!sendmsg(bch, ISAR_HIS_VNR, 0, 3, msg))
+		return(-1);
+	if (!waitrecmsg(bch, &len, tmp, 100000))
+		 return(-2);
+	bch->debug = debug;
+	if (ih->reg->iis == ISAR_IIS_VNR) {
+		if (len == 1) {
+			ver = tmp[0] & 0xf;
+			printk(KERN_INFO "%s ISAR version %d\n", s, ver);
+			return(ver);
+		}
+		return(-3);
+	}
+	return(-4);
+}
+
+int
+isar_load_firmware(channel_t *bch, u_char *buf, int size)
+{
+	int		ret, cnt, debug;
+	u_char		len, nom, noc;
+	u_short		sadr, left, *sp;
+	u_char		*p = buf;
+	u_char		*msg, *tmpmsg, *mp, tmp[64];
+	isar_hw_t	*ih = bch->hw;
+	u_long		flags;
+	
+	struct {u_short sadr;
+		u_short len;
+		u_short d_key;
+	} *blk_head;
+		
+	spin_lock_irqsave(bch->inst.hwlock, flags);
+#define	BLK_HEAD_SIZE 6
+	if (1 != (ret = ISARVersion(bch, "Testing"))) {
+		printk(KERN_ERR"isar_load_firmware wrong isar version %d\n", ret);
+		spin_unlock_irqrestore(bch->inst.hwlock, flags);
+		return(1);
+	}
+	debug = bch->debug;
+#if DBG_LOADFIRM<2
+	bch->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
+#endif
+	printk(KERN_DEBUG"isar_load_firmware buf %#lx\n", (u_long)buf);
+	printk(KERN_DEBUG"isar_load_firmware size: %d\n", size);
+	cnt = 0;
+	/* disable ISAR IRQ */
+	bch->write_reg(bch->inst.privat, ISAR_IRQBIT, 0);
+	if (!(msg = kmalloc(256, GFP_ATOMIC))) {
+		printk(KERN_ERR"isar_load_firmware no buffer\n");
+		spin_unlock_irqrestore(bch->inst.hwlock, flags);
+		return (1);
+	}
+	while (cnt < size) {
+		blk_head = (void *)p;
+#ifdef __BIG_ENDIAN
+		sadr = (blk_head->sadr & 0xff)*256 + blk_head->sadr/256;
+		blk_head->sadr = sadr;
+		sadr = (blk_head->len & 0xff)*256 + blk_head->len/256;
+		blk_head->len = sadr;
+		sadr = (blk_head->d_key & 0xff)*256 + blk_head->d_key/256;
+		blk_head->d_key = sadr;
+#endif /* __BIG_ENDIAN */
+		cnt += BLK_HEAD_SIZE;
+		p += BLK_HEAD_SIZE;
+		printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n",
+			blk_head->sadr, blk_head->len, blk_head->d_key & 0xff);
+		sadr = blk_head->sadr;
+		left = blk_head->len;
+		if (cnt+left > size) {
+			printk(KERN_ERR"isar: firmware size error have %d need %d bytes\n",
+				size, cnt+left);
+			ret = 1;goto reterror;
+		}
+		if (!sendmsg(bch, ISAR_HIS_DKEY, blk_head->d_key & 0xff, 0, NULL)) {
+			printk(KERN_ERR"isar sendmsg dkey failed\n");
+			ret = 1;goto reterror;
+		}
+		if (!waitrecmsg(bch, &len, tmp, 100000)) {
+			printk(KERN_ERR"isar waitrecmsg dkey failed\n");
+			ret = 1;goto reterror;
+		}
+		if ((ih->reg->iis != ISAR_IIS_DKEY) || ih->reg->cmsb || len) {
+			printk(KERN_ERR"isar wrong dkey response (%x,%x,%x)\n",
+				ih->reg->iis, ih->reg->cmsb, len);
+			ret = 1;goto reterror;
+		}
+		while (left>0) {
+			noc = MIN(126, left);
+			nom = 2*noc;
+			mp  = msg;
+			*mp++ = sadr / 256;
+			*mp++ = sadr % 256;
+			left -= noc;
+			*mp++ = noc;
+			tmpmsg = p;
+			p += nom;
+			cnt += nom;
+			nom += 3;
+			sp = (u_short *)tmpmsg;
+#if DBG_LOADFIRM
+			printk(KERN_DEBUG"isar: load %3d words at %04x\n",
+				 noc, sadr);
+#endif
+			sadr += noc;
+			while(noc) {
+#ifdef __BIG_ENDIAN
+				*mp++ = *sp % 256;
+				*mp++ = *sp / 256;
+#else
+				*mp++ = *sp / 256;
+				*mp++ = *sp % 256;
+#endif /* __BIG_ENDIAN */
+				sp++;
+				noc--;
+			}
+			if (!sendmsg(bch, ISAR_HIS_FIRM, 0, nom, msg)) {
+				printk(KERN_ERR"isar sendmsg prog failed\n");
+				ret = 1;goto reterror;
+			}
+			if (!waitrecmsg(bch, &len, tmp, 100000)) {
+				printk(KERN_ERR"isar waitrecmsg prog failed\n");
+				ret = 1;goto reterror;
+			}
+			if ((ih->reg->iis != ISAR_IIS_FIRM) || ih->reg->cmsb || len) {
+				printk(KERN_ERR"isar wrong prog response (%x,%x,%x)\n",
+					ih->reg->iis, ih->reg->cmsb, len);
+				ret = 1;goto reterror;
+			}
+		}
+		printk(KERN_DEBUG"isar firmware block %5d words loaded\n",
+			blk_head->len);
+	}
+	/* 10ms delay */
+	cnt = 10;
+	while (cnt--)
+		udelay(1000);
+	msg[0] = 0xff;
+	msg[1] = 0xfe;
+	ih->reg->bstat = 0;
+	if (!sendmsg(bch, ISAR_HIS_STDSP, 0, 2, msg)) {
+		printk(KERN_ERR"isar sendmsg start dsp failed\n");
+		ret = 1;goto reterror;
+	}
+	if (!waitrecmsg(bch, &len, tmp, 100000)) {
+		printk(KERN_ERR"isar waitrecmsg start dsp failed\n");
+		ret = 1;goto reterror;
+	}
+	if ((ih->reg->iis != ISAR_IIS_STDSP) || ih->reg->cmsb || len) {
+		printk(KERN_ERR"isar wrong start dsp response (%x,%x,%x)\n",
+			ih->reg->iis, ih->reg->cmsb, len);
+		ret = 1;goto reterror;
+	} else
+		printk(KERN_DEBUG"isar start dsp success\n");
+	/* NORMAL mode entered */
+	/* Enable IRQs of ISAR */
+	bch->write_reg(bch->inst.privat, ISAR_IRQBIT, ISAR_IRQSTA);
+	spin_unlock_irqrestore(bch->inst.hwlock, flags);
+	cnt = 1000; /* max 1s */
+	while ((!ih->reg->bstat) && cnt) {
+		mdelay(1);
+		cnt--;
+	}
+ 	if (!cnt) {
+		printk(KERN_ERR"isar no general status event received\n");
+		ret = 1;
+		goto reterrflg;
+	} else {
+		printk(KERN_DEBUG"isar general status event %x\n",
+			ih->reg->bstat);
+	}
+	/* 10ms delay */
+	cnt = 10;
+	while (cnt--)
+		mdelay(1);
+	ih->reg->iis = 0;
+	spin_lock_irqsave(bch->inst.hwlock, flags);
+	if (!sendmsg(bch, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) {
+		printk(KERN_ERR"isar sendmsg self tst failed\n");
+		ret = 1;goto reterror;
+	}
+	spin_unlock_irqrestore(bch->inst.hwlock, flags);
+	cnt = 10000; /* max 100 ms */
+	while ((ih->reg->iis != ISAR_IIS_DIAG) && cnt) {
+		udelay(10);
+		cnt--;
+	}
+	mdelay(1);
+	if (!cnt) {
+		printk(KERN_ERR"isar no self tst response\n");
+		ret = 1;goto reterrflg;
+	}
+	if ((ih->reg->cmsb == ISAR_CTRL_STST) && (ih->reg->clsb == 1)
+		&& (ih->reg->par[0] == 0)) {
+		printk(KERN_DEBUG"isar selftest OK\n");
+	} else {
+		printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n",
+			ih->reg->cmsb, ih->reg->clsb, ih->reg->par[0]);
+		ret = 1;goto reterrflg;
+	}
+	spin_lock_irqsave(bch->inst.hwlock, flags);
+	ih->reg->iis = 0;
+	if (!sendmsg(bch, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) {
+		printk(KERN_ERR"isar RQST SVN failed\n");
+		ret = 1;goto reterror;
+	}
+	spin_unlock_irqrestore(bch->inst.hwlock, flags);
+	cnt = 30000; /* max 300 ms */
+	while ((ih->reg->iis != ISAR_IIS_DIAG) && cnt) {
+		udelay(10);
+		cnt--;
+	}
+	mdelay(1);
+	if (!cnt) {
+		printk(KERN_ERR"isar no SVN response\n");
+		ret = 1;goto reterrflg;
+	} else {
+		if ((ih->reg->cmsb == ISAR_CTRL_SWVER) && (ih->reg->clsb == 1))
+			printk(KERN_DEBUG"isar software version %#x\n",
+				ih->reg->par[0]);
+		else {
+			
+			printk(KERN_ERR"isar wrong swver response (%x,%x) cnt(%d)\n",
+				ih->reg->cmsb, ih->reg->clsb, cnt);
+			ret = 1;goto reterrflg;
+		}
+	}
+	bch->debug = debug;
+	spin_lock_irqsave(bch->inst.hwlock, flags);
+	isar_setup(bch);
+	spin_unlock_irqrestore(bch->inst.hwlock, flags);
+	bch->inst.obj->own_ctrl(&bch->inst, MGR_LOADFIRM | CONFIRM, NULL);
+	ret = 0;
+reterrflg:
+	spin_lock_irqsave(bch->inst.hwlock, flags);
+reterror:
+	bch->debug = debug;
+	if (ret)
+		/* disable ISAR IRQ */
+		bch->write_reg(bch->inst.privat, ISAR_IRQBIT, 0);
+	spin_unlock_irqrestore(bch->inst.hwlock, flags);
+	kfree(msg);
+	return(ret);
+}
+
+#ifdef OBSOLETE
+#define B_LL_READY	8
+#define B_LL_NOCARRIER	9
+#define B_LL_CONNECT	10
+#define B_LL_OK		11
+#define B_LL_FCERROR	12
+#define B_TOUCH_TONE	13
+#endif
+
+static inline void
+deliver_status(channel_t *bch, int status)
+{
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "HL->LL FAXIND %x", status);
+	mISDN_queue_data(&bch->inst, FLG_MSG_UP, PH_STATUS | INDICATION, status, 0, NULL, 0);
+}
+
+#ifdef OBSOLETE
+static void
+isar_bh(channel_t *bch)
+{
+	int	tt;
+
+	if (test_and_clear_bit(B_LL_READY, &bch->event))
+		deliver_status(bch, HW_MOD_READY);
+	if (test_and_clear_bit(B_LL_NOCARRIER, &bch->event))
+		deliver_status(bch, HW_MOD_NOCARR);
+	if (test_and_clear_bit(B_LL_CONNECT, &bch->event))
+		deliver_status(bch, HW_MOD_CONNECT);
+	if (test_and_clear_bit(B_LL_OK, &bch->event))
+		deliver_status(bch, HW_MOD_OK);
+	if (test_and_clear_bit(B_LL_FCERROR, &bch->event))
+		deliver_status(bch, HW_MOD_FCERROR);
+	if (test_and_clear_bit(B_TOUCH_TONE, &bch->event)) {
+		tt = bch->conmsg[0] | 0x30;
+		if (tt == 0x3e)
+			tt = '*';
+		else if (tt == 0x3f)
+			tt = '#';
+		else if (tt > '9')
+			tt += 7;
+		tt |= DTMF_TONE_VAL;
+		mISDN_queue_data(&bch->inst, FLG_MSG_UP, PH_CONTROL | INDICATION,
+			0, sizeof(int), &tt, 0);
+	}
+}
+#endif
+
+static inline void
+isar_rcv_frame(channel_t *bch)
+{
+	u_char		*ptr;
+	struct sk_buff	*skb;
+	isar_hw_t	*ih = bch->hw;
+	
+	if (!ih->reg->clsb) {
+		mISDN_debugprint(&bch->inst, "isar zero len frame");
+		bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+		return;
+	}
+	switch (bch->state) {
+	    case ISDN_PID_NONE:
+		mISDN_debugprint(&bch->inst, "isar protocol 0 spurious IIS_RDATA %x/%x/%x",
+			ih->reg->iis, ih->reg->cmsb, ih->reg->clsb);
+		printk(KERN_WARNING"isar protocol 0 spurious IIS_RDATA %x/%x/%x\n",
+			ih->reg->iis, ih->reg->cmsb, ih->reg->clsb);
+		bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+		break;
+	    case ISDN_PID_L1_B_64TRANS:
+	    case ISDN_PID_L2_B_TRANSDTMF:
+	    case ISDN_PID_L1_B_MODEM_ASYNC:
+	    	if (!bch->rx_skb) {
+	    		bch->rx_skb = alloc_stack_skb(ih->reg->clsb, bch->up_headerlen);
+	    		if (unlikely(!bch->rx_skb)) {
+	    			printk(KERN_WARNING "mISDN: skb out of memory\n");
+	    			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+	    			break;
+			}
+		}
+		rcv_mbox(bch, ih->reg, (u_char *)skb_put(bch->rx_skb, ih->reg->clsb));
+		queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, bch->rx_skb);
+		bch->rx_skb = NULL;
+		break;
+	    case ISDN_PID_L1_B_64HDLC:
+	    	if (!bch->rx_skb) {
+	    		bch->rx_skb = alloc_stack_skb(bch->maxlen + 2, bch->up_headerlen);
+	    		if (unlikely(!bch->rx_skb)) {
+	    			printk(KERN_WARNING "mISDN: skb out of memory\n");
+	    			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+	    			break;
+			}
+		}
+		if ((bch->rx_skb->len + ih->reg->clsb) > (bch->maxlen + 2)) {
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "isar_rcv_frame: incoming packet too large");
+			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			skb_trim(bch->rx_skb, 0);
+			break;
+		}
+		if (ih->reg->cmsb & HDLC_ERROR) {
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "isar frame error %x len %d",
+					ih->reg->cmsb, ih->reg->clsb);
+#ifdef ERROR_STATISTIC
+			if (ih->reg->cmsb & HDLC_ERR_RER)
+				bch->err_inv++;
+			if (ih->reg->cmsb & HDLC_ERR_CER)
+				bch->err_crc++;
+#endif
+			skb_trim(bch->rx_skb, 0);
+			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			break;
+		}
+		if (ih->reg->cmsb & HDLC_FSD)
+			skb_trim(bch->rx_skb, 0);
+		ptr = skb_put(bch->rx_skb, ih->reg->clsb);
+		rcv_mbox(bch, ih->reg, ptr);
+		if (ih->reg->cmsb & HDLC_FED) {
+			if (bch->rx_skb->len < 3) { /* last 2 bytes are the FCS */
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "isar frame to short %d",
+						bch->rx_skb->len);
+				skb_trim(bch->rx_skb, 0);
+				break;
+			}
+			skb_trim(bch->rx_skb, bch->rx_skb->len - 2);
+			if (bch->rx_skb->len < MISDN_COPY_SIZE) {
+				skb = alloc_stack_skb(bch->rx_skb->len, bch->up_headerlen);
+				if (skb) {
+					memcpy(skb_put(skb, bch->rx_skb->len),
+						bch->rx_skb->data, bch->rx_skb->len);
+					skb_trim(bch->rx_skb, 0);
+				} else {
+					skb = bch->rx_skb;
+					bch->rx_skb = NULL;
+				}
+			} else {
+				skb = bch->rx_skb;
+				bch->rx_skb = NULL;
+			}
+			queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, skb);
+		}
+		break;
+	case ISDN_PID_L1_B_T30FAX:
+		if (ih->state != STFAX_ACTIV) {
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "isar_rcv_frame: not ACTIV");
+			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			if (bch->rx_skb)
+				skb_trim(bch->rx_skb, 0);
+			break;
+		}
+		if (ih->cmd == PCTRL_CMD_FRM) {
+		    	if (!bch->rx_skb) {
+		    		bch->rx_skb = alloc_stack_skb(ih->reg->clsb, bch->up_headerlen);
+	    			if (unlikely(!bch->rx_skb)) {
+	    				printk(KERN_WARNING "mISDN: skb out of memory\n");
+		    			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+	    				break;
+				}
+			}
+			rcv_mbox(bch, ih->reg, skb_put(bch->rx_skb, ih->reg->clsb));
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "isar_rcv_frame: %d",
+					bch->rx_skb->len);
+			if (ih->reg->cmsb & SART_NMD) { /* ABORT */
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "isar_rcv_frame: no more data");
+				bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+				sendmsg(bch, SET_DPS(ih->dpath) |
+					ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
+					0, NULL);
+				ih->state = STFAX_ESCAPE;
+//				set_skb_flag(skb, DF_NOMOREDATA);
+			}
+			queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, bch->rx_skb);
+			bch->rx_skb = NULL;
+			if (ih->reg->cmsb & SART_NMD)
+				deliver_status(bch, HW_MOD_NOCARR);
+			break;
+		}
+		if (ih->cmd != PCTRL_CMD_FRH) {
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "isar_rcv_frame: unknown fax mode %x",
+					ih->cmd);
+			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			if (bch->rx_skb)
+				skb_trim(bch->rx_skb, 0);
+			break;
+		}
+		/* PCTRL_CMD_FRH */
+	    	if (!bch->rx_skb) {
+	    		bch->rx_skb = alloc_stack_skb(bch->maxlen + 2, bch->up_headerlen);
+	    		if (unlikely(!bch->rx_skb)) {
+	    			printk(KERN_WARNING "mISDN: skb out of memory\n");
+	    			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+	    			break;
+			}
+		}
+		if ((bch->rx_skb->len + ih->reg->clsb) > (bch->maxlen + 2)) {
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "isar_rcv_frame: incoming packet too large");
+			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			skb_trim(bch->rx_skb, 0);
+			break;
+		}  else if (ih->reg->cmsb & HDLC_ERROR) {
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "isar frame error %x len %d",
+					ih->reg->cmsb, ih->reg->clsb);
+			skb_trim(bch->rx_skb, 0);
+			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			break;
+		}
+		if (ih->reg->cmsb & HDLC_FSD)
+			skb_trim(bch->rx_skb, 0);
+		ptr = skb_put(bch->rx_skb, ih->reg->clsb);
+		rcv_mbox(bch, ih->reg, ptr);
+		if (ih->reg->cmsb & HDLC_FED) {
+			if (bch->rx_skb->len < 3) { /* last 2 bytes are the FCS */
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "isar frame to short %d",
+						bch->rx_skb->len);
+				skb_trim(bch->rx_skb, 0);
+				break;
+			}
+			skb_trim(bch->rx_skb, bch->rx_skb->len - 2);
+			if (bch->rx_skb->len < MISDN_COPY_SIZE) {
+				skb = alloc_stack_skb(bch->rx_skb->len, bch->up_headerlen);
+				if (skb) {
+					memcpy(skb_put(skb, bch->rx_skb->len),
+						bch->rx_skb->data, bch->rx_skb->len);
+					skb_trim(bch->rx_skb, 0);
+				} else {
+					skb = bch->rx_skb;
+					bch->rx_skb = NULL;
+				}
+			} else {
+				skb = bch->rx_skb;
+				bch->rx_skb = NULL;
+			}
+			queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, skb);
+		}
+		if (ih->reg->cmsb & SART_NMD) { /* ABORT */
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "isar_rcv_frame: no more data");
+			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			if (bch->rx_skb)
+				skb_trim(bch->rx_skb, 0);
+			sendmsg(bch, SET_DPS(ih->dpath) | ISAR_HIS_PUMPCTRL,
+				PCTRL_CMD_ESC, 0, NULL);
+			ih->state = STFAX_ESCAPE;
+			deliver_status(bch, HW_MOD_NOCARR);
+		}
+		break;
+	default:
+		printk(KERN_ERR"isar_rcv_frame protocol (%x)error\n", bch->state);
+		bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+		break;
+	}
+}
+
+void
+isar_fill_fifo(channel_t *bch)
+{
+	isar_hw_t	*ih = bch->hw;
+	int count;
+	u_char msb;
+	u_char *ptr;
+
+	if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
+		mISDN_debugprint(&bch->inst, "%s", __FUNCTION__);
+	if (!bch->tx_skb)
+		return;
+	count = bch->tx_skb->len - bch->tx_idx;
+	if (count <= 0)
+		return;
+	if (!(ih->reg->bstat &
+		(ih->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2)))
+		return;
+	if (count > ih->mml) {
+		msb = 0;
+		count = ih->mml;
+	} else {
+		msb = HDLC_FED;
+	}
+	ptr = bch->tx_skb->data + bch->tx_idx;
+	if (!bch->tx_idx) {
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst, "frame start");
+		if ((bch->state == ISDN_PID_L1_B_T30FAX) &&
+			(ih->cmd == PCTRL_CMD_FTH)) {
+			if (count > 1) {
+				if ((ptr[0]== 0xff) && (ptr[1] == 0x13)) {
+					/* last frame */
+					test_and_set_bit(FLG_LASTDATA, &bch->Flags);
+					if (bch->debug & L1_DEB_HSCX)
+						mISDN_debugprint(&bch->inst, "set LASTDATA");
+					if (msb == HDLC_FED)
+						test_and_set_bit(FLG_DLEETX, &bch->Flags);
+				}
+			}
+		}
+		msb |= HDLC_FST;
+	}
+	bch->tx_idx += count;
+	switch (bch->state) {
+		case ISDN_PID_NONE:
+			printk(KERN_ERR "%s: wrong protocol 0\n", __FUNCTION__);
+			break;
+		case ISDN_PID_L1_B_64TRANS:
+		case ISDN_PID_L2_B_TRANSDTMF:
+		case ISDN_PID_L1_B_MODEM_ASYNC:
+			sendmsg(bch, SET_DPS(ih->dpath) | ISAR_HIS_SDATA,
+				0, count, ptr);
+			break;
+		case ISDN_PID_L1_B_64HDLC:
+			sendmsg(bch, SET_DPS(ih->dpath) | ISAR_HIS_SDATA,
+				msb, count, ptr);
+			break;
+		case ISDN_PID_L1_B_T30FAX:
+			if (ih->state != STFAX_ACTIV) {
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "%s: not ACTIV",
+						__FUNCTION__);
+			} else if (ih->cmd == PCTRL_CMD_FTH) {
+				sendmsg(bch, SET_DPS(ih->dpath) | ISAR_HIS_SDATA,
+					msb, count, ptr);
+			} else if (ih->cmd == PCTRL_CMD_FTM) {
+				sendmsg(bch, SET_DPS(ih->dpath) | ISAR_HIS_SDATA,
+					0, count, ptr);
+			} else {
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "%s: not FTH/FTM",
+						__FUNCTION__);
+			}
+			break;
+		default:
+			if (bch->debug)
+				mISDN_debugprint(&bch->inst, "%s: protocol(%x) error",
+					__FUNCTION__, bch->state);
+			printk(KERN_ERR "%s: protocol(%x) error\n",
+				__FUNCTION__, bch->state);
+			break;
+	}
+}
+
+inline
+channel_t *sel_bch_isar(channel_t *bch, u_char dpath)
+{
+
+	if ((!dpath) || (dpath == 3))
+		return(NULL);
+	
+	if (((isar_hw_t *)bch[0].hw)->dpath == dpath)
+		return(&bch[0]);
+	if (((isar_hw_t *)bch[1].hw)->dpath == dpath)
+		return(&bch[1]);
+	return(NULL);
+}
+
+inline void
+send_frames(channel_t *bch)
+{
+	isar_hw_t	*ih = bch->hw;
+
+	if (bch->tx_skb && (bch->tx_skb->len > bch->tx_idx)) {
+		isar_fill_fifo(bch);
+	} else {
+		if (bch->state == ISDN_PID_L1_B_T30FAX) {
+			if (ih->cmd == PCTRL_CMD_FTH) {
+				if (test_bit(FLG_LASTDATA, &bch->Flags)) {
+					printk(KERN_WARNING "set NMD_DATA\n");
+					test_and_set_bit(FLG_NMD_DATA, &bch->Flags);
+				}
+			} else if (ih->cmd == PCTRL_CMD_FTM) {
+				if (test_bit(FLG_DLEETX, &bch->Flags)) {
+					test_and_set_bit(FLG_LASTDATA, &bch->Flags);
+					test_and_set_bit(FLG_NMD_DATA, &bch->Flags);
+				}
+			}
+		}
+		if (bch->tx_skb)
+			dev_kfree_skb(bch->tx_skb);
+		bch->tx_idx = 0;
+		if (test_bit(FLG_TX_NEXT, &bch->Flags)) {
+			bch->tx_skb = bch->next_skb;
+			if (bch->tx_skb) {
+				mISDN_head_t	*hh = mISDN_HEAD_P(bch->tx_skb);
+
+				bch->next_skb = NULL;
+				test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+				queue_ch_frame(bch, CONFIRM, hh->dinfo, NULL);
+				isar_fill_fifo(bch);
+			} else {
+				printk(KERN_WARNING "hdlc tx irq TX_NEXT without skb\n");
+				test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+				test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+			}
+		} else {
+			bch->tx_skb = NULL;
+			if (test_and_clear_bit(FLG_DLEETX, &bch->Flags)) {
+				if (test_and_clear_bit(FLG_LASTDATA, &bch->Flags)) {
+					if (test_and_clear_bit(FLG_NMD_DATA, &bch->Flags)) {
+						u_char dummy = 0;
+						sendmsg(bch, SET_DPS(ih->dpath) |
+							ISAR_HIS_SDATA, 0x01, 1, &dummy);
+					}
+					test_and_set_bit(FLG_LL_OK, &bch->Flags);
+				} else {
+					deliver_status(bch, HW_MOD_CONNECT);
+				}
+			}
+			test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+//			bch_sched_event(bch, B_XMTBUFREADY);
+		}
+	}
+}
+
+inline void
+check_send(channel_t *bch, u_char rdm)
+{
+	channel_t *bc;
+	
+	if (rdm & BSTAT_RDM1) {
+		if ((bc = sel_bch_isar(bch, 1))) {
+			if (test_bit(FLG_ACTIVE, &bc->Flags)) {
+				send_frames(bc);
+			}
+		}
+	}
+	if (rdm & BSTAT_RDM2) {
+		if ((bc = sel_bch_isar(bch, 2))) {
+			if (test_bit(FLG_ACTIVE, &bc->Flags)) {
+				send_frames(bc);
+			}
+		}
+	}
+	
+}
+
+const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4",
+			"300", "600", "1200", "2400", "4800", "7200",
+			"9600nt", "9600t", "12000", "14400", "WRONG"};
+const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
+			"Bell103", "V23", "Bell202", "V17", "V29", "V27ter"};
+
+static void
+isar_pump_status_rsp(channel_t *bch, isar_reg_t *ireg) {
+	isar_hw_t	*ih = bch->hw;
+	u_char ril = ireg->par[0];
+	u_char rim;
+
+	if (!test_and_clear_bit(ISAR_RATE_REQ, &ireg->Flags))
+		return;
+	if (ril > 14) {
+		if (bch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&bch->inst, "wrong pstrsp ril=%d",ril);
+		ril = 15;
+	}
+	switch(ireg->par[1]) {
+		case 0:
+			rim = 0;
+			break;
+		case 0x20:
+			rim = 2;
+			break;
+		case 0x40:
+			rim = 3;
+			break;
+		case 0x41:
+			rim = 4;
+			break;
+		case 0x51:
+			rim = 5;
+			break;
+		case 0x61:
+			rim = 6;
+			break;
+		case 0x71:
+			rim = 7;
+			break;
+		case 0x82:
+			rim = 8;
+			break;
+		case 0x92:
+			rim = 9;
+			break;
+		case 0xa2:
+			rim = 10;
+			break;
+		default:
+			rim = 1;
+			break;
+	}
+	sprintf(ih->conmsg,"%s %s", dmril[ril], dmrim[rim]);
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "pump strsp %s %s", ih->conmsg);
+}
+
+static void
+isar_pump_statev_modem(channel_t *bch, u_char devt) {
+	isar_hw_t	*ih = bch->hw;
+	u_char dps = SET_DPS(ih->dpath);
+
+	switch(devt) {
+		case PSEV_10MS_TIMER:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev TIMER");
+			break;
+		case PSEV_CON_ON:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev CONNECT");
+			deliver_status(bch, HW_MOD_CONNECT);
+			break;
+		case PSEV_CON_OFF:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev NO CONNECT");
+			sendmsg(bch, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+			deliver_status(bch, HW_MOD_NOCARR);
+			break;
+		case PSEV_V24_OFF:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev V24 OFF");
+			break;
+		case PSEV_CTS_ON:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev CTS ON");
+			break;
+		case PSEV_CTS_OFF:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev CTS OFF");
+			break;
+		case PSEV_DCD_ON:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev CARRIER ON");
+			test_and_set_bit(ISAR_RATE_REQ, &ih->reg->Flags);
+			sendmsg(bch, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+			break;
+		case PSEV_DCD_OFF:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev CARRIER OFF");
+			break;
+		case PSEV_DSR_ON:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev DSR ON");
+			break;
+		case PSEV_DSR_OFF:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev DSR_OFF");
+			break;
+		case PSEV_REM_RET:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev REMOTE RETRAIN");
+			break;
+		case PSEV_REM_REN:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev REMOTE RENEGOTIATE");
+			break;
+		case PSEV_GSTN_CLR:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev GSTN CLEAR", devt);
+			break;
+		default:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "unknown pump stev %x", devt);
+			break;
+	}
+}
+
+static void
+isar_pump_statev_fax(channel_t *bch, u_char devt) {
+	isar_hw_t	*ih = bch->hw;
+	u_char dps = SET_DPS(ih->dpath);
+	u_char p1;
+
+	switch(devt) {
+		case PSEV_10MS_TIMER:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev TIMER");
+			break;
+		case PSEV_RSP_READY:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev RSP_READY");
+			ih->state = STFAX_READY;
+			deliver_status(bch, HW_MOD_READY);
+//			if (test_bit(BC_FLG_ORIG, &bch->Flags)) {
+//				isar_pump_cmd(bch, HW_MOD_FRH, 3);
+//			} else {
+//				isar_pump_cmd(bch, HW_MOD_FTH, 3);
+//			}
+			break;
+		case PSEV_LINE_TX_H:
+			if (ih->state == STFAX_LINE) {
+				if (bch->debug & L1_DEB_HSCX)
+					mISDN_debugprint(&bch->inst, "pump stev LINE_TX_H");
+				ih->state = STFAX_CONT;
+				sendmsg(bch, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+			} else {
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "pump stev LINE_TX_H wrong st %x",
+						ih->state);
+			}
+			break;
+		case PSEV_LINE_RX_H:
+			if (ih->state == STFAX_LINE) {
+				if (bch->debug & L1_DEB_HSCX)
+					mISDN_debugprint(&bch->inst, "pump stev LINE_RX_H");
+				ih->state = STFAX_CONT;
+				sendmsg(bch, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+			} else {
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "pump stev LINE_RX_H wrong st %x",
+						ih->state);
+			}
+			break;
+		case PSEV_LINE_TX_B:
+			if (ih->state == STFAX_LINE) {
+				if (bch->debug & L1_DEB_HSCX)
+					mISDN_debugprint(&bch->inst, "pump stev LINE_TX_B");
+				ih->state = STFAX_CONT;
+				sendmsg(bch, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+			} else {
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "pump stev LINE_TX_B wrong st %x",
+						ih->state);
+			}
+			break;
+		case PSEV_LINE_RX_B:
+			if (ih->state == STFAX_LINE) {
+				if (bch->debug & L1_DEB_HSCX)
+					mISDN_debugprint(&bch->inst, "pump stev LINE_RX_B");
+				ih->state = STFAX_CONT;
+				sendmsg(bch, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+			} else {
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "pump stev LINE_RX_B wrong st %x",
+						ih->state);
+			}
+			break;
+		case PSEV_RSP_CONN:
+			if (ih->state == STFAX_CONT) {
+				if (bch->debug & L1_DEB_HSCX)
+					mISDN_debugprint(&bch->inst, "pump stev RSP_CONN");
+				ih->state = STFAX_ACTIV;
+				test_and_set_bit(ISAR_RATE_REQ, &ih->reg->Flags);
+				sendmsg(bch, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+				if (ih->cmd == PCTRL_CMD_FTH) {
+					int delay = (ih->mod == 3) ? 1000 : 200;
+					/* 1s (200 ms) Flags before data */
+					if (test_and_set_bit(FLG_FTI_RUN, &bch->Flags))
+						del_timer(&ih->ftimer);
+					ih->ftimer.expires =
+						jiffies + ((delay * HZ)/1000);
+					test_and_set_bit(FLG_LL_CONN,
+						&bch->Flags);
+					add_timer(&ih->ftimer);
+				} else {
+					deliver_status(bch, HW_MOD_CONNECT);
+				}
+			} else {
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "pump stev RSP_CONN wrong st %x",
+						ih->state);
+			}
+			break;
+		case PSEV_FLAGS_DET:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev FLAGS_DET");
+			break;
+		case PSEV_RSP_DISC:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev RSP_DISC state(%d)", ih->state);
+			if (ih->state == STFAX_ESCAPE) {
+				p1 = 5;
+				switch(ih->newcmd) {
+					case 0:
+						ih->state = STFAX_READY;
+						break;
+					case PCTRL_CMD_FTM:
+						p1 = 2;
+					case PCTRL_CMD_FTH:
+						sendmsg(bch, dps | ISAR_HIS_PUMPCTRL,
+							PCTRL_CMD_SILON, 1, &p1);
+						ih->state = STFAX_SILDET;
+						break;
+					case PCTRL_CMD_FRH:
+					case PCTRL_CMD_FRM:
+						p1 = ih->mod = ih->newmod;
+						ih->newmod = 0;
+						ih->cmd = ih->newcmd;
+						ih->newcmd = 0;
+						sendmsg(bch, dps | ISAR_HIS_PUMPCTRL,
+							ih->cmd, 1, &p1);
+						ih->state = STFAX_LINE;
+						ih->try_mod = 3;
+						break;
+					default:
+						if (bch->debug & L1_DEB_HSCX)
+							mISDN_debugprint(&bch->inst, "RSP_DISC unknown newcmd %x", ih->newcmd);
+						break;
+				}
+			} else if (ih->state == STFAX_ACTIV) {
+				if (test_and_clear_bit(FLG_LL_OK, &bch->Flags)) {
+					deliver_status(bch, HW_MOD_OK);
+				} else if (ih->cmd == PCTRL_CMD_FRM) {
+					deliver_status(bch, HW_MOD_NOCARR);
+				} else {
+					deliver_status(bch, HW_MOD_FCERROR);
+				}
+				ih->state = STFAX_READY;
+			} else if (ih->state != STFAX_SILDET) { // ignore in STFAX_SILDET
+				ih->state = STFAX_READY;
+				deliver_status(bch, HW_MOD_FCERROR);
+			}
+			break;
+		case PSEV_RSP_SILDET:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev RSP_SILDET");
+			if (ih->state == STFAX_SILDET) {
+				p1 = ih->mod = ih->newmod;
+				ih->newmod = 0;
+				ih->cmd = ih->newcmd;
+				ih->newcmd = 0;
+				sendmsg(bch, dps | ISAR_HIS_PUMPCTRL,
+					ih->cmd, 1, &p1);
+				ih->state = STFAX_LINE;
+				ih->try_mod = 3;
+			}
+			break;
+		case PSEV_RSP_SILOFF:
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev RSP_SILOFF");
+			break;
+		case PSEV_RSP_FCERR:
+			if (ih->state == STFAX_LINE) {
+				if (bch->debug & L1_DEB_HSCX)
+					mISDN_debugprint(&bch->inst, "pump stev RSP_FCERR try %d",
+						ih->try_mod);
+				if (ih->try_mod--) {
+					sendmsg(bch, dps | ISAR_HIS_PUMPCTRL,
+						ih->cmd, 1,
+						&ih->mod);
+					break;
+				}
+			}
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "pump stev RSP_FCERR");
+			ih->state = STFAX_ESCAPE;
+			sendmsg(bch, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
+			deliver_status(bch, HW_MOD_FCERROR);
+			break;
+		default:
+			break;
+	}
+}
+
+static char debbuf[128];
+
+void
+isar_int_main(channel_t *bch)
+{
+	isar_hw_t	*ih = bch->hw;
+	channel_t *bc;
+
+	get_irq_infos(bch, ih->reg);
+	switch (ih->reg->iis & ISAR_IIS_MSCMSD) {
+		case ISAR_IIS_RDATA:
+			if ((bc = sel_bch_isar(bch, ih->reg->iis >> 6))) {
+				isar_rcv_frame(bc);
+			} else {
+				mISDN_debugprint(&bch->inst, "isar spurious IIS_RDATA %x/%x/%x",
+					ih->reg->iis, ih->reg->cmsb, ih->reg->clsb);
+				bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			}
+			break;
+		case ISAR_IIS_GSTEV:
+			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			ih->reg->bstat |= ih->reg->cmsb;
+			check_send(bch, ih->reg->cmsb);
+			break;
+		case ISAR_IIS_BSTEV:
+#ifdef ERROR_STATISTIC
+			if ((bc = sel_bch_isar(bch, ih->reg->iis >> 6))) {
+				if (ih->reg->cmsb == BSTEV_TBO)
+					bc->err_tx++;
+				if (ih->reg->cmsb == BSTEV_RBO)
+					bc->err_rdo++;
+			}
+#endif
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "Buffer STEV dpath%d msb(%x)",
+					ih->reg->iis>>6, ih->reg->cmsb);
+			bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			break;
+		case ISAR_IIS_PSTEV:
+			if ((bc = sel_bch_isar(bch, ih->reg->iis >> 6))) {
+				rcv_mbox(bc, ih->reg, (u_char *)ih->reg->par);
+				if (bc->state == ISDN_PID_L1_B_MODEM_ASYNC) {
+					isar_pump_statev_modem(bc, ih->reg->cmsb);
+				} else if (bc->state == ISDN_PID_L1_B_T30FAX) {
+					isar_pump_statev_fax(bc, ih->reg->cmsb);
+				} else if (bc->state == ISDN_PID_L2_B_TRANSDTMF) {
+					int	tt;
+					tt = ih->reg->cmsb | 0x30;
+					if (tt == 0x3e)
+						tt = '*';
+					else if (tt == 0x3f)
+						tt = '#';
+					else if (tt > '9')
+						tt += 7;
+					tt |= DTMF_TONE_VAL;
+					mISDN_queue_data(&bch->inst, FLG_MSG_UP, PH_CONTROL | INDICATION,
+						0, sizeof(int), &tt, 0);
+				} else {
+					if (bch->debug & L1_DEB_WARN)
+						mISDN_debugprint(&bch->inst, "isar IIS_PSTEV pmode %d stat %x",
+							bc->state, ih->reg->cmsb);
+				}
+			} else {
+				mISDN_debugprint(&bch->inst, "isar spurious IIS_PSTEV %x/%x/%x",
+					ih->reg->iis, ih->reg->cmsb, ih->reg->clsb);
+				bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			}
+			break;
+		case ISAR_IIS_PSTRSP:
+			if ((bc = sel_bch_isar(bch, ih->reg->iis >> 6))) {
+				rcv_mbox(bc, ih->reg, (u_char *)ih->reg->par);
+				isar_pump_status_rsp(bc, ih->reg);
+			} else {
+				mISDN_debugprint(&bch->inst, "isar spurious IIS_PSTRSP %x/%x/%x",
+					ih->reg->iis, ih->reg->cmsb, ih->reg->clsb);
+				bch->write_reg(bch->inst.privat, ISAR_IIA, 0);
+			}
+			break;
+		case ISAR_IIS_DIAG:
+		case ISAR_IIS_BSTRSP:
+		case ISAR_IIS_IOM2RSP:
+			rcv_mbox(bch, ih->reg, (u_char *)ih->reg->par);
+			if ((bch->debug & (L1_DEB_HSCX | L1_DEB_HSCX_FIFO))
+				== L1_DEB_HSCX) {
+				u_char *tp=debbuf;
+
+				tp += sprintf(debbuf, "msg iis(%x) msb(%x)",
+					ih->reg->iis, ih->reg->cmsb);
+				mISDN_QuickHex(tp, (u_char *)ih->reg->par, ih->reg->clsb);
+				mISDN_debugprint(&bch->inst, debbuf);
+			}
+			break;
+		case ISAR_IIS_INVMSG:
+			rcv_mbox(bch, ih->reg, debbuf);
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "invalid msg his:%x",
+					ih->reg->cmsb);
+			break;
+		default:
+			rcv_mbox(bch, ih->reg, debbuf);
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "unhandled msg iis(%x) ctrl(%x/%x)",
+					ih->reg->iis, ih->reg->cmsb, ih->reg->clsb);
+			break;
+	}
+}
+
+static void
+ftimer_handler(channel_t *bch) {
+	if (bch->debug)
+		mISDN_debugprint(&bch->inst, "ftimer flags %04x",
+			bch->Flags);
+	test_and_clear_bit(FLG_FTI_RUN, &bch->Flags);
+	if (test_and_clear_bit(FLG_LL_CONN, &bch->Flags)) {
+		deliver_status(bch, HW_MOD_CONNECT);
+	}
+}
+
+static void
+setup_pump(channel_t *bch) {
+	isar_hw_t	*ih = bch->hw;
+	u_char dps = SET_DPS(ih->dpath);
+	u_char ctrl, param[6];
+
+	switch (bch->state) {
+		case ISDN_PID_NONE:
+		case ISDN_PID_L1_B_64TRANS:
+		case ISDN_PID_L1_B_64HDLC:
+			sendmsg(bch, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL);
+			break;
+		case ISDN_PID_L2_B_TRANSDTMF:
+			if (test_bit(FLG_DTMFSEND, &bch->Flags)) {
+				param[0] = 5; /* TOA 5 db */
+				sendmsg(bch, dps | ISAR_HIS_PUMPCFG, PMOD_DTMF_TRANS, 1, param);
+			} else {
+				param[0] = 40; /* REL -46 dbm */
+				sendmsg(bch, dps | ISAR_HIS_PUMPCFG, PMOD_DTMF, 1, param);
+			}
+		case ISDN_PID_L1_B_MODEM_ASYNC:
+			ctrl = PMOD_DATAMODEM;
+			if (test_bit(FLG_ORIGIN, &bch->Flags)) {
+				ctrl |= PCTRL_ORIG;
+				param[5] = PV32P6_CTN;
+			} else {
+				param[5] = PV32P6_ATN;
+			}
+			param[0] = 6; /* 6 db */
+			param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
+				   PV32P2_V22C | PV32P2_V21 | PV32P2_BEL;
+			param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
+			param[3] = PV32P4_UT144;
+			param[4] = PV32P5_UT144;
+			sendmsg(bch, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param);
+			break;
+		case ISDN_PID_L1_B_T30FAX:
+			ctrl = PMOD_FAX;
+			if (test_bit(FLG_ORIGIN, &bch->Flags)) {
+				ctrl |= PCTRL_ORIG;
+				param[1] = PFAXP2_CTN;
+			} else {
+				param[1] = PFAXP2_ATN;
+			}
+			param[0] = 6; /* 6 db */
+			sendmsg(bch, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
+			ih->state = STFAX_NULL;
+			ih->newcmd = 0;
+			ih->newmod = 0;
+			test_and_set_bit(FLG_FTI_RUN, &bch->Flags);
+			break;
+	}
+	udelay(1000);
+	sendmsg(bch, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+	udelay(1000);
+}
+
+static void
+setup_sart(channel_t *bch) {
+	isar_hw_t	*ih = bch->hw;
+	u_char dps = SET_DPS(ih->dpath);
+	u_char ctrl, param[2];
+	
+	switch (bch->state) {
+		case ISDN_PID_NONE:
+			sendmsg(bch, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0,
+				NULL);
+			break;
+		case ISDN_PID_L1_B_64TRANS:
+		case ISDN_PID_L2_B_TRANSDTMF:
+			sendmsg(bch, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2,
+				"\0\0");
+			break;
+		case ISDN_PID_L1_B_64HDLC:
+		case ISDN_PID_L1_B_T30FAX:
+			param[0] = 0;
+			sendmsg(bch, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1,
+				param);
+			break;
+		case ISDN_PID_L1_B_MODEM_ASYNC:
+			ctrl = SMODE_V14 | SCTRL_HDMC_BOTH;
+			param[0] = S_P1_CHS_8;
+			param[1] = S_P2_BFT_DEF;
+			sendmsg(bch, dps | ISAR_HIS_SARTCFG, ctrl, 2,
+				param);
+			break;
+	}
+	udelay(1000);
+	sendmsg(bch, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
+	udelay(1000);
+}
+
+static void
+setup_iom2(channel_t *bch) {
+	isar_hw_t	*ih = bch->hw;
+	u_char dps = SET_DPS(ih->dpath);
+	u_char cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD,0,0,0,0};
+	
+	if (bch->channel)
+		msg[1] = msg[3] = 1;
+	switch (bch->state) {
+		case ISDN_PID_NONE:
+			cmsb = 0;
+			/* dummy slot */
+			msg[1] = msg[3] = ih->dpath + 2;
+			break;
+		case ISDN_PID_L1_B_64TRANS:
+		case ISDN_PID_L1_B_64HDLC:
+			break;
+		case ISDN_PID_L1_B_MODEM_ASYNC:
+		case ISDN_PID_L1_B_T30FAX:
+			cmsb |= IOM_CTRL_RCV;
+		case ISDN_PID_L2_B_TRANSDTMF:
+			if (test_bit(FLG_DTMFSEND, &bch->Flags))
+				cmsb |= IOM_CTRL_RCV;
+			cmsb |= IOM_CTRL_ALAW;
+			break;
+	}
+	sendmsg(bch, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg);
+	udelay(1000);
+	sendmsg(bch, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL);
+	udelay(1000);
+}
+
+static int
+modeisar(channel_t *bch, int channel, u_int bprotocol, u_char *param)
+{
+	isar_hw_t	*ih = bch->hw;
+
+	/* Here we are selecting the best datapath for requested protocol */
+	if(bch->state == ISDN_PID_NONE) { /* New Setup */
+		bch->channel = channel;
+		switch (bprotocol) {
+			case ISDN_PID_NONE: /* init */
+				if (!ih->dpath)
+					/* no init for dpath 0 */
+					return(0);
+				break;
+			case ISDN_PID_L1_B_64TRANS:
+			case ISDN_PID_L1_B_64HDLC:
+				/* best is datapath 2 */
+				if (!test_and_set_bit(ISAR_DP2_USE, &ih->reg->Flags))
+					ih->dpath = 2;
+				else if (!test_and_set_bit(ISAR_DP1_USE,
+					&ih->reg->Flags))
+					ih->dpath = 1;
+				else {
+					printk(KERN_WARNING"isar modeisar both pathes in use\n");
+					return(-EINVAL);
+				}
+				break;
+			case ISDN_PID_L1_B_MODEM_ASYNC:
+			case ISDN_PID_L1_B_T30FAX:
+			case ISDN_PID_L2_B_TRANSDTMF:
+				/* only datapath 1 */
+				if (!test_and_set_bit(ISAR_DP1_USE,
+					&ih->reg->Flags))
+					ih->dpath = 1;
+				else {
+					printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
+					mISDN_debugprint(&bch->inst, "isar modeisar analog funktions only with DP1");
+					return(-EBUSY);
+				}
+				break;
+		}
+	}
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "isar dp%d protocol %x->%x ichan %d",
+			ih->dpath, bch->state, bprotocol, channel);
+	bch->state = bprotocol;
+	setup_pump(bch);
+	setup_iom2(bch);
+	setup_sart(bch);
+	if (bch->state == ISDN_PID_NONE) {
+		/* Clear resources */
+		if (ih->dpath == 1)
+			test_and_clear_bit(ISAR_DP1_USE, &ih->reg->Flags);
+		else if (ih->dpath == 2)
+			test_and_clear_bit(ISAR_DP2_USE, &ih->reg->Flags);
+		ih->dpath = 0;
+	}
+	return(0);
+}
+
+static void
+isar_pump_cmd(channel_t *bch, int cmd, u_char para)
+{
+	isar_hw_t	*ih = bch->hw;
+	u_char		dps = SET_DPS(ih->dpath);
+	u_char		ctrl = 0, nom = 0, p1 = 0;
+
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "isar_pump_cmd %x/%x state(%x)",
+					cmd, para, ih->state);
+	switch(cmd) {
+		case HW_MOD_FTM:
+			if (ih->state == STFAX_READY) {
+				p1 = para;
+				ctrl = PCTRL_CMD_FTM;
+				nom = 1;
+				ih->state = STFAX_LINE;
+				ih->cmd = ctrl;
+				ih->mod = para;
+				ih->newmod = 0;
+				ih->newcmd = 0;
+				ih->try_mod = 3;
+			} else if ((ih->state == STFAX_ACTIV) &&
+				(ih->cmd == PCTRL_CMD_FTM) &&
+				(ih->mod == para)) {
+				deliver_status(bch, HW_MOD_CONNECT);
+			} else {
+				ih->newmod = para;
+				ih->newcmd = PCTRL_CMD_FTM;
+				nom = 0;
+				ctrl = PCTRL_CMD_ESC;
+				ih->state = STFAX_ESCAPE;
+			}
+			break;
+		case HW_MOD_FTH:
+			if (ih->state == STFAX_READY) {
+				p1 = para;
+				ctrl = PCTRL_CMD_FTH;
+				nom = 1;
+				ih->state = STFAX_LINE;
+				ih->cmd = ctrl;
+				ih->mod = para;
+				ih->newmod = 0;
+				ih->newcmd = 0;
+				ih->try_mod = 3;
+			} else if ((ih->state == STFAX_ACTIV) &&
+				(ih->cmd == PCTRL_CMD_FTH) &&
+				(ih->mod == para)) {
+				deliver_status(bch, HW_MOD_CONNECT);
+			} else {
+				ih->newmod = para;
+				ih->newcmd = PCTRL_CMD_FTH;
+				nom = 0;
+				ctrl = PCTRL_CMD_ESC;
+				ih->state = STFAX_ESCAPE;
+			}
+			break;
+		case HW_MOD_FRM:
+			if (ih->state == STFAX_READY) {
+				p1 = para;
+				ctrl = PCTRL_CMD_FRM;
+				nom = 1;
+				ih->state = STFAX_LINE;
+				ih->cmd = ctrl;
+				ih->mod = para;
+				ih->newmod = 0;
+				ih->newcmd = 0;
+				ih->try_mod = 3;
+			} else if ((ih->state == STFAX_ACTIV) &&
+				(ih->cmd == PCTRL_CMD_FRM) &&
+				(ih->mod == para)) {
+				deliver_status(bch, HW_MOD_CONNECT);
+			} else {
+				ih->newmod = para;
+				ih->newcmd = PCTRL_CMD_FRM;
+				nom = 0;
+				ctrl = PCTRL_CMD_ESC;
+				ih->state = STFAX_ESCAPE;
+			}
+			break;
+		case HW_MOD_FRH:
+			if (ih->state == STFAX_READY) {
+				p1 = para;
+				ctrl = PCTRL_CMD_FRH;
+				nom = 1;
+				ih->state = STFAX_LINE;
+				ih->cmd = ctrl;
+				ih->mod = para;
+				ih->newmod = 0;
+				ih->newcmd = 0;
+				ih->try_mod = 3;
+			} else if ((ih->state == STFAX_ACTIV) &&
+				(ih->cmd == PCTRL_CMD_FRH) &&
+				(ih->mod == para)) {
+				deliver_status(bch, HW_MOD_CONNECT);
+			} else {
+				ih->newmod = para;
+				ih->newcmd = PCTRL_CMD_FRH;
+				nom = 0;
+				ctrl = PCTRL_CMD_ESC;
+				ih->state = STFAX_ESCAPE;
+			}
+			break;
+		case PCTRL_CMD_TDTMF:
+			p1 = para;
+			nom = 1;
+			ctrl = PCTRL_CMD_TDTMF;
+			break;
+	}
+	if (ctrl)
+		sendmsg(bch, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
+}
+
+void
+isar_setup(channel_t *bch)
+{
+	u_char msg;
+	int i;
+	
+	/* Dpath 1, 2 */
+	msg = 61;
+	for (i=0; i<2; i++) {
+		isar_hw_t	*ih = bch[i].hw;
+		/* Buffer Config */
+		sendmsg(bch, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
+			ISAR_HIS_P12CFG, 4, 1, &msg);
+		ih->mml = msg;
+		bch[i].state = 0;
+		ih->dpath = i + 1;
+		modeisar(&bch[i], i, 0, NULL);
+	}
+}
+
+int
+isar_down(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*bch = container_of(inst, channel_t, inst);
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	if ((hh->prim == PH_DATA_REQ) ||
+		(hh->prim == (DL_DATA | REQUEST))) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		ret = channel_senddata(bch, hh->dinfo, skb);
+		if (ret > 0) { /* direct TX */
+			isar_fill_fifo(bch);
+			ret = 0;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		return(ret);
+	}
+	if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_ESTABLISH  | REQUEST))) {
+		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
+			u_int	bp = bch->inst.pid.protocol[1];
+
+			if (bch->inst.pid.global == 1)
+				test_and_set_bit(FLG_ORIGIN, &bch->Flags);
+			if ((bp == ISDN_PID_L1_B_64TRANS) &&
+				(bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANSDTMF))
+				bp = ISDN_PID_L2_B_TRANSDTMF;
+			spin_lock_irqsave(inst->hwlock, flags);
+			ret = modeisar(bch, bch->channel, bp, NULL);
+			spin_unlock_irqrestore(inst->hwlock, flags);
+		}
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
+	} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_RELEASE | REQUEST)) ||
+		((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+			dev_kfree_skb(bch->next_skb);
+			bch->next_skb = NULL;
+		}
+		if (bch->tx_skb) {
+			dev_kfree_skb(bch->tx_skb);
+			bch->tx_skb = NULL;
+		}
+		bch->tx_idx = 0;
+		if (bch->rx_skb) {
+			dev_kfree_skb(bch->rx_skb);
+			bch->rx_skb = NULL;
+		}
+		test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		test_and_clear_bit(FLG_L2DATA, &bch->Flags);
+		modeisar(bch, bch->channel, 0, NULL);
+		test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		skb_trim(skb, 0);
+		if (hh->prim != (PH_CONTROL | REQUEST))
+			if (!mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, 0, skb))
+				return(0);
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		int  *val;
+		int  len;
+
+		val = (int *)skb->data;
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst, "PH_CONTROL | REQUEST %x/%x",
+					hh->dinfo, *val);
+		if ((hh->dinfo == 0) && ((*val & ~DTMF_TONE_MASK) == DTMF_TONE_VAL)) {
+			if (bch->state == ISDN_PID_L2_B_TRANSDTMF) {
+				char tt = *val & DTMF_TONE_MASK;
+				
+				if (tt == '*')
+					tt = 0x1e;
+				else if (tt == '#')
+					tt = 0x1f;
+				else if (tt > '9')
+					tt -= 7;
+				tt &= 0x1f;
+				spin_lock_irqsave(inst->hwlock, flags);
+				isar_pump_cmd(bch, PCTRL_CMD_TDTMF, tt);
+				spin_unlock_irqrestore(inst->hwlock, flags);
+				skb_trim(skb, 0);
+				if (!mISDN_queueup_newhead(inst, 0, PH_CONTROL | CONFIRM, 0, skb))
+					return(0);
+			} else {
+				printk(KERN_WARNING "isar_down TOUCH_TONE_SEND wrong protocol %x\n",
+					bch->state);
+				return(-EINVAL);
+			}
+		} else if ((hh->dinfo == HW_MOD_FRM) || (hh->dinfo == HW_MOD_FRH) ||
+			(hh->dinfo == HW_MOD_FTM) || (hh->dinfo == HW_MOD_FTH)) {
+			u_int i;
+
+			for (i=0; i<FAXMODCNT; i++)
+				if (faxmodulation[i] == *val)
+					break;
+			if ((FAXMODCNT > i) && test_bit(FLG_INITIALIZED, &bch->Flags)) {
+				printk(KERN_WARNING "isar: new mod\n");
+				isar_pump_cmd(bch, hh->dinfo, *val);
+				ret = 0;
+			} else {
+				int_errtxt("wrong modulation");
+				/* wrong modulation or not activ */
+				// TODO
+				ret = -EINVAL;
+			}
+		} else if (hh->dinfo == HW_MOD_LASTDATA) {
+			test_and_set_bit(FLG_DLEETX, &bch->Flags);
+		} else if (hh->dinfo == HW_FIRM_START) {
+			firmwaresize = *val;
+			if (!(firmware = vmalloc(firmwaresize))) {
+				firmwaresize = 0;
+				return(-ENOMEM);
+			}
+			fw_p = firmware;
+			skb_trim(skb, 0);
+			if(!mISDN_queueup_newhead(inst, 0, PH_CONTROL | CONFIRM, 0, skb))
+				return(0);
+		} else if (hh->dinfo == HW_FIRM_DATA) {
+			len = *val++;
+			if (!fw_p)
+				return(-EINVAL);
+			memcpy(fw_p, val, len);
+			fw_p += len;
+			skb_trim(skb, 0);
+			if(!mISDN_queueup_newhead(inst, 0, PH_CONTROL | CONFIRM, 0, skb))
+				return(0);
+		} else if (hh->dinfo == HW_FIRM_END) {
+			if (!fw_p)
+				return(-EINVAL);
+			len = (fw_p - firmware) & 0xffffffff;
+			if (len == firmwaresize)
+				ret = isar_load_firmware(bch, firmware, firmwaresize);
+			else {
+				printk(KERN_WARNING "wrong firmware size %d/%d\n",
+					len, firmwaresize);
+				ret = -EINVAL;
+			}
+			vfree(firmware);
+			fw_p = firmware = NULL;
+			firmwaresize = 0;
+			skb_trim(skb, 0);
+			if(!mISDN_queueup_newhead(inst, 0, PH_CONTROL | CONFIRM, 0, skb))
+				return(0);
+		} else {
+			printk(KERN_WARNING "isar_down unknown (PH_CONTROL | REQUEST) %x\n",
+				hh->dinfo);
+			ret = -EINVAL;
+		}
+	} else {
+		printk(KERN_WARNING "isar_down unknown prim(%x)\n", hh->prim);
+		ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+void
+free_isar(channel_t *bch)
+{
+	isar_hw_t *ih = bch->hw;
+
+	modeisar(bch, bch->channel, 0, NULL);
+	del_timer(&ih->ftimer);
+	test_and_clear_bit(FLG_INITIALIZED, &bch->Flags);
+}
+
+
+int init_isar(channel_t *bch)
+{
+	isar_hw_t *ih = bch->hw;
+
+	printk(KERN_INFO "mISDN: ISAR driver Rev. %s\n", mISDN_getrev(ISAR_revision));
+	ih->ftimer.function = (void *) ftimer_handler;
+	ih->ftimer.data = (long) bch;
+	init_timer(&ih->ftimer);
+	test_and_set_bit(FLG_INITIALIZED, &bch->Flags);
+	return (0);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isar.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isar.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/isar.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,238 @@
+/* $Id: isar.h,v 1.4 2006/03/06 12:52:07 keil Exp $
+ *
+ * isar.h   ISAR (Siemens PSB 7110) specific defines
+ *
+ * Author Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+ 
+typedef struct _isar_reg {
+	unsigned long	Flags;
+	volatile u_char	bstat;
+	volatile u_char	iis;
+	volatile u_char	cmsb;
+	volatile u_char	clsb;
+	volatile u_char	par[8];
+} isar_reg_t;
+
+typedef struct _isar_hw {
+	int			dpath;
+	int			mml;
+	u_char			state;
+	u_char			cmd;
+	u_char			mod;
+	u_char			newcmd;
+	u_char			newmod;
+	char			try_mod;
+	struct timer_list	ftimer;
+	u_char			conmsg[16];
+	isar_reg_t		*reg;
+} isar_hw_t;
+
+#define ISAR_IRQMSK	0x04
+#define ISAR_IRQSTA	0x04
+#define ISAR_IRQBIT	0x75
+#define ISAR_CTRL_H	0x61
+#define ISAR_CTRL_L	0x60
+#define ISAR_IIS	0x58
+#define ISAR_IIA	0x58
+#define ISAR_HIS	0x50
+#define ISAR_HIA	0x50
+#define ISAR_MBOX	0x4c
+#define ISAR_WADR	0x4a
+#define ISAR_RADR	0x48 
+
+#define ISAR_HIS_VNR		0x14
+#define ISAR_HIS_DKEY		0x02
+#define ISAR_HIS_FIRM		0x1e
+#define ISAR_HIS_STDSP		0x08
+#define ISAR_HIS_DIAG		0x05
+#define ISAR_HIS_P0CFG		0x3c
+#define ISAR_HIS_P12CFG		0x24
+#define ISAR_HIS_SARTCFG	0x25	
+#define ISAR_HIS_PUMPCFG	0x26	
+#define ISAR_HIS_PUMPCTRL	0x2a	
+#define ISAR_HIS_IOM2CFG	0x27
+#define ISAR_HIS_IOM2REQ	0x07
+#define ISAR_HIS_IOM2CTRL	0x2b
+#define ISAR_HIS_BSTREQ		0x0c
+#define ISAR_HIS_PSTREQ		0x0e
+#define ISAR_HIS_SDATA		0x20
+#define ISAR_HIS_DPS1		0x40
+#define ISAR_HIS_DPS2		0x80
+#define SET_DPS(x)		((x<<6) & 0xc0)
+
+#define ISAR_IIS_MSCMSD		0x3f
+#define ISAR_IIS_VNR		0x15
+#define ISAR_IIS_DKEY		0x03
+#define ISAR_IIS_FIRM		0x1f
+#define ISAR_IIS_STDSP		0x09
+#define ISAR_IIS_DIAG		0x25
+#define ISAR_IIS_GSTEV		0x00
+#define ISAR_IIS_BSTEV		0x28
+#define ISAR_IIS_BSTRSP		0x2c
+#define ISAR_IIS_PSTRSP		0x2e
+#define ISAR_IIS_PSTEV		0x2a
+#define ISAR_IIS_IOM2RSP	0x27
+#define ISAR_IIS_RDATA		0x20
+#define ISAR_IIS_INVMSG		0x3f
+
+#define ISAR_CTRL_SWVER	0x10
+#define ISAR_CTRL_STST	0x40
+
+#define ISAR_MSG_HWVER	{0x20, 0, 1}
+
+#define ISAR_DP1_USE	1
+#define ISAR_DP2_USE	2
+#define ISAR_RATE_REQ	3
+
+#define PMOD_DISABLE	0
+#define PMOD_FAX	1
+#define PMOD_DATAMODEM	2
+#define PMOD_HALFDUPLEX	3
+#define PMOD_V110	4
+#define PMOD_DTMF	5
+#define PMOD_DTMF_TRANS	6
+#define PMOD_BYPASS	7
+
+#define PCTRL_ORIG	0x80
+#define PV32P2_V23R	0x40
+#define PV32P2_V22A	0x20
+#define PV32P2_V22B	0x10
+#define PV32P2_V22C	0x08
+#define PV32P2_V21	0x02
+#define PV32P2_BEL	0x01
+
+// LSB MSB in ISAR doc wrong !!! Arghhh
+#define PV32P3_AMOD	0x80
+#define PV32P3_V32B	0x02
+#define PV32P3_V23B	0x01
+#define PV32P4_48	0x11
+#define PV32P5_48	0x05
+#define PV32P4_UT48	0x11
+#define PV32P5_UT48	0x0d
+#define PV32P4_96	0x11
+#define PV32P5_96	0x03
+#define PV32P4_UT96	0x11
+#define PV32P5_UT96	0x0f
+#define PV32P4_B96	0x91
+#define PV32P5_B96	0x0b
+#define PV32P4_UTB96	0xd1
+#define PV32P5_UTB96	0x0f
+#define PV32P4_120	0xb1
+#define PV32P5_120	0x09
+#define PV32P4_UT120	0xf1
+#define PV32P5_UT120	0x0f
+#define PV32P4_144	0x99
+#define PV32P5_144	0x09
+#define PV32P4_UT144	0xf9
+#define PV32P5_UT144	0x0f
+#define PV32P6_CTN	0x01
+#define PV32P6_ATN	0x02
+
+#define PFAXP2_CTN	0x01
+#define PFAXP2_ATN	0x04
+
+#define PSEV_10MS_TIMER	0x02
+#define PSEV_CON_ON	0x18
+#define PSEV_CON_OFF	0x19
+#define PSEV_V24_OFF	0x20
+#define PSEV_CTS_ON	0x21
+#define PSEV_CTS_OFF	0x22
+#define PSEV_DCD_ON	0x23
+#define PSEV_DCD_OFF	0x24
+#define PSEV_DSR_ON	0x25
+#define PSEV_DSR_OFF	0x26
+#define PSEV_REM_RET	0xcc
+#define PSEV_REM_REN	0xcd
+#define PSEV_GSTN_CLR	0xd4
+
+#define 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_TDTMF	0x5a
+
+#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
+
+#define SMODE_DISABLE	0
+#define SMODE_V14	2
+#define SMODE_HDLC	3
+#define SMODE_BINARY	4
+#define SMODE_FSK_V14	5
+
+#define SCTRL_HDMC_BOTH	0x00
+#define SCTRL_HDMC_DTX	0x80
+#define SCTRL_HDMC_DRX	0x40
+#define S_P1_OVSP	0x40
+#define S_P1_SNP	0x20
+#define S_P1_EOP	0x10
+#define S_P1_EDP	0x08
+#define S_P1_NSB	0x04
+#define S_P1_CHS_8	0x03
+#define S_P1_CHS_7	0x02
+#define S_P1_CHS_6	0x01
+#define S_P1_CHS_5	0x00
+
+#define S_P2_BFT_DEF	0x10
+
+#define IOM_CTRL_ENA	0x80
+#define IOM_CTRL_NOPCM	0x00
+#define IOM_CTRL_ALAW	0x02
+#define IOM_CTRL_ULAW	0x04
+#define IOM_CTRL_RCV	0x01
+
+#define IOM_P1_TXD	0x10
+
+#define HDLC_FED	0x40
+#define HDLC_FSD	0x20
+#define HDLC_FST	0x20
+#define HDLC_ERROR	0x1c
+#define HDLC_ERR_FAD	0x10
+#define HDLC_ERR_RER	0x08
+#define HDLC_ERR_CER	0x04
+#define SART_NMD	0x01
+
+#define BSTAT_RDM0	0x1
+#define BSTAT_RDM1	0x2
+#define BSTAT_RDM2	0x4
+#define BSTAT_RDM3	0x8
+#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(channel_t *bch, char *s);
+extern void isar_int_main(channel_t *bch);
+extern int init_isar(channel_t *bch);
+extern void free_isar(channel_t *bch);
+extern int isar_down(mISDNinstance_t *, struct sk_buff *);
+extern int isar_load_firmware(channel_t *bch, u_char *buf, int size);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l1oip.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l1oip.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l1oip.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1194 @@
+/*
+
+ * l1oip.c  low level driver for tunneling layer 1 over IP
+ *
+ * NOTE: It is not compatible with TDMoIP nor "ISDN over IP".
+ *
+ * Author	Andreas Eversberg (jolly at eversberg.eu)
+ *
+ * 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.
+ *
+ */
+
+/* module parameters:
+ * type:
+	Value 1	= BRI
+	Value 2	= PRI
+	Value 3 = BRI (multi channel frame)
+	Value 4 = PRI (multi channel frame)
+	A multi channel frame reduces overhead to a single frame for all
+       	b-channels, but increases delay.
+
+ * codec:
+	Value 0 = aLaw transparent
+	Value 1	= uLaw transparent (instead of aLaw)
+	Value 2 = aLaw to TADPCM
+	Value 3	= uLaw to TADPCM
+
+ * protocol:
+ 	Bit 0-3 = protocol
+	Bit 4	= NT-Mode
+	Bit 5	= PTP (instead of multipoint)
+
+ * layermask:
+	NOTE: Must be given for all ports, not for the number of cards.
+	mask of layers to be used for D-channel stack
+
+ * limit:
+	limitation of bchannels to control bandwidth (1...29)
+
+ * ip:
+	binary representation of remote ip address (127.0.0.0 -> 0x7f000001)
+	If not given, no remote address is set.
+
+ * port:
+	port number
+	If not given or 0, port 931 is used.
+
+ * id:
+	mandatory value to identify frames. This value must be equal on both
+	peers and should be random.
+
+ * debug:
+	NOTE: only one debug value must be given for all cards
+	enable debugging (see l1oip.h for debug options)
+
+
+Special PH_CONTROL messages:
+
+ dinfo = L1OIP_SETPEER
+ data bytes 0-3 : IP address in network order (MSB first)
+ data bytes 4-5 : local port in network order
+ data bytes 6-7 : remote port in network order
+
+ dinfo = L1OIP_UNSETPEER
+
+ * Use l1oipctrl for setting or removin ip address
+	
+
+L1oIP-Protocol
+--------------
+
+The Layer 1 over IP protocol tunnels frames and audio streams over IP. It will
+be directly attached to the layer 2 or interconnected to layer 1 of a different
+stack.
+
+It also provides layer 1 control and keeps dynamic IP connectivity up.
+
+Frame structure:
+
++---------------------------------------------------------------+
+|                              ID                               |
++---------------+---------------+-------------------------------+
+|    Coding     |B|  Channel    |  Time Base / Layer 1 message  |
++---------------+---------------+-------------------------------+
+|                          Channel Map                          |
++---------------------------------------------------------------+
+|                                                               |
+.                             Data                              .
+.                                                               .
+
+
+The "ID" should be a random number. It makes shure that missrouted frames get
+dropped due to wrong id. Also it provides simple security agains DOS attacs.
+
+The "Coding" byte defines the data format. It can be
+
+0	HDLC-data
+1	TADPCM (table ADPCM)
+2	A-law
+3	u-law
+
+The "B"-Flag shows the interface type:
+0	BRI
+1	PRI 
+
+The "Channel" will give the timeslot or channel number.
+
+0	Layer 1 message
+1-2	B-Channel for BRI interface
+1-15	B-Channel 1-15 for PRI interface
+16	D-Channel for PRI and BRI interface
+17-31	B-Channel 17-31 for PRI interface
+127	B-Channels as given by "Channel Map"
+
+The "Time Base" is used to rearange packets and to detect packet loss.
+The 16 bits are sent in network order (MSB first) and count 1/8000 th of a
+second. This causes a wrap arround each 8,192 seconds. There is no requirement
+for the initial "Time Base", but 0 should be used for the first packet.
+
+The "Channel Map" are 4 bytes in network order (MSB first). They only exist, if
+the Channel Map was selected with the Channel value. Bits 1-31 represent the
+existance of data for each channel Bit 0 is not used and shall be 0.
+The length of each channel data is defined by the total number of bytes
+divided by the number of bits set in the Channel Map. The coding and length must
+be equal for all existing channels.
+NOTE: D-Channel data must be sent via seperate frame, because length and
+coding are differen. Also packet mode data should be sent in a seperate frame.
+
+The total length of data is defined by the maximum packet size (without header).
+
+
+Validity check at the receiver: Packets will be dropped if
+
+- the length is less than 4 bytes.
+- there is no data in the packet.
+- the Coding is not supported. False coding should produce a warning once.
+- the B-flag does not equal the expected interface type.
+- the channel is out of range.
+- the channel does not exists by interface. A warning should be produced once.
+- the channel map is selected, but length is less than 8 bytes.
+- the channel map's bit 0 is set if channel map is selected.
+- the channel map is completely 0, but the packet has data anyway.
+- the length of data is not a multiple of the channels indicated by channel map.
+- the data exceeds the maximum frame length of the ISDN driver.
+- the layer 1 message is unknown.
+
+Layer 1 Message:
+
+This is a special type of frame. In this case the "Time Base" contains two
+bytes with the message. The first byte (MSB) contains the sequence number and the
+second byte the message.
+
+The sequence number is used to detect the reception of a message. If the message
+is received, the new sequence number is acknowledged using message 0 (keepalive)
+If the keepalive is received with the sequence number last sent, the next
+message can be sent with incremented sequence number.
+
+If no message is to be sent, the sequence number is not incremented and the 
+last sequence number is repeated.
+
+The keepalive is sent every 10 seconds. If a message is about to be sent, the
+message is repeated every second until the keepalive is received with the 
+incremented sequence number.
+
+0,x	IP link keepalive. X is a sequence to detect packet loss.
+1,1	Activate layer 1
+1,0	Deactivate layer 1
+2,1	AIS on (alarm on the remote interface)
+2,0	AIS off
+3,1	Maintainance blocked
+3,0	Maintainance unblocked
+16,x	Application specific information.
+32,0	Announce new IP
+32,1	Acknowledge new IP
+
+IP Announcement:
+
+One or both sides may have dynamic IP address. A simple trick is used to get
+the remote IP if it changes. It is assumed, that both sides don't change their
+IP at the same time.
+
+If IP changes, the peer must announce it's new IP address. A layer 1 message
+with the new IP address (4 extra bytes) and the "peer's password" (more extra
+bytes).
+The transmission interval is one second. 
+The remote peer will receive the new IP address with the password. If the
+password matches, the new IP will be used. The passwort is used to prevent
+"take over" connections. An acknowledge will be generated, by the remote peer
+to make the local peer stop sending "Announces".
+
+The initial value will be given by application. It is only required for one
+peer to give the initial IP address. After an IP address is given, it will be
+announced.
+
+*/
+
+
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include "dchannel.h"
+#include "bchannel.h"
+#include "layer1.h"
+#include "dsp.h"
+#include "debug.h"
+#include <linux/isdn_compat.h>
+
+#include "l1oip.h"
+
+//static void ph_state_change(dchannel_t *dch);
+
+extern const char *CardType[];
+
+static const char *l1oip_revision = "$Revision: 1.8 $";
+
+static int l1oip_cnt;
+
+static mISDNobject_t	l1oip_obj;
+
+static char l1oipName[] = "Layer1oIP";
+
+
+/****************/
+/* module stuff */
+/****************/
+
+#define MAX_CARDS	16
+static u_int type[MAX_CARDS];
+static u_int codec[MAX_CARDS];
+static u_int protocol[MAX_CARDS];
+static int layermask[MAX_CARDS];
+static int debug;
+
+#ifdef MODULE
+MODULE_AUTHOR("Andreas Eversberg");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(codec, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(protocol, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, NULL, S_IRUGO | S_IWUSR);
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+#endif
+
+
+/********************/
+/* D-channel access */
+/********************/
+
+locking bedenken
+/* message transfer from layer 2
+ */
+static int l1oip_dchannel(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	dchannel_t	*dch = container_of(inst, dchannel_t, inst);
+	l1oip_t		*hc;
+	int		ret = 0;
+	mISDN_head_t	*hh;
+	u_long		flags;
+
+	hh = mISDN_HEAD_P(skb);
+	hc = dch->inst.privat;
+	if (hh->prim == PH_DATA_REQ) {
+		/* check oversize */
+		if (skb->len <= 0) {
+			printk(KERN_WARNING "%s: skb too small\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+		if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > MAX_L1OIP_LEN) {
+			printk(KERN_WARNING "%s: skb too large\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+		/* check for pending next_skb */
+		spin_lock_irqsave(inst->hwlock, flags);
+		if (dch->next_skb) {
+			printk(KERN_WARNING "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n",
+				__FUNCTION__, skb->len, dch->next_skb->len);
+			spin_unlock_irqrestore(inst->hwlock, flags);
+			return(-EBUSY);
+		}
+		if (test_and_set_bit(FLG_TX_BUSY, &dch->DFlags)) {
+			test_and_set_bit(FLG_TX_NEXT, &dch->DFlags);
+			dch->next_skb = skb;
+			spin_unlock_irqrestore(inst->hwlock, flags);
+			return(0);
+		}
+		/* send/queue frame */
+		l1oip_tx(hc, 16, skb, CODEC_L1OIP_DATA);
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(inst, 0, PH_DATA_CNF,hh->dinfo, skb));
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		switch (hh->dinfo) {
+			case L1OIP_SETPEER:
+				lkkllkö
+			return(mISDN_queueup_newhead(inst, 0, PH_CONTROL | INDICATION, L1OIP_SETPEER, skb));
+			break;
+
+			case L1OIP_UNSETPEER:
+				lkkllkö
+			return(mISDN_queueup_newhead(inst, 0, PH_CONTROL | INDICATION, L1OIP_UNSETPEER, skb));
+			break;
+
+			default:
+			printk(KERN_DEBUG "%s: unknown PH_CONTROL info %x\n", __FUNCTION__, hh->dinfo);
+			ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+	} else if (hh->prim == (PH_ACTIVATE | REQUEST)) {
+		if (test_bit(HFC_CFG_NTMODE, &hc->chan[dch->channel].cfg)) {
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: PH_ACTIVATE port %d (0..%d)\n", __FUNCTION__, hc->chan[dch->channel].port, hc->pri?30:2);
+			spin_lock_irqsave(inst->hwlock, flags);
+			/* start activation */
+			if (pri) {
+				//dchannel_sched_event(dch, D_L1STATECHANGE);
+				ph_state_change(dch);
+				if (debug & DEBUG_L1OIP_STATE)
+					printk(KERN_DEBUG "%s: E1 report state %x \n", __FUNCTION__, dch->ph_state);
+			} else {
+				HFC_outb(hc, R_ST_SEL, hc->chan[dch->channel].port);
+				HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1); /* G1 */
+				udelay(6); /* wait at least 5,21us */
+				HFC_outb(hc, A_ST_WR_STATE, 1);
+				HFC_outb(hc, A_ST_WR_STATE, 1 | (V_ST_ACT*3)); /* activate */
+				dch->ph_state = 1;
+			}
+			spin_unlock_irqrestore(inst->hwlock, flags);
+		} else {
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: PH_ACTIVATE no NT-mode port %d (0..%d)\n", __FUNCTION__, hc->chan[dch->channel].port, hc->pri?30:2);
+			ret = -EINVAL;
+		}
+	} else if (hh->prim == (PH_DEACTIVATE | REQUEST)) {
+		if (test_bit(HFC_CFG_NTMODE, &hc->chan[dch->channel].cfg)) {
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: PH_DEACTIVATE port %d (0..%d)\n", __FUNCTION__, hc->chan[dch->channel].port, hc->pri?30:2);
+			spin_lock_irqsave(inst->hwlock, flags);
+			hw_deactivate: /* after lock */
+			dch->ph_state = 0;
+			/* start deactivation */
+			if (hc->pri) {
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: PH_DEACTIVATE no BRI\n", __FUNCTION__);
+			} else {
+				HFC_outb(hc, R_ST_SEL, hc->chan[dch->channel].port);
+				HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT*2); /* deactivate */
+			}
+			if (dch->next_skb) {
+				dev_kfree_skb(dch->next_skb);
+				dch->next_skb = NULL;
+			}
+			dch->tx_idx = dch->tx_len = hc->chan[dch->channel].rx_idx = 0;
+			test_and_clear_bit(FLG_TX_NEXT, &dch->DFlags);
+			test_and_clear_bit(FLG_TX_BUSY, &dch->DFlags);
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
+				del_timer(&dch->dbusytimer);
+			spin_unlock_irqrestore(inst->hwlock, flags);
+		} else {
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: PH_DEACTIVATE no NT-mode port %d (0..%d)\n", __FUNCTION__, hc->chan[dch->channel].port, hc->pri?30:2);
+			ret = -EINVAL;
+		}
+	} else
+	if (hh->prim == MGR_SHORTSTATUS) {
+		if(hh->dinfo==SSTATUS_ALL || hh->dinfo==SSTATUS_L1) {
+			int new_addr;
+			if(hh->dinfo&SSTATUS_BROADCAST_BIT) new_addr= dch->inst.id | MSG_BROADCAST;
+			else new_addr=hh->addr | FLG_MSG_TARGET;
+			return(mISDN_queueup_newhead(inst, new_addr, MGR_SHORTSTATUS,(dch->l1_up) ? SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED, skb));
+		}
+	} else {
+		if (debug & DEBUG_L1OIP_MSG)
+			printk(KERN_DEBUG "%s: unknown prim %x\n", __FUNCTION__, hh->prim);
+		ret = -EINVAL;
+	}
+	if (!ret) {
+//		printk("1\n");
+		dev_kfree_skb(skb);
+//		printk("2\n");
+	}
+	return(ret);
+}
+
+
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+
+/* messages from layer 2 to layer 1 are processed here.
+ */
+static int
+l1oip_bchannel(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	u_long		flags, num;
+	int		slot_tx, slot_rx, bank_tx, bank_rx;
+	bchannel_t	*bch = container_of(inst, bchannel_t, inst);
+	int		ret = -EINVAL;
+	mISDN_head_t	*hh;
+	hfc_multi_t	*hc;
+	struct		dsp_features *features;
+
+	hh = mISDN_HEAD_P(skb);
+	hc = bch->inst.privat;
+
+	if ((hh->prim == PH_DATA_REQ)
+	 || (hh->prim == (DL_DATA | REQUEST))) {
+		if (skb->len <= 0) {
+			printk(KERN_WARNING "%s: skb too small\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+		if (skb->len > MAX_DATA_MEM) {
+			printk(KERN_WARNING "%s: skb too large\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+		/* check for pending next_skb */
+		spin_lock_irqsave(inst->hwlock, flags);
+		if (bch->next_skb) {
+			printk(KERN_WARNING "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", __FUNCTION__, skb->len, bch->next_skb->len);
+			spin_unlock_irqrestore(inst->hwlock, flags);
+			return(-EBUSY);
+		}
+		/* if we have currently a pending tx skb */
+		if (test_and_set_bit(BC_FLG_TX_BUSY, &bch->Flag)) {
+			test_and_set_bit(BC_FLG_TX_NEXT, &bch->Flag);
+			bch->next_skb = skb;
+			spin_unlock_irqrestore(inst->hwlock, flags);
+			return(0);
+		}
+		/* write to fifo */
+		bch->tx_len = skb->len;
+		memcpy(bch->tx_buf, skb->data, bch->tx_len);
+		bch->tx_idx = 0;
+		hfcmulti_tx(hc, bch->channel, NULL, bch);
+		/* start fifo */
+		HFC_outb_(hc, R_FIFO, 0);
+		HFC_wait_(hc);
+		spin_unlock_irqrestore(inst->hwlock, flags);
+#ifdef FIXME   // TODO changed
+		if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+			&& bch->dev)
+			hif = &bch->dev->rport.pif;
+		else
+			hif = &bch->inst.up;
+#endif
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, hh->dinfo, skb));
+	} else if ((hh->prim == (PH_ACTIVATE | REQUEST))
+	 || (hh->prim == (DL_ESTABLISH  | REQUEST))) {
+		/* activate B-channel if not already activated */
+		if (debug & DEBUG_L1OIP_MSG)
+			printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n", __FUNCTION__, bch->channel);
+		if (test_and_set_bit(BC_FLG_ACTIV, &bch->Flag))
+			ret = 0;
+		else {
+			spin_lock_irqsave(inst->hwlock, flags);
+			ret = mode_hfcmulti(hc, bch->channel, bch->inst.pid.protocol[1], hc->chan[bch->channel].slot_tx, hc->chan[bch->channel].bank_tx, hc->chan[bch->channel].slot_rx, hc->chan[bch->channel].bank_rx);
+			if (!ret) {
+				bch->protocol = bch->inst.pid.protocol[1];
+				if (bch->protocol==ISDN_PID_L1_B_64TRANS && !hc->dtmf) {
+					/* start decoder */
+					hc->dtmf = 1;
+					if (debug & DEBUG_L1OIP_DTMF)
+						printk(KERN_DEBUG "%s: start dtmf decoder\n", __FUNCTION__);
+					HFC_outb(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF);
+				}
+			}
+			spin_unlock_irqrestore(inst->hwlock, flags);
+		}
+#ifdef FIXME  // TODO changed
+		if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+			if (bch->dev)
+				if_link(&bch->dev->rport.pif, hh->prim | CONFIRM, 0, 0, NULL, 0);
+#endif
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
+	} else if ((hh->prim == (PH_DEACTIVATE | REQUEST))
+	 || (hh->prim == (DL_RELEASE | REQUEST))
+	 || ((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
+		if (debug & DEBUG_L1OIP_MSG)
+			printk(KERN_DEBUG "%s: PH_DEACTIVATE ch %d (0..32)\n", __FUNCTION__, bch->channel);
+		/* deactivate B-channel if not already deactivated */
+		spin_lock_irqsave(inst->hwlock, flags);
+		if (bch->next_skb) {
+			test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag);
+			dev_kfree_skb(bch->next_skb);
+			bch->next_skb = NULL;
+		}
+		bch->tx_idx = bch->tx_len = bch->rx_idx = 0;
+		test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
+		hc->chan[bch->channel].slot_tx = -1;
+		hc->chan[bch->channel].slot_rx = -1;
+		hc->chan[bch->channel].conf = -1;
+		mode_hfcmulti(hc, bch->channel, ISDN_PID_NONE, hc->chan[bch->channel].slot_tx, hc->chan[bch->channel].bank_tx, hc->chan[bch->channel].slot_rx, hc->chan[bch->channel].bank_rx);
+		bch->protocol = ISDN_PID_NONE;
+		test_and_clear_bit(BC_FLG_ACTIV, &bch->Flag);
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		skb_trim(skb, 0);
+//printk("5\n");
+		if (hh->prim != (PH_CONTROL | REQUEST)) {
+#ifdef FIXME  // TODO changed
+			if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+				if (bch->dev)
+					if_link(&bch->dev->rport.pif, hh->prim | CONFIRM, 0, 0, NULL, 0);
+#endif
+			return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
+//printk("6\n");
+		}
+//printk("7\n");
+		ret = 0;
+	} else
+	if (hh->prim == (PH_CONTROL | REQUEST)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		switch (hh->dinfo) {
+			/* fill features structure */
+			case HW_FEATURES:
+			if (skb->len != sizeof(void *)) {
+				printk(KERN_WARNING "%s: HW_FEATURES lacks parameters\n", __FUNCTION__);
+				break;
+			}
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: HW_FEATURE request\n", __FUNCTION__);
+			features = *((struct dsp_features **)skb->data);
+			features->hfc_id = hc->id;
+			if (test_bit(HFC_CHIP_DTMF, &hc->chip))
+				features->hfc_dtmf = 1;
+			features->hfc_loops = 0;
+			features->pcm_id = hc->pcm;
+			features->pcm_slots = hc->slots;
+			features->pcm_banks = 2;
+			ret = 0;
+			break;
+
+			/* connect interface to pcm timeslot (0..N) */
+			case HW_PCM_CONN:
+			if (skb->len < 4*sizeof(u_long)) {
+				printk(KERN_WARNING "%s: HW_PCM_CONN lacks parameters\n", __FUNCTION__);
+				break;
+			}
+			slot_tx = ((int *)skb->data)[0];
+			bank_tx = ((int *)skb->data)[1];
+			slot_rx = ((int *)skb->data)[2];
+			bank_rx = ((int *)skb->data)[3];
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX)\n", __FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx);
+			if (slot_tx<=hc->slots && bank_tx<=2 && slot_rx<=hc->slots && bank_rx<=2)
+				hfcmulti_pcm(hc, bch->channel, slot_tx, bank_tx, slot_rx, bank_rx);
+			else
+				printk(KERN_WARNING "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX) out of range\n", __FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx);
+			ret = 0;
+			break;
+
+			/* release interface from pcm timeslot */
+			case HW_PCM_DISC:
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: HW_PCM_DISC\n", __FUNCTION__);
+			hfcmulti_pcm(hc, bch->channel, -1, -1, -1, -1);
+			ret = 0;
+			break;
+
+			/* join conference (0..7) */
+			case HW_CONF_JOIN:
+			if (skb->len < sizeof(u_long)) {
+				printk(KERN_WARNING "%s: HW_CONF_JOIN lacks parameters\n", __FUNCTION__);
+				break;
+			}
+			num = ((u_long *)skb->data)[0];
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: HW_CONF_JOIN conf %ld\n", __FUNCTION__, num);
+			if (num <= 7) {
+				hfcmulti_conf(hc, bch->channel, num);
+				ret = 0;
+			} else
+				printk(KERN_WARNING "%s: HW_CONF_JOIN conf %ld out of range\n", __FUNCTION__, num);
+			break;
+
+			/* split conference */
+			case HW_CONF_SPLIT:
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: HW_CONF_SPLIT\n", __FUNCTION__);
+			hfcmulti_conf(hc, bch->channel, -1);
+			ret = 0;
+			break;
+
+			/* set sample loop */
+			case HW_SPL_LOOP_ON:
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: HW_SPL_LOOP_ON (len = %d)\n", __FUNCTION__, skb->len);
+			hfcmulti_splloop(hc, bch->channel, skb->data, skb->len);
+			ret = 0;
+			break;
+
+			/* set silence */
+			case HW_SPL_LOOP_OFF:
+			if (debug & DEBUG_L1OIP_MSG)
+				printk(KERN_DEBUG "%s: HW_SPL_LOOP_OFF\n", __FUNCTION__);
+			hfcmulti_splloop(hc, bch->channel, NULL, 0);
+			ret = 0;
+			break;
+
+			default:
+			printk(KERN_DEBUG "%s: unknown PH_CONTROL info %x\n", __FUNCTION__, hh->dinfo);
+			ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+	} else {
+		printk(KERN_WARNING "%s: unknown prim(%x)\n", __FUNCTION__, hh->prim);
+		ret = -EINVAL;
+	}
+	if (!ret) {
+//		printk("3\n");
+		dev_kfree_skb(skb);
+//		printk("4\n");
+	}
+	return(ret);
+}
+
+
+
+/* MGR stuff */
+
+static int
+l1oip_manager(void *data, u_int prim, void *arg)
+{
+	hfc_multi_t	*hc;
+	mISDNinstance_t	*inst = data;
+	struct sk_buff	*skb;
+	dchannel_t	*dch = NULL;
+	bchannel_t	*bch = NULL;
+	int		ch;
+	int		i;
+	u_long		flags;
+
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim,arg,&HFCM_obj)
+		printk(KERN_ERR "%s: no data prim %x arg %p\n", __FUNCTION__, prim, arg);
+		return(-EINVAL);
+	}
+
+	/* find channel and card */
+	spin_lock_irqsave(&HFCM_obj.lock, flags);
+	if (hc->dch[i])
+	if (&hc->dch[i]->inst == inst) {
+		dch = hc->dch[i];
+		ch = dch->channel;
+		break;
+	}
+	list_for_each_entry(hc, &HFCM_obj.ilist, list) {
+		i = 0;
+		while(i < 30) {
+//printk(KERN_DEBUG "comparing (D-channel) card=%08x inst=%08x with inst=%08x\n", hc, &hc->dch[i].inst, inst);
+			if (hc->bch[i])
+			if (&hc->bch[i]->inst == inst) {
+				bch = hc->bch[i];
+				ch = dch->channel;
+				goto found;
+			}
+			i++;
+		}
+	}
+	spin_unlock_irqrestore(&HFCM_obj.lock, flags);
+	printk(KERN_ERR "%s: no card/channel found  data %p prim %x arg %p\n", __FUNCTION__, data, prim, arg);
+	return(-EINVAL);
+	
+	found:
+	spin_unlock_irqrestore(&HFCM_obj.lock, flags);
+	if (debug & DEBUG_L1OIP_MGR)
+		printk(KERN_DEBUG "%s: channel %d (0..31)  data %p prim %x arg %p\n", __FUNCTION__, ch, data, prim, arg);
+
+	switch(prim) {
+		case MGR_REGLAYER | CONFIRM:
+		if (debug & DEBUG_L1OIP_MGR)
+			printk(KERN_DEBUG "%s: MGR_REGLAYER\n", __FUNCTION__);
+		if (dch)
+			dch_set_para(dch, &inst->st->para);
+		if (bch)
+			bch_set_para(bch, &inst->st->para);
+		break;
+
+		case MGR_UNREGLAYER | REQUEST:
+		if (debug & DEBUG_L1OIP_MGR)
+			printk(KERN_DEBUG "%s: MGR_UNREGLAYER\n", __FUNCTION__);
+		if (dch) {
+			if ((skb = create_link_skb(PH_CONTROL | REQUEST, HW_DEACTIVATE, 0, NULL, 0))) {
+				if (hfcmulti_l1hw(inst, skb)) dev_kfree_skb(skb);
+			}
+		} else
+		if (bch) {
+			if ((skb = create_link_skb(PH_CONTROL | REQUEST, 0, 0, NULL, 0))) {
+				if (hfcmulti_l2l1(inst, skb)) dev_kfree_skb(skb);
+			}
+		}
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+		break;
+
+		case MGR_CLRSTPARA | INDICATION:
+		arg = NULL;
+		// fall through
+		case MGR_ADDSTPARA | INDICATION:
+		if (debug & DEBUG_L1OIP_MGR)
+			printk(KERN_DEBUG "%s: MGR_***STPARA\n", __FUNCTION__);
+		if (dch)
+			dch_set_para(dch, arg);
+		if (bch)
+			bch_set_para(bch, arg);
+		break;
+
+		case MGR_RELEASE | INDICATION:
+		if (debug & DEBUG_L1OIP_MGR)
+			printk(KERN_DEBUG "%s: MGR_RELEASE = remove port from mISDN\n", __FUNCTION__);
+		if (dch) {
+			release_network(hc);
+			release_card(hc);
+		}
+		break;
+#ifdef FIXME
+		case MGR_CONNECT | REQUEST:
+		if (debug & DEBUG_L1OIP_MGR)
+			printk(KERN_DEBUG "%s: MGR_CONNECT\n", __FUNCTION__);
+		return(mISDN_ConnectIF(inst, arg));
+
+		case MGR_SETIF | REQUEST:
+		case MGR_SETIF | INDICATION:
+		if (debug & DEBUG_L1OIP_MGR)
+			printk(KERN_DEBUG "%s: MGR_SETIF\n", __FUNCTION__);
+		if (dch)
+			return(mISDN_SetIF(inst, arg, prim, hfcmulti_l1hw, NULL, dch));
+		if (bch)
+			return(mISDN_SetIF(inst, arg, prim, hfcmulti_l2l1, NULL, bch));
+		break;
+
+		case MGR_DISCONNECT | REQUEST:
+		case MGR_DISCONNECT | INDICATION:
+		if (debug & DEBUG_L1OIP_MGR)
+			printk(KERN_DEBUG "%s: MGR_DISCONNECT\n", __FUNCTION__);
+		return(mISDN_DisConnectIF(inst, arg));
+#endif
+		case MGR_SELCHANNEL | REQUEST:
+		if (debug & DEBUG_L1OIP_MGR)
+			printk(KERN_DEBUG "%s: MGR_SELCHANNEL\n", __FUNCTION__);
+		if (!dch) {
+			printk(KERN_WARNING "%s(MGR_SELCHANNEL|REQUEST): selchannel not dinst\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+		return(SelFreeBChannel(hc, ch, arg));
+
+		case MGR_SETSTACK | INDICATION:
+		if (debug & DEBUG_L1OIP_MGR)
+			printk(KERN_DEBUG "%s: MGR_SETSTACK\n", __FUNCTION__);
+		if (bch && inst->pid.global==2) {
+			if ((skb = create_link_skb(PH_ACTIVATE | REQUEST, 0, 0, NULL, 0))) {
+				if (hfcmulti_l2l1(inst, skb)) dev_kfree_skb(skb);
+			}
+			if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+			mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION, 0, 0, NULL, 0);
+		else mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION, 0, 0, NULL, 0);
+		}
+		break;
+
+		PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+		PRIM_NOT_HANDLED(MGR_GLOBALOPT | REQUEST);
+		default:
+		printk(KERN_WARNING "%s: prim %x not handled\n", __FUNCTION__, prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+
+/**************************
+ * remove card from stack *
+ **************************/
+
+static void
+release_card(hfc_multi_t *hc)
+{
+	int	i = 0;
+	u_long	flags;
+
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: entered\n", __FUNCTION__);
+
+	if (hc->dch) {
+		if (debug & DEBUG_L1OIP_INIT)
+			printk(KERN_DEBUG "%s: free port %d D-channel %d (1..32)\n", __FUNCTION__, hc->chan[i].port, i);
+		mISDN_free_dch(hc->chan[i].dch);
+		mISDN_ctrl(&hc->chan[i].dch->inst, MGR_UNREGLAYER | REQUEST, NULL);
+		kfree(hc->chan[i].dch);
+		hc->chan[i].dch = NULL;
+	}
+//	if (hc->chan[i].rx_buf) {
+//		kfree(hc->chan[i].rx_buf);
+//		hc->chan[i].rx_buf = NULL;
+//	}
+	i = 0;
+	while(i < 30) {
+		if (hc->bch[i]) {
+			if (debug & DEBUG_L1OIP_INIT)
+				printk(KERN_DEBUG "%s: free port %d B-channel %d (1..32)\n", __FUNCTION__, hc->chan[i].port, hc->bch[i].channel);
+			mISDN_free_bch(hc->bch[i]);
+			kfree(hc->bch[i]);
+			hc->bch[i] = NULL;
+		}
+		i++;
+	}
+
+	/* remove us from list and delete */
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_WARNING "%s: remove instance from list\n", __FUNCTION__);
+	spin_lock_irqsave(&HFCM_obj.lock, flags);
+	list_del(&hc->list);
+	spin_unlock_irqrestore(&HFCM_obj.lock, flags);
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_WARNING "%s: delete instance\n", __FUNCTION__);
+	kfree(hc);
+	HFC_cnt--;
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_WARNING "%s: card successfully removed\n", __FUNCTION__);
+}
+
+static void __exit
+l1oip_cleanup(void)
+{
+	l1oip_t *hc,*next;
+	int err;
+
+	/* unregister mISDN object */
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: entered (refcnt = %d l1oip_cnt = %d)\n", __FUNCTION__, l1oip_obj.refcnt, l1oip_cnt);
+	if ((err = mISDN_unregister(&l1oip_obj))) {
+		printk(KERN_ERR "Can't unregister L1oIP error(%d)\n", err);
+	}
+
+	/* remove remaining devices, but this should never happen */
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: now checking ilist (refcnt = %d)\n", __FUNCTION__, l1oip_obj.refcnt);
+
+	list_for_each_entry_safe(hc, next, &l1oip_obj.ilist, list) {
+		printk(KERN_ERR "L1oIP devices struct not empty refs %d\n", l1oip_obj.refcnt);
+		release_network(hc);
+		release_card(hc);
+	}
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: done (refcnt = %d l1oip_cnt = %d)\n", __FUNCTION__, l1oip_obj.refcnt, l1oip_cnt);
+}
+
+static int __init
+l1oip_init(void)
+{
+	int err, i;
+	char tmpstr[64];
+
+#if !defined(CONFIG_HOTPLUG) || !defined(MODULE)
+#error	"CONFIG_HOTPLUG and MODULE are not defined."
+#endif
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: init entered\n", __FUNCTION__);
+
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+	strcpy(tmpstr, l1oip_revision);
+	printk(KERN_INFO "mISDN: Layer-1-over-IP driver Rev. %s\n", mISDN_getrev(tmpstr));
+
+	memset(&l1oip_obj, 0, sizeof(l1oip_obj));
+#ifdef MODULE
+	l1oip_obj.owner = THIS_MODULE;
+#endif
+	spin_lock_init(&l1oip_obj.lock);
+	INIT_LIST_HEAD(&l1oip_obj.ilist);
+	l1oip_obj.name = l1oipName;
+	l1oip_obj.own_ctrl = l1oip_manager;
+	l1oip_obj.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0 | ISDN_PID_L0_NT_S0
+				| ISDN_PID_L0_TE_E1 | ISDN_PID_L0_NT_E1;
+	l1oip_obj.DPROTO.protocol[1] = ISDN_PID_L1_TE_S0 | ISDN_PID_L1_NT_S0
+				| ISDN_PID_L1_TE_E1 | ISDN_PID_L1_NT_E1;
+	l1oip_obj.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS | ISDN_PID_L1_B_64HDLC;
+	l1oip_obj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS | ISDN_PID_L2_B_RAWDEV;
+
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: registering l1oip_obj\n", __FUNCTION__);
+	if ((err = mISDN_register(&l1oip_obj))) {
+		printk(KERN_ERR "Can't register L1oIP error(%d)\n", err);
+		return(err);
+	}
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: new mISDN object (refcnt = %d)\n", __FUNCTION__, l1oip_obj.refcnt);
+
+	l1oip_cnt = 0;
+
+	/* check card type */
+	switch (type[l1oip_cnt] & 0xff) {
+		case 1:
+		pri = 0;
+		multichannel = 0;
+		break;
+
+		case 2:
+		pri = 1;
+		multichannel = 0;
+		break;
+
+		case 3:
+		pri = 0;
+		multichannel = 1;
+		break;
+
+		case 4:
+		pri = 1;
+		multichannel = 1;
+		break;
+
+		case 0:
+		printk(KERN_INFO "%d virtual devices registered\n", l1oip_cnt);
+		return(0);
+
+		default:
+		printk(KERN_ERR "Card type(%d) not supported.\n", type[HFC_idx] & 0xff);
+		ret_err = -EINVAL;
+		goto free_object;
+	}
+
+
+	/* allocate card+fifo structure */
+	if (!(hc = kmalloc(sizeof(l1oip_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "No kmem for L1-over-IP driver.\n");
+		ret_err = -ENOMEM;
+		goto free_object;
+	}
+	memset(hc, 0, sizeof(hfc_multi_t));
+	hc->idx = l1oip_cnt;
+	hc->pri = pri;
+	hc->multichannel = multichannel;
+	hc->limit = limit[l1oip_cnt];
+
+	if (hc->pri)
+		sprintf(hc->name, "L1oIP-E1#%d", HFC_cnt+1);
+	else
+		sprintf(hc->name, "L1oIP-S0#%d", HFC_cnt+1);
+
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__);
+	
+	spin_lock_irqsave(&HFCM_obj.lock, flags);
+	list_add_tail(&hc->list, &HFCM_obj.ilist);
+	spin_unlock_irqrestore(&HFCM_obj.lock, flags);
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__);
+
+	spin_lock_init(&hc->lock);
+
+	/* check codec */
+	switch (codec[l1oip_cnt]) {
+		case 0:
+		break;
+
+		case 1:
+		hc->ulaw = 1;
+		break;
+
+		case 2:
+		hc->tadpcm = 1;
+		break;
+
+		case 3:
+		hc->ulaw = 1;
+		hc->tadpcm = 1;
+		break;
+
+		default:
+		printk(KERN_ERR "Codec(%d) not supported.\n", codec[l1oip_cnt]);
+		ret_err = -EINVAL;
+		goto free_channels;
+	}
+
+	if (id[l1oip_cnt] == 0) {
+		printk(KERN_ERR "No 'id' value given. Please use 32 bit randmom number 0x...\n");
+		ret_err = -EINVAL;
+		goto free_channels;
+	}
+
+	/* check protocol */
+	if (protocol[l1oip_cnt] == 0) {
+		printk(KERN_ERR "No 'protocol' value given.\n");
+		ret_err = -EINVAL;
+		goto free_channels;
+	}
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: Registering D-channel, card(%d) protocol(%x)\n", __FUNCTION__, l1oip_cnt+1, protocol[l1oip_cnt]);
+	dch = kmalloc(sizeof(dchannel_t), GFP_ATOMIC);
+	if (!dch) {
+		ret_err = -ENOMEM;
+		goto free_channels;
+	}
+	memset(dch, 0, sizeof(dchannel_t));
+	if (hc->pri)
+		dch->channel = 16;
+	//dch->debug = debug;
+	dch->inst.obj = &l1oip_obj;
+	dch->inst.hwlock = &hc->lock;
+	dch->inst.class_dev.dev = &pdev->dev;
+	mISDN_init_instance(&dch->inst, &l1oip_obj, hc, l1oip_dchannel);
+	dch->inst.pid.layermask = ISDN_LAYER(0);
+	sprintf(dch->inst.name, "L1OIP%d", l1oip_cnt);
+//	if (!(hc->chan[ch].rx_buf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
+//		ret_err = -ENOMEM;
+//		goto free_channels;
+//	}
+	if (mISDN_init_dch(dch)) {
+		ret_err = -ENOMEM;
+		goto free_channels;
+	}
+	hc->dch = dch;
+
+	i=0;
+	while(i < ((hc->pri)?30:2)) {
+		if (hc->pri)
+			ch = i + 1 + (i>=15);
+		else
+			ch = i + 1;
+		if (debug & DEBUG_L1OIP_INIT)
+			printk(KERN_DEBUG "%s: Registering B-channel, card(%d) channel(%d)\n", __FUNCTION__, l1oip_cnt, ch);
+		bch = kmalloc(sizeof(bchannel_t), GFP_ATOMIC);
+		if (!bch) {
+			ret_err = -ENOMEM;
+			goto free_channels;
+		}
+		memset(bch, 0, sizeof(bchannel_t));
+		bch->channel = ch;
+		mISDN_init_instance(&bch->inst, &l1oip_obj, hc, l1oip_bchannel);
+		bch->inst.pid.layermask = ISDN_LAYER(0);
+		bch->inst.hwlock = &hc->lock;
+		bch->inst.class_dev.dev = &pdev->dev;
+		//bch->debug = debug;
+		sprintf(bch->inst.name, "%s B%d",
+			dch->inst.name, i+1);
+		if (mISDN_init_bch(bch)) {
+			kfree(bch);
+			ret_err = -ENOMEM;
+			goto free_channels;
+		}
+		hc->bch[i] = bch;
+#ifdef FIXME  // TODO
+		if (bch->dev) {
+			bch->dev->wport.pif.func = l1oip_bchannel;
+			bch->dev->wport.pif.fdata = bch;
+		}
+#endif
+		i++;
+	}
+
+	/* set D-channel */
+	mISDN_set_dchannel_pid(&pid, protocol[l1oip_cnt], layermask[l1oip_cnt]);
+
+	/* set PRI */
+	if (hc->pri == 1) {
+		if (layermask[l1oip_cnt] & ISDN_LAYER(2)) {
+			pid.protocol[2] |= ISDN_PID_L2_DF_PTP;
+		}
+		if (layermask[l1oip_cnt] & ISDN_LAYER(3)) {
+			pid.protocol[3] |= ISDN_PID_L3_DF_PTP;
+			pid.protocol[3] |= ISDN_PID_L3_DF_EXTCID;
+			pid.protocol[3] |= ISDN_PID_L3_DF_CRLEN2;
+		}
+	}
+
+	/* set protocol type */
+	dch->inst.pid.protocol[0] = (hc->pri)?ISDN_PID_L0_IP_E1:ISDN_PID_L0_IP_S0;
+	pid.protocol[0] = (hc->pri)?ISDN_PID_L0_IP_E1:ISDN_PID_L0_IP_S0;
+	if (protocol[l1oip_cnt] & 0x10) {
+		/* NT-mode */
+		dch->inst.pid.protocol[1] = (hc->pri)?ISDN_PID_L1_NT_E1:ISDN_PID_L1_NT_S0;
+		pid.protocol[1] = (hc->pri)?ISDN_PID_L1_NT_E1:ISDN_PID_L1_NT_S0;
+		if (layermask[l1oip_cnt] & ISDN_LAYER(2))
+			pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
+	} else {
+		/* TE-mode */
+		dch->inst.pid.protocol[1] = (hc->pri)?ISDN_PID_L1_TE_E1:ISDN_PID_L1_TE_S0;
+		pid.protocol[1] = (hc->pri)?ISDN_PID_L1_TE_E1:ISDN_PID_L1_TE_S0;
+	}
+	dch->inst.pid.layermask |= ISDN_LAYER(1);
+	pid.layermask |= ISDN_LAYER(1);
+
+
+	/* run card setup */
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: Setting up network(%d)\n", __FUNCTION__, l1oip_cnt+1);
+	if ((ret_err = setup_network(hc))) {
+		goto free_channels;
+	}
+	/* add stacks */
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: Adding d-stack: card(%d)\n", __FUNCTION__, l1oip_cnt+1);
+	if ((ret_err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &dch->inst))) {
+		printk(KERN_ERR  "MGR_ADDSTACK REQUEST dch err(%d)\n", ret_err);
+		free_release:
+		release_network(hc);
+		goto free_object;
+	}
+	dst = dch->inst.st;
+	i=0;
+	while(i < ((hc->pri)?30:2)) {
+		bch = hc->bch;
+		if (debug & DEBUG_L1OIP_INIT)
+			printk(KERN_DEBUG "%s: Adding b-stack: card(%d) B-channel(%d)\n", __FUNCTION__, l1oip_cnt+1, bch->channel);
+		if ((ret_err = mISDN_ctrl(dst, MGR_NEWSTACK | REQUEST, &bch->inst))) {
+			printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", ret_err);
+			free_delstack:
+			mISDN_ctrl(dst, MGR_DELSTACK | REQUEST, NULL);
+			goto free_release;
+		}
+		bch->st = bch->inst.st;
+		i++;
+	}
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: (before MGR_SETSTACK REQUEST) layermask=0x%x\n", __FUNCTION__, pids[pt].layermask);
+
+	if ((ret_err = mISDN_ctrl(dst, MGR_SETSTACK | REQUEST, &pids[pt]))) {
+		printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", ret_err);
+		goto free_delstack;
+	}
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: (after MGR_SETSTACK REQUEST)\n", __FUNCTION__);
+
+	/* delay some time */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((100*HZ)/1000); /* Timeout 100ms */
+
+	/* tell stack, that we are ready */
+	mISDN_ctrl(dst, MGR_CTRLREADY | INDICATION, NULL);
+
+	HFC_cnt++;
+	goto next_card;
+
+	/* if an error ocurred */
+
+	free_channels:
+	if (hc->dch) {
+		if (debug & DEBUG_L1OIP_INIT)
+			printk(KERN_DEBUG "%s: free D-channel %d (1..32)\n", __FUNCTION__, i);
+		mISDN_free_dch(hc->dch);
+		kfree(hc->dch);
+		hc->dch = NULL;
+	}
+//	if (hc->rx_buf) {
+//		kfree(hc->rx_buf);
+//		hc->rx_buf = NULL;
+//	}
+	i = 0;
+	while(i < 30) {
+		if (hc->bch[i]) {
+			if (debug & DEBUG_L1OIP_INIT)
+				printk(KERN_DEBUG "%s: free B-channel %d (1..32)\n", __FUNCTION__, hc->bch[i].channel);
+			mISDN_free_bch(hc->bch[i]);
+			kfree(hc->bch[i]);
+			hc->bch[i] = NULL;
+		}
+		i++;
+	}
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: before REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, l1oip_obj.refcnt);
+	spin_lock_irqsave(&l1oip_obj.lock, flags);
+	list_del(&hc->list);
+	spin_unlock_irqrestore(&l1oip_obj.lock, flags);
+	if (debug & DEBUG_L1OIP_INIT)
+		printk(KERN_DEBUG "%s: after REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, l1oip_obj.refcnt);
+	kfree(hc);
+
+	free_object:
+	l1oip_cleanup();
+	return(ret_err);
+}
+
+
+#ifdef MODULE
+module_init(l1oip_init);
+module_exit(l1oip_cleanup);
+#endif
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l3_udss1.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l3_udss1.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l3_udss1.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,3185 @@
+/* $Id: l3_udss1.c,v 1.47 2007/01/10 12:56:45 crich Exp $
+ *
+ * EURO/DSS1 D-channel protocol
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ *		This file is (c) under GNU  PUBLIC LICENSE
+ *		For changes and modifications please read
+ *		../../../Documentation/isdn/mISDN.cert
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ */
+
+#include <linux/module.h>
+
+#include "core.h"
+#include "layer3.h"
+#include "helper.h"
+#include "debug.h"
+#include "dss1.h"
+
+static int debug = 0;
+static mISDNobject_t u_dss1;
+
+
+const char *dss1_revision = "$Revision: 1.47 $";
+
+
+static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1};
+
+
+static int dss1man(l3_process_t *, u_int, void *);
+
+static int
+parseQ931(struct sk_buff *skb) {
+	Q931_info_t	*qi;
+	int		l, codeset, maincodeset;
+	int		len, iep, pos = 0, cnt = 0, eidx = -1;
+	u16		cr;
+	ie_info_t	*ie, *old;
+	u_char		t, *p = skb->data;
+
+	if (skb->len < 3)
+		return(-1);
+	p++;
+	l = (*p++) & 0xf;
+	if (l>2)
+		return(-2);
+	if (l)
+		cr = *p++;
+	else
+		cr = 0;
+	if (l == 2) {
+		cr <<= 8;
+		cr |= *p++;
+	} else if (l == 1)
+		if (cr & 0x80) {
+			cr |= 0x8000;
+			cr &= 0xFF7F;
+		}
+	t = *p;
+	if ((u_long)p & 1)
+		pos = 1;
+	else
+		pos = 0;
+	skb_pull(skb, (p - skb->data) - pos);
+	len = skb->len;
+	p = skb->data;
+	if (skb_headroom(skb) < (int)L3_EXTRA_SIZE) {
+		int_error();
+		return(-3);
+	}
+	qi = (Q931_info_t *)skb_push(skb, L3_EXTRA_SIZE);
+	mISDN_initQ931_info(qi);
+	qi->type = t;
+	qi->crlen = l;
+	qi->cr = cr;
+	pos++;
+	codeset = maincodeset = 0;
+	ie = &qi->bearer_capability;
+	while (pos < len) {
+
+		
+		if ((p[pos] & 0xf0) == 0x90) {
+			codeset = p[pos] & 0x07;
+			if (!(p[pos] & 0x08))
+				maincodeset = codeset;
+			if (eidx >= 0) {
+				qi->ext[eidx].cs.len = pos - qi->ext[eidx].ie.off;
+				eidx = -1;
+			}
+			pos++;
+			continue;
+		}
+		if (codeset == 0) {
+			if (p[pos] & 0x80) { /* single octett IE */
+				if (p[pos] == IE_MORE_DATA)
+					qi->more_data.off = pos;
+				else if (p[pos] == IE_COMPLETE) {
+					qi->sending_complete.off = pos;
+				}
+				else if ((p[pos] & 0xf0) == IE_CONGESTION)
+					qi->congestion_level.off = pos;
+				else {
+					printk("parseQ931: Unknown Single Oct IE [%x]\n",p[pos]);
+				}
+				cnt++;
+				pos++;
+			} else {
+				t = p[pos];
+				iep = mISDN_l3_ie2pos(t);
+				if ((pos+1) >= len)
+					return(-4);
+				l = p[pos+1];
+				if ((pos+l+1) >= len)
+					return(-5);
+				if (iep>=0) {
+					if (!ie[iep].off) { /* IE not detected before */
+						ie[iep].off = pos;
+					} else { /* IE is repeated */
+						old = &ie[iep];
+						if (old->repeated)
+							old = mISDN_get_last_repeated_ie(qi, old);
+						if (!old) {
+							int_error();
+							return(-6);
+						}
+						eidx = mISDN_get_free_ext_ie(qi);
+						if (eidx < 0) {
+							int_error();
+							return(-7);
+						}
+						old->ridx = eidx;
+						old->repeated = 1;
+						qi->ext[eidx].ie.off = pos;
+						qi->ext[eidx].v.codeset = 0;
+						qi->ext[eidx].v.val = t;
+						eidx = -1;
+					}
+				} else {
+					int i;
+					for (i=0; comp_required[i] > 0; i++) {
+						if ( p[pos] == comp_required[i] && l==1 ) {
+							qi->comprehension_required.off = pos;
+						} 
+					}
+					if (!qi->comprehension_required.off)
+						printk(" ie not handled ie [%x] l [%x]\n", p[pos],l);
+				}
+				pos += l + 2;
+				cnt++;
+			}
+		} else { /* codeset != 0 */
+			if (eidx < 0) {
+				eidx = mISDN_get_free_ext_ie(qi);
+				if (eidx < 0) {
+					int_error();
+					return(-8);
+				}
+				qi->ext[eidx].cs.codeset = codeset;
+				qi->ext[eidx].ie.off = pos;
+				qi->ext[eidx].ie.cs_flg = 1;
+				if (codeset == maincodeset) { /* locked shift */
+					qi->ext[eidx].cs.locked = 1;
+				}
+			}
+			if (p[pos] & 0x80) { /* single octett IE */
+				cnt++;
+				pos++;
+			} else {
+				if ((pos+1) >= len)
+					return(-4);
+				l = p[pos+1];
+				if ((pos+l+1) >= len)
+					return(-5);
+				pos += l + 2;
+				cnt++;
+			}
+			if (qi->ext[eidx].cs.locked == 0) {/* single IE codeset shift */
+				qi->ext[eidx].cs.len = pos - qi->ext[eidx].ie.off;
+				eidx = -1;
+			}
+		}
+		codeset = maincodeset;
+	}
+	if (eidx >= 0)
+		qi->ext[eidx].cs.len = pos - qi->ext[eidx].ie.off;
+	return(cnt);
+}
+
+static int
+calc_msg_len(Q931_info_t *qi)
+{
+	int		i, cnt = 0;
+	u_char		*buf = (u_char *)qi;
+	ie_info_t	*ie;
+
+	buf += L3_EXTRA_SIZE;
+	if (qi->more_data.off)
+		cnt++;
+	if (qi->sending_complete.off)
+		cnt++;
+	if (qi->congestion_level.off)
+		cnt++;
+	ie = &qi->bearer_capability;
+	while (ie <= &qi->comprehension_required) {
+		if (ie->off)
+			cnt += buf[ie->off + 1] + 2;
+		ie++;
+	}
+	for (i = 0; i < 8; i++) {
+		if (qi->ext[i].ie.off) {
+			if (qi->ext[i].ie.cs_flg == 1) { /* other codset info chunk */
+				cnt++; /* codeset shift IE */
+				cnt += qi->ext[i].cs.len;
+			} else { /* repeated IE */
+				cnt += buf[qi->ext[i].ie.off + 1] + 2;
+			}
+		}
+	}
+	return(cnt);
+}
+
+static int
+compose_msg(struct sk_buff *skb, Q931_info_t *qi)
+{
+	int		i, l, ri;
+	u_char		*p, *buf = (u_char *)qi;
+	ie_info_t	*ie;
+
+	buf += L3_EXTRA_SIZE;
+
+	if (qi->more_data.off) {
+		p = skb_put(skb, 1);
+		*p = buf[qi->more_data.off];
+	}
+	if (qi->sending_complete.off) {
+		p = skb_put(skb, 1);
+		*p = buf[qi->sending_complete.off];
+	}
+	if (qi->congestion_level.off) {
+		p = skb_put(skb, 1);
+		*p = buf[qi->congestion_level.off];
+	}
+	ie = &qi->bearer_capability;
+	for (i=0; i<33; i++) {
+		if (ie[i].off) {
+			l = buf[ie[i].off + 1] +1;
+			p = skb_put(skb, l + 1);
+			*p++ = mISDN_l3_pos2ie(i);
+			memcpy(p, &buf[ie[i].off + 1], l);
+			if (ie[i].repeated) {
+				ri = ie[i].ridx;
+				while(ri >= 0) {
+					l = buf[qi->ext[ri].ie.off + 1] +1;
+					p = skb_put(skb, l + 1);
+					if (mISDN_l3_pos2ie(i) != qi->ext[ri].v.val)
+						int_error();
+					*p++ = qi->ext[ri].v.val;
+					memcpy(p, &buf[qi->ext[ri].ie.off + 1], l);
+					if (qi->ext[ri].ie.repeated)
+						ri = qi->ext[ri].ie.ridx;
+					else
+						ri = -1;
+				}
+			}
+		}
+	}
+	for (i=0; i<8; i++) {
+		/* handle other codeset elements */
+		if (qi->ext[i].ie.cs_flg == 1) {
+			p = skb_put(skb, 1); /* shift codeset IE */
+			if (qi->ext[i].cs.locked == 1)
+				*p = 0x90 | qi->ext[i].cs.codeset;
+			else /* non-locking shift */
+				*p = 0x98 | qi->ext[i].cs.codeset;
+			p = skb_put(skb, qi->ext[i].cs.len);
+			memcpy(p, &buf[qi->ext[i].ie.off], qi->ext[i].cs.len);
+		}
+	}
+	return(0);
+}
+
+static struct sk_buff
+*MsgStart(l3_process_t *pc, u_char mt, int len) {
+	struct sk_buff	*skb;
+	int		lx = 4;
+	u_char		*p;
+
+	if (test_bit(FLG_CRLEN2, &pc->l3->Flag))
+		lx++;
+	if (pc->callref == -1) /* dummy cr */
+		lx = 3;
+	if (!(skb = alloc_stack_skb(len + lx, pc->l3->down_headerlen)))
+		return(NULL);
+	p = skb_put(skb, lx);
+	*p++ = 8;
+	if (lx == 3)
+		*p++ = 0;
+	else if (lx == 5) {
+		*p++ = 2;
+		*p++ = (pc->callref >> 8)  ^ 0x80;
+		*p++ = pc->callref & 0xff;
+	} else {
+		*p++ = 1;
+		*p = pc->callref & 0xff;
+		if (!(pc->callref & 0x8000))
+			*p |= 0x80;
+		p++;
+	}
+	*p = mt;
+	return(skb);
+}
+
+static int SendMsg(l3_process_t *pc, struct sk_buff *skb, int state) {
+	int		l;
+	int		ret;
+	struct sk_buff	*nskb;
+	Q931_info_t	*qi;
+
+	if (!skb)
+		return(-EINVAL);
+	qi = (Q931_info_t *)skb->data;
+	l = calc_msg_len(qi);
+	if (!(nskb = MsgStart(pc, qi->type, l))) {
+		kfree_skb(skb);
+		return(-ENOMEM);
+	}
+	if (l)
+		compose_msg(nskb, qi);
+	kfree_skb(skb);
+	if (state != -1)
+		newl3state(pc, state);
+	if ((ret=l3_msg(pc->l3, DL_DATA | REQUEST, 0, 0, nskb)))
+		kfree_skb(nskb);
+	return(ret);
+}
+
+static int
+l3dss1_message(l3_process_t *pc, u_char mt)
+{
+	struct sk_buff	*skb;
+	int		ret;
+
+	if (!(skb = MsgStart(pc, mt, 0)))
+		return(-ENOMEM);
+	if ((ret=l3_msg(pc->l3, DL_DATA | REQUEST, 0, 0, skb)))
+		kfree_skb(skb);
+	return(ret);
+}
+
+static void
+l3dss1_message_cause(l3_process_t *pc, u_char mt, u_char cause)
+{
+	struct sk_buff	*skb;
+	u_char		*p;
+	int		ret;
+
+	if (!(skb = MsgStart(pc, mt, 4)))
+		return;
+	p = skb_put(skb, 4);
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80 | CAUSE_LOC_USER;
+	*p++ = 0x80 | cause;
+	if ((ret=l3_msg(pc->l3, DL_DATA | REQUEST, 0, 0, skb)))
+		kfree_skb(skb);
+}
+
+static void
+l3dss1_status_send(l3_process_t *pc, u_char cause)
+{
+	struct sk_buff	*skb;
+	u_char		*p;
+	int		ret;
+
+	if (!(skb = MsgStart(pc, MT_STATUS, 7)))
+		return;
+	p = skb_put(skb, 7);
+	*p++ = IE_CAUSE;
+	*p++ = 2;
+	*p++ = 0x80 | CAUSE_LOC_USER;
+	*p++ = 0x80 | cause;
+
+	*p++ = IE_CALL_STATE;
+	*p++ = 1;
+	*p++ = pc->state & 0x3f;
+	if ((ret=l3_msg(pc->l3, DL_DATA | REQUEST, 0, 0, skb)))
+		kfree_skb(skb);
+}
+
+static void
+l3dss1_msg_without_setup(l3_process_t *pc, u_char cause)
+{
+	/* This routine is called if here was no SETUP made (checks in dss1up and in
+	 * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code
+	 * MT_STATUS_ENQUIRE in the NULL state is handled too
+	 */
+	switch (cause) {
+		case 81:	/* invalid callreference */
+		case 88:	/* incomp destination */
+		case 96:	/* mandory IE missing */
+		case 100:       /* invalid IE contents */
+		case 101:	/* incompatible Callstate */
+			l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
+			break;
+		default:
+			printk(KERN_ERR "mISDN l3dss1_msg_without_setup wrong cause %d\n",
+				cause);
+	}
+	release_l3_process(pc);
+}
+
+static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
+		IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_REDIR_DN,
+		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_REDIR_DN, IE_HLC, -1};
+static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
+		IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL,
+		IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
+static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
+static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
+		IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
+static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
+		IE_CALLED_PN, -1};
+static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
+		IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
+static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
+		IE_SIGNAL, IE_USER_USER, -1};
+/* a RELEASE_COMPLETE with errors don't require special actions
+static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY,
+		IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
+*/
+static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY,
+		IE_DISPLAY, -1};
+static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER  | IE_MANDATORY,
+		IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
+		IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
+		IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
+		IE_LLC, IE_HLC, IE_USER_USER, -1};
+static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
+		IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
+static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
+		IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
+static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_FACILITY, IE_DISPLAY, -1};
+static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_HOLD[] = {IE_DISPLAY, -1};
+static int ie_HOLD_ACKNOWLEDGE[] = {IE_DISPLAY, -1};
+static int ie_HOLD_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_RETRIEVE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_RETRIEVE_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_RETRIEVE_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+/* not used
+ * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY,
+ *		IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+ * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1};
+ * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND |
+ *		IE_MANDATORY, -1};
+ */
+static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1};
+
+static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1};
+
+struct ie_len {
+	int ie;
+	int len;
+};
+
+static
+struct ie_len max_ie_len[] = {
+	{IE_SEGMENT, 4},
+	{IE_BEARER, 12},
+	{IE_CAUSE, 32},
+	{IE_CALL_ID, 10},
+	{IE_CALL_STATE, 3},
+	{IE_CHANNEL_ID,	34},
+	{IE_FACILITY, 255},
+	{IE_PROGRESS, 4},
+	{IE_NET_FAC, 255},
+	{IE_NOTIFY, 255}, /* 3-* Q.932 Section 9 */
+	{IE_DISPLAY, 82},
+	{IE_DATE, 8},
+	{IE_KEYPAD, 34},
+	{IE_SIGNAL, 3},
+	{IE_INFORATE, 6},
+	{IE_E2E_TDELAY, 11},
+	{IE_TDELAY_SEL, 5},
+	{IE_PACK_BINPARA, 3},
+	{IE_PACK_WINSIZE, 4},
+	{IE_PACK_SIZE, 4},
+	{IE_CUG, 7},
+	{IE_REV_CHARGE, 3},
+	{IE_CALLING_PN, 24},
+	{IE_CALLING_SUB, 23},
+	{IE_CALLED_PN, 24},
+	{IE_CALLED_SUB, 23},
+	{IE_REDIR_NR, 255},
+	{IE_REDIR_DN, 255},
+	{IE_TRANS_SEL, 255},
+	{IE_RESTART_IND, 3},
+	{IE_LLC, 18},
+	{IE_HLC, 5},
+	{IE_USER_USER, 131},
+	{-1,0},
+};
+
+static int
+getmax_ie_len(u_char ie) {
+	int i = 0;
+	while (max_ie_len[i].ie != -1) {
+		if (max_ie_len[i].ie == ie)
+			return(max_ie_len[i].len);
+		i++;
+	}
+	return(255);
+}
+
+static int
+ie_in_set(l3_process_t *pc, u_char ie, int *checklist) {
+	int ret = 1;
+
+	while (*checklist != -1) {
+		if ((*checklist & 0xff) == ie) {
+			if (ie & 0x80)
+				return(-ret);
+			else
+				return(ret);
+		}
+		ret++;
+		checklist++;
+	}
+	return(0);
+}
+
+static int
+check_infoelements(l3_process_t *pc, struct sk_buff *skb, int *checklist)
+{
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	int		*cl = checklist;
+	u_char		*p, ie;
+	ie_info_t	*iep;
+	int		i, l, newpos, oldpos;
+	int		err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
+
+	p = skb->data;
+	p += L3_EXTRA_SIZE;
+	iep = &qi->bearer_capability;
+	oldpos = -1;
+
+	for (i=0; i<33; i++) {
+		if (iep[i].off) {
+			ie = mISDN_l3_pos2ie(i);
+			if ((newpos = ie_in_set(pc, ie, cl))) {
+				if (newpos > 0) {
+					if (newpos < oldpos)
+						err_seq++;
+					else
+						oldpos = newpos;
+				} else {
+					printk(KERN_NOTICE "ie_in_set returned <0  [%d] ie:[%x]\n",newpos,ie);
+				}
+			} else {
+				if (debug) printk(KERN_NOTICE "Found ie in set which we do not support ie [%x]\n",ie);
+				if (ie_in_set(pc, ie, comp_required))
+					err_compr++;
+				else
+					err_ureg++;
+			}
+			l = p[iep[i].off +1];
+			if (l > getmax_ie_len(ie))
+				err_len++;
+		}
+	}
+
+	if (qi->comprehension_required.off) {
+		if ( ! (p[qi->comprehension_required.off +2] &0xf) ) {
+			err_compr++;
+		}
+	}
+	
+	if (err_compr | err_ureg | err_len | err_seq) {
+		if (pc->l3->debug & L3_DEB_CHECK)
+			l3_debug(pc->l3, "check IE MT(%x) %d/%d/%d/%d",
+				qi->type, err_compr, err_ureg, err_len, err_seq);
+		if (err_compr)
+			return(ERR_IE_COMPREHENSION);
+		if (err_ureg)
+			return(ERR_IE_UNRECOGNIZED);
+		if (err_len)
+			return(ERR_IE_LENGTH);
+		if (err_seq)
+			return(ERR_IE_SEQUENCE);
+	}
+	return(0);
+}
+
+/* verify if a message type exists and contain no IE error */
+static int
+l3dss1_check_messagetype_validity(l3_process_t *pc, int mt, void *arg)
+{
+	switch (mt) {
+		case MT_ALERTING:
+		case MT_CALL_PROCEEDING:
+		case MT_CONNECT:
+		case MT_CONNECT_ACKNOWLEDGE:
+		case MT_DISCONNECT:
+		case MT_INFORMATION:
+		case MT_FACILITY:
+		case MT_NOTIFY:
+		case MT_PROGRESS:
+		case MT_RELEASE:
+		case MT_RELEASE_COMPLETE:
+		case MT_SETUP:
+		case MT_SETUP_ACKNOWLEDGE:
+		case MT_RESUME_ACKNOWLEDGE:
+		case MT_RESUME_REJECT:
+		case MT_SUSPEND_ACKNOWLEDGE:
+		case MT_SUSPEND_REJECT:
+		case MT_USER_INFORMATION:
+		case MT_RESTART:
+		case MT_RESTART_ACKNOWLEDGE:
+		case MT_CONGESTION_CONTROL:
+		case MT_STATUS:
+		case MT_STATUS_ENQUIRY:
+		case MT_HOLD:
+		case MT_HOLD_ACKNOWLEDGE:
+		case MT_HOLD_REJECT:
+		case MT_RETRIEVE:
+		case MT_RETRIEVE_ACKNOWLEDGE:
+		case MT_RETRIEVE_REJECT:
+			if (pc->l3->debug & L3_DEB_CHECK)
+				l3_debug(pc->l3, "l3dss1_check_messagetype_validity mt(%x) OK", mt);
+			break;
+		case MT_RESUME: /* RESUME only in user->net */
+		case MT_SUSPEND: /* SUSPEND only in user->net */
+		default:
+			if (pc->l3->debug & (L3_DEB_CHECK | L3_DEB_WARN))
+				l3_debug(pc->l3, "l3dss1_check_messagetype_validity mt(%x) fail", mt);
+			l3dss1_status_send(pc, CAUSE_MT_NOTIMPLEMENTED);
+			return(1);
+	}
+	return(0);
+}
+
+static void
+l3dss1_std_ie_err(l3_process_t *pc, int ret) {
+
+	if (pc->l3->debug & L3_DEB_CHECK)
+		l3_debug(pc->l3, "check_infoelements ret %d", ret);
+	switch(ret) {
+		case 0:
+			break;
+		case ERR_IE_COMPREHENSION:
+			l3dss1_status_send(pc, CAUSE_MANDATORY_IE_MISS);
+			break;
+		case ERR_IE_UNRECOGNIZED:
+			l3dss1_status_send(pc, CAUSE_IE_NOTIMPLEMENTED);
+			break;
+		case ERR_IE_LENGTH:
+			l3dss1_status_send(pc, CAUSE_INVALID_CONTENTS);
+			break;
+		case ERR_IE_SEQUENCE:
+		default:
+			break;
+	}
+}
+
+static int
+l3dss1_get_channel_id(l3_process_t *pc, struct sk_buff *skb) {
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	u_char		*p;
+
+	if (qi->channel_id.off) {
+		p = skb->data;
+		p += L3_EXTRA_SIZE + qi->channel_id.off;
+		p++;
+		if (test_bit(FLG_EXTCID, &pc->l3->Flag)) {
+			if (*p != 1) {
+				pc->bc = 1;
+				pc->real_bc=p[3];
+				return (0);
+			}
+		}
+		if (*p != 1) { /* len for BRI = 1 */
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "wrong chid len %d", *p);
+			return (-2);
+		}
+		p++;
+		if (*p & 0x60) { /* only base rate interface */
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "wrong chid %x", *p);
+			return (-3);
+		}
+		pc->bc = *p & 3;
+		pc->real_bc=pc->bc;
+	} else
+		return(-1);
+	return(0);
+}
+
+static int
+l3dss1_get_cause(l3_process_t *pc, struct sk_buff *skb) {
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	u_char		l;
+	u_char		*p;
+
+	if (qi->cause.off) {
+		p = skb->data;
+		p += L3_EXTRA_SIZE + qi->cause.off;
+		p++;
+		l = *p++;
+		if (l>30) {
+			return(-30);
+		}
+		if (l)
+			l--;
+		else {
+			return(-2);
+		}
+		if (l && !(*p & 0x80)) {
+			l--;
+			p++; /* skip recommendation */
+		}
+		p++;
+		if (l) {
+			if (!(*p & 0x80)) {
+				return(-3);
+			}
+			pc->err = *p & 0x7F;
+		} else {
+			return(-4);
+		}
+	} else
+		return(-1);
+	return(0);
+}
+
+static void
+l3dss1_release_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	StopAllL3Timer(pc);
+	if (arg) {
+		SendMsg(pc, arg, 19);
+	} else {
+		newl3state(pc, 19);
+		l3dss1_message(pc, MT_RELEASE);
+	}
+	L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3dss1_setup_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = skb_clone(arg, GFP_ATOMIC);
+
+	if (!SendMsg(pc, arg, 1)) {
+		L3DelTimer(&pc->timer);
+		L3AddTimer(&pc->timer, T303, CC_T303);
+		pc->t303skb = skb;
+	} else
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_disconnect_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	Q931_info_t	*qi;
+	u_char		*p;
+
+	StopAllL3Timer(pc);
+	if (arg) {
+		qi = (Q931_info_t *)skb->data;
+		if (!qi->cause.off) {
+			qi->cause.off = skb->len - L3_EXTRA_SIZE;
+			p = skb_put(skb, 4);
+			*p++ = IE_CAUSE;
+			*p++ = 2;
+			*p++ = 0x80 | CAUSE_LOC_USER;
+			*p++ = 0x80 | CAUSE_NORMALUNSPECIFIED;
+			pc->cause=CAUSE_NORMALUNSPECIFIED;
+		} else {
+			p=skb->data;
+			p += L3_EXTRA_SIZE + qi->cause.off;
+			pc->cause = (*(p+3) & 0x7f);
+		}
+		SendMsg(pc, arg, 11);
+	} else {
+		newl3state(pc, 11);
+		l3dss1_message_cause(pc, MT_DISCONNECT, CAUSE_NORMALUNSPECIFIED);
+		pc->cause=CAUSE_NORMALUNSPECIFIED;
+	}
+	L3AddTimer(&pc->timer, T305, CC_T305);
+}
+
+static void
+l3dss1_connect_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (!pc->bc) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "D-chan connect for waiting call");
+		l3dss1_disconnect_req(pc, pr, NULL);
+		return;
+	}
+	if (arg) {
+		SendMsg(pc, arg, 8);
+	} else {
+		newl3state(pc, 8);
+		l3dss1_message(pc, MT_CONNECT);
+	}
+	L3DelTimer(&pc->timer);
+	L3AddTimer(&pc->timer, T313, CC_T313);
+}
+
+static void
+l3dss1_release_cmpl_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	StopAllL3Timer(pc);
+	if (arg) {
+		SendMsg(pc, arg, 0);
+	} else {
+		newl3state(pc, 0);
+		l3dss1_message(pc, MT_RELEASE_COMPLETE);
+	}
+	mISDN_l3up(pc, CC_RELEASE_COMPLETE | CONFIRM, NULL);
+	release_l3_process(pc);
+}
+
+static void
+l3dss1_alert_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (arg) {
+		SendMsg(pc, arg, 7);
+	} else {
+		newl3state(pc, 7);
+		l3dss1_message(pc, MT_ALERTING);
+	}
+	L3DelTimer(&pc->timer);
+}
+
+static void
+l3dss1_proceed_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (arg) {
+		SendMsg(pc, arg, 9);
+	} else {
+		newl3state(pc, 9);
+		l3dss1_message(pc, MT_CALL_PROCEEDING);
+	}
+	L3DelTimer(&pc->timer);
+}
+
+static void
+l3dss1_setup_ack_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (arg) {
+		SendMsg(pc, arg, 25);
+	} else {
+		newl3state(pc, 25);
+		l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE);
+	}
+	L3DelTimer(&pc->timer);
+	L3AddTimer(&pc->timer, T302, CC_T302);
+}
+
+static void
+l3dss1_suspend_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (arg) {
+		SendMsg(pc, arg, 15);
+	} else {
+		newl3state(pc, 15);
+		l3dss1_message(pc, MT_SUSPEND);
+	}
+	L3AddTimer(&pc->timer, T319, CC_T319);
+}
+
+static void
+l3dss1_resume_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (arg) {
+		SendMsg(pc, arg, 17);
+	} else {
+		newl3state(pc, 17);
+		l3dss1_message(pc, MT_RESUME);
+	}
+	L3AddTimer(&pc->timer, T318, CC_T318);
+}
+
+static void
+l3dss1_status_enq_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (arg)
+		dev_kfree_skb(arg);
+	l3dss1_message(pc, MT_STATUS_ENQUIRY);
+}
+
+static void
+l3dss1_information_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (pc->state == 2) {
+		L3DelTimer(&pc->timer);
+		L3AddTimer(&pc->timer, T304, CC_T304);
+	}
+
+	if (arg) {
+		SendMsg(pc, arg, -1);
+	}
+}
+
+static void
+l3dss1_notify_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (arg) {
+		SendMsg(pc, arg, -1);
+	}
+}
+
+static void
+l3dss1_progress_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (arg) {
+		SendMsg(pc, arg, -1);
+	}
+}
+
+static void
+l3dss1_facility_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (arg) {
+		SendMsg(pc, arg, -1);
+	}
+}
+
+static void
+l3dss1_restart_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	pc->callref=0;
+	if (arg) {
+		SendMsg(pc, arg, -1);
+	}
+	pc->callref=-1;
+}
+
+static void
+l3dss1_release_cmpl(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+
+	StopAllL3Timer(pc);
+	newl3state(pc, 0);
+	if (mISDN_l3up(pc, CC_RELEASE_COMPLETE | INDICATION, skb))
+		dev_kfree_skb(skb);
+	release_l3_process(pc);
+}
+
+static void
+l3dss1_alerting(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int ret;
+
+	ret = check_infoelements(pc, skb, ie_ALERTING);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	L3DelTimer(&pc->timer);	/* T304 */
+	if (pc->t303skb) {
+		dev_kfree_skb(pc->t303skb);
+		pc->t303skb = NULL;
+	}
+	newl3state(pc, 4);
+	if (ret)
+		l3dss1_std_ie_err(pc, ret);
+	if (mISDN_l3up(pc, CC_ALERTING | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_call_proc(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+	u_char		cause;
+
+	if (!(ret = l3dss1_get_channel_id(pc, skb))) {
+		if ((0 == pc->bc) || (3 == pc->bc)) {
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "setup answer with wrong chid %x", pc->bc);
+			l3dss1_status_send(pc, CAUSE_INVALID_CONTENTS);
+			return;
+		}
+	} else if (1 == pc->state) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "setup answer wrong chid (ret %d)", ret);
+		if (ret == -1)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else
+			cause = CAUSE_INVALID_CONTENTS;
+		l3dss1_status_send(pc, cause);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	L3DelTimer(&pc->timer);
+	if (pc->t303skb) {
+		dev_kfree_skb(pc->t303skb);
+		pc->t303skb = NULL;
+	}
+	newl3state(pc, 3);
+	L3AddTimer(&pc->timer, T310, CC_T310);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, ret);
+	if (mISDN_l3up(pc, CC_PROCEEDING | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_connect(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+
+	ret = check_infoelements(pc, skb, ie_CONNECT);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	L3DelTimer(&pc->timer);	/* T310 */
+	if (pc->t303skb) {
+		dev_kfree_skb(pc->t303skb);
+		pc->t303skb = NULL;
+	}
+	l3dss1_message(pc, MT_CONNECT_ACKNOWLEDGE);
+	newl3state(pc, 10);
+	if (ret)
+		l3dss1_std_ie_err(pc, ret);
+	if (mISDN_l3up(pc, CC_CONNECT | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_connect_ack(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+
+	ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	newl3state(pc, 10);
+	L3DelTimer(&pc->timer);
+	if (pc->t303skb) {
+		dev_kfree_skb(pc->t303skb);
+		pc->t303skb = NULL;
+	}
+	if (ret)
+		l3dss1_std_ie_err(pc, ret);
+	if (mISDN_l3up(pc, CC_CONNECT_ACKNOWLEDGE | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_disconnect(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+	u_char		cause = 0;
+
+	StopAllL3Timer(pc);
+	if ((ret = l3dss1_get_cause(pc, skb))) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "DISC get_cause ret(%d)", ret);
+		if (ret == -1)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else
+			cause = CAUSE_INVALID_CONTENTS;
+	}
+	else if (pc->state == 7) /* Call Received*/
+		cause = pc->err;
+	ret = check_infoelements(pc, skb, ie_DISCONNECT);
+	if (ERR_IE_COMPREHENSION == ret)
+		cause = CAUSE_MANDATORY_IE_MISS;
+	else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret))
+		cause = CAUSE_IE_NOTIMPLEMENTED;
+	ret = pc->state;
+	if (cause)
+		newl3state(pc, 19);
+	else
+		newl3state(pc, 12);
+       	if (11 != ret) {
+		if (mISDN_l3up(pc, CC_DISCONNECT | INDICATION, skb))
+			dev_kfree_skb(skb);
+	} else if (!cause) {
+		l3dss1_release_req(pc, pr, NULL);
+		dev_kfree_skb(skb);
+	} else
+		dev_kfree_skb(skb);
+	if (cause) {
+		l3dss1_message_cause(pc, MT_RELEASE, cause);
+		L3AddTimer(&pc->timer, T308, CC_T308_1);
+	}
+}
+
+static void
+l3dss1_setup_ack(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+	u_char		cause;
+
+	if (!(ret = l3dss1_get_channel_id(pc, skb))) {
+		if ((0 == pc->bc) || (3 == pc->bc)) {
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "setup answer with wrong chid %x", pc->bc);
+			l3dss1_status_send(pc, CAUSE_INVALID_CONTENTS);
+			dev_kfree_skb(skb);
+			return;
+		}
+	} else {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "setup answer wrong chid (ret %d)", ret);
+		if (ret == -1)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else
+			cause = CAUSE_INVALID_CONTENTS;
+		l3dss1_status_send(pc, cause);
+		dev_kfree_skb(skb);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	L3DelTimer(&pc->timer);
+	if (pc->t303skb) {
+		dev_kfree_skb(pc->t303skb);
+		pc->t303skb = NULL;
+	}
+	newl3state(pc, 2);
+	L3AddTimer(&pc->timer, T304, CC_T304);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, ret);
+	if (mISDN_l3up(pc, CC_SETUP_ACKNOWLEDGE | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_setup(l3_process_t *pc, u_char pr, void *arg)
+{
+	u_char		*p, cause, bc2 = 0;
+	int		bcfound = 0;
+	struct sk_buff	*skb = arg;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	int		err = 0;
+
+	/*
+	 * Bearer Capabilities
+	 */
+	/* only the first occurence 'll be detected ! */
+	p = skb->data;
+	if (qi->bearer_capability.off) {
+		p += L3_EXTRA_SIZE + qi->bearer_capability.off;
+		p++;
+		if ((p[0] < 2) || (p[0] > 11))
+			err = 1;
+		else {
+			bc2 = p[2] & 0x7f;
+			switch (p[1] & 0x7f) {
+				case 0x00: /* Speech */
+				case 0x10: /* 3.1 Khz audio */
+				case 0x08: /* Unrestricted digital information */
+				case 0x09: /* Restricted digital information */
+				case 0x11:
+					/* Unrestr. digital information  with
+					 * tones/announcements ( or 7 kHz audio
+					 */
+				case 0x18: /* Video */
+					break;
+				default:
+					err = 2;
+					break;
+			}
+			switch (p[2] & 0x7f) {
+				case 0x40: /* packed mode */
+				case 0x10: /* 64 kbit */
+				case 0x11: /* 2*64 kbit */
+				case 0x13: /* 384 kbit */
+				case 0x15: /* 1536 kbit */
+				case 0x17: /* 1920 kbit */
+					break;
+				default:
+					err = 3;
+					break;
+			}
+		}
+		if (err) {
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "setup with wrong bearer(l=%d:%x,%x)",
+					p[0], p[1], p[2]);
+			l3dss1_msg_without_setup(pc, CAUSE_INVALID_CONTENTS);
+			dev_kfree_skb(skb);
+			return;
+		}
+	} else {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "setup without bearer capabilities");
+		/* ETS 300-104 1.3.3 */
+		l3dss1_msg_without_setup(pc, CAUSE_MANDATORY_IE_MISS);
+		dev_kfree_skb(skb);
+		return;
+	}
+	/*
+	 * Channel Identification
+	 */
+	if (!(err = l3dss1_get_channel_id(pc, skb))) {
+		if (pc->bc) {
+			if ((3 == pc->bc) && (0x10 == bc2)) {
+				if (pc->l3->debug & L3_DEB_WARN)
+					l3_debug(pc->l3, "setup with wrong chid %x",
+						pc->bc);
+				l3dss1_msg_without_setup(pc,
+					CAUSE_INVALID_CONTENTS);
+				dev_kfree_skb(skb);
+				return;
+			}
+			bcfound++;
+		} else {
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "setup without bchannel, call waiting");
+			bcfound++;
+		}
+	} else {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "setup with wrong chid ret %d", err);
+		if (err == -1)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else
+			cause = CAUSE_INVALID_CONTENTS;
+		l3dss1_msg_without_setup(pc, cause);
+		dev_kfree_skb(skb);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	err = check_infoelements(pc, skb, ie_SETUP);
+	if (ERR_IE_COMPREHENSION == err) {
+		l3dss1_msg_without_setup(pc, CAUSE_MANDATORY_IE_MISS);
+		dev_kfree_skb(skb);
+		return;
+	}
+	newl3state(pc, 6);
+	L3DelTimer(&pc->timer);
+	L3AddTimer(&pc->timer, T_CTRL, CC_TCTRL);
+	if (err) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, err);
+// already done
+//	err = mISDN_l3up(pc, CC_NEW_CR | INDICATION, NULL);
+	if (mISDN_l3up(pc, CC_SETUP | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_reset(l3_process_t *pc, u_char pr, void *arg)
+{
+	release_l3_process(pc);
+}
+
+static void
+l3dss1_release(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret, cause=0;
+
+	StopAllL3Timer(pc);
+	if ((ret = l3dss1_get_cause(pc, skb))) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "REL get_cause ret(%d)", ret);
+		if ((ret == -1) && (pc->state != 11))
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else if (ret != -1)
+			cause = CAUSE_INVALID_CONTENTS;
+	}
+	ret = check_infoelements(pc, skb, ie_RELEASE);
+	if (ERR_IE_COMPREHENSION == ret)
+		cause = CAUSE_MANDATORY_IE_MISS;
+	else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause))
+		cause = CAUSE_IE_NOTIMPLEMENTED;
+	if (cause)
+		l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
+	else
+		l3dss1_message(pc, MT_RELEASE_COMPLETE);
+	if (mISDN_l3up(pc, CC_RELEASE | INDICATION, skb))
+		dev_kfree_skb(skb);
+	newl3state(pc, 0);
+	release_l3_process(pc);
+}
+
+static void
+l3dss1_progress(l3_process_t *pc, u_char pr, void *arg) {
+	struct sk_buff	*skb = arg;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	int		err = 0;
+	u_char		*p, cause = CAUSE_INVALID_CONTENTS;
+
+	if (qi->progress.off) {
+		p = skb->data;
+		p += L3_EXTRA_SIZE + qi->progress.off;
+		p++;
+		if (p[0] != 2) {
+			err = 1;
+		} else if (!(p[1] & 0x70)) {
+			switch (p[1]) {
+				case 0x80:
+				case 0x81:
+				case 0x82:
+				case 0x84:
+				case 0x85:
+				case 0x87:
+				case 0x8a:
+					switch (p[2]) {
+						case 0x81:
+						case 0x82:
+						case 0x83:
+						case 0x84:
+						case 0x88:
+							break;
+						default:
+							err = 2;
+							break;
+					}
+					break;
+				default:
+					err = 3;
+					break;
+			}
+		}
+	} else {
+		cause = CAUSE_MANDATORY_IE_MISS;
+		err = 4;
+	}
+	if (err) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "progress error %d", err);
+		l3dss1_status_send(pc, cause);
+		dev_kfree_skb(skb);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	err = check_infoelements(pc, skb, ie_PROGRESS);
+	if (err)
+		l3dss1_std_ie_err(pc, err);
+	/* 
+	 * clear T310 if running (should be cleared by a Progress 
+	 * Message, according to ETSI). 
+	 * 
+	 */
+	L3DelTimer(&pc->timer);
+	if (pc->t303skb) {
+		dev_kfree_skb(pc->t303skb);
+		pc->t303skb = NULL;
+	}
+	if (ERR_IE_COMPREHENSION != err) {
+		if (mISDN_l3up(pc, CC_PROGRESS | INDICATION, skb))
+			dev_kfree_skb(skb);
+	} else
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_notify(l3_process_t *pc, u_char pr, void *arg) {
+	struct sk_buff	*skb = arg;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	int		err = 0;
+	u_char		*p, cause = CAUSE_INVALID_CONTENTS;
+
+	if (qi->notify.off) {
+		p = skb->data;
+		p += L3_EXTRA_SIZE + qi->notify.off;
+		p++;
+		if (p[0] != 1) {
+			err = 1;
+#if 0
+		} else {
+			switch (p[1]) {
+				case 0x80:
+				case 0x81:
+				case 0x82:
+					break;
+				default:
+					err = 2;
+					break;
+			}
+#endif
+		}
+	} else {
+		cause = CAUSE_MANDATORY_IE_MISS;
+		err = 3;
+	}
+	if (err) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "notify error %d", err);
+		l3dss1_status_send(pc, cause);
+		dev_kfree_skb(skb);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	err = check_infoelements(pc, skb, ie_NOTIFY);
+	if (err)
+		l3dss1_std_ie_err(pc, err);
+	if (ERR_IE_COMPREHENSION != err) {
+		if (mISDN_l3up(pc, CC_NOTIFY | INDICATION, skb))
+			dev_kfree_skb(skb);
+	} else
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_status_enq(l3_process_t *pc, u_char pr, void *arg) {
+	int		ret;
+	struct sk_buff	*skb = arg;
+
+	ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY);
+	l3dss1_std_ie_err(pc, ret);
+	l3dss1_status_send(pc, CAUSE_STATUS_RESPONSE);
+	if (mISDN_l3up(pc, CC_STATUS_ENQUIRY | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_information(l3_process_t *pc, u_char pr, void *arg) {
+	int		ret;
+	struct sk_buff	*skb = arg;
+
+	ret = check_infoelements(pc, skb, ie_INFORMATION);
+	if (ret)
+		l3dss1_std_ie_err(pc, ret);
+	if (pc->state == 25) { /* overlap receiving */
+		L3DelTimer(&pc->timer);
+		L3AddTimer(&pc->timer, T302, CC_T302);
+	}
+	if (mISDN_l3up(pc, CC_INFORMATION | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_release_ind(l3_process_t *pc, u_char pr, void *arg)
+{
+	u_char		*p;
+	struct sk_buff	*skb = arg;
+	int		err, callState = -1;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+
+	if (pc->state == 19) {
+		/* ETS 300-102 5.3.5 */
+		newl3state(pc, 0);
+		err = mISDN_l3up(pc, CC_RELEASE | INDICATION, skb);
+		release_l3_process(pc);
+	} else {
+		if (qi->call_state.off) {
+			p = skb->data;
+			p += L3_EXTRA_SIZE + qi->call_state.off;
+			p++;
+			if (1 == *p++)
+				callState = *p;
+		}
+		if (callState == 0) {
+			/* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
+			 * set down layer 3 without sending any message
+			 */
+			newl3state(pc, 0);
+			err = mISDN_l3up(pc, CC_RELEASE | INDICATION, skb);
+			release_l3_process(pc);
+		} else {
+			err = mISDN_l3up(pc, CC_RELEASE | INDICATION, skb);
+		}
+	}
+	if (err)
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_restart(l3_process_t *pc, u_char pr, void *arg) {
+	struct sk_buff	*skb = arg;
+
+	L3DelTimer(&pc->timer);
+	mISDN_l3up(pc, CC_RELEASE | INDICATION, NULL);
+	release_l3_process(pc);
+	if (skb)
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_status(l3_process_t *pc, u_char pr, void *arg) {
+	struct sk_buff	*skb = arg;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	int		ret = 0;
+	u_char		*p, cause = 0, callState = 0xff;
+
+	if ((ret = l3dss1_get_cause(pc, skb))) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "STATUS get_cause ret(%d)", ret);
+		if (ret == -1)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else
+			cause = CAUSE_INVALID_CONTENTS;
+	}
+	if (qi->call_state.off) {
+		p = skb->data;
+		p += L3_EXTRA_SIZE + qi->call_state.off;
+		p++;
+		if (1 == *p++) {
+			callState = *p;
+			if (!ie_in_set(pc, callState, l3_valid_states))
+				cause = CAUSE_INVALID_CONTENTS;
+		} else
+			cause = CAUSE_INVALID_CONTENTS;
+	} else
+		cause = CAUSE_MANDATORY_IE_MISS;
+	if (!cause) { /*  no error before */
+		ret = check_infoelements(pc, skb, ie_STATUS);
+		if (ERR_IE_COMPREHENSION == ret)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else if (ERR_IE_UNRECOGNIZED == ret)
+			cause = CAUSE_IE_NOTIMPLEMENTED;
+	}
+	if (cause) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "STATUS error(%d/%d)", ret, cause);
+		l3dss1_status_send(pc, cause);
+		if (cause != CAUSE_IE_NOTIMPLEMENTED) {
+			dev_kfree_skb(skb);
+			return;
+		}
+	}
+	if (qi->cause.off)
+		cause = pc->err & 0x7f;
+	if ((cause == CAUSE_PROTOCOL_ERROR) && (callState == 0)) {
+		/* ETS 300-104 7.6.1, 8.6.1, 10.6.1...
+		 * if received MT_STATUS with cause == 111 and call
+		 * state == 0, then we must set down layer 3
+		 */
+		newl3state(pc, 0);
+		ret = mISDN_l3up(pc, CC_STATUS| INDICATION, skb);
+		release_l3_process(pc);
+	} else
+		ret = mISDN_l3up(pc, CC_STATUS | INDICATION, skb);
+	if (ret)
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_facility(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	int		ret;
+
+	ret = check_infoelements(pc, skb, ie_FACILITY);
+	l3dss1_std_ie_err(pc, ret);
+	if (!qi->facility.off) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "FACILITY without IE_FACILITY");
+		dev_kfree_skb(skb);
+		return;
+	}
+	if (mISDN_l3up(pc, CC_FACILITY | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_suspend_ack(l3_process_t *pc, u_char pr, void *arg) {
+	struct sk_buff	*skb = arg;
+	int		ret;
+
+	L3DelTimer(&pc->timer);
+	newl3state(pc, 0);
+	/* We don't handle suspend_ack for IE errors now */
+	if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "SUSPACK check ie(%d)",ret);
+	if (mISDN_l3up(pc, CC_SUSPEND_ACKNOWLEDGE | INDICATION, skb))
+		dev_kfree_skb(skb);
+	release_l3_process(pc);
+}
+
+static void
+l3dss1_suspend_rej(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+	u_char		cause;
+
+	if ((ret = l3dss1_get_cause(pc, skb))) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "SUSP_REJ get_cause err(%d)", ret);
+		if (ret == -1)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else
+			cause = CAUSE_INVALID_CONTENTS;
+		l3dss1_status_send(pc, cause);
+		dev_kfree_skb(skb);
+		return;
+	}
+	ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	L3DelTimer(&pc->timer);
+	if (mISDN_l3up(pc, CC_SUSPEND_REJECT | INDICATION, skb))
+		dev_kfree_skb(skb);
+	newl3state(pc, 10);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, ret);
+}
+
+static void
+l3dss1_resume_ack(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+
+	if (!(ret = l3dss1_get_channel_id(pc, skb))) {
+		if ((0 == pc->bc) || (3 == pc->bc)) {
+			if (pc->l3->debug & L3_DEB_WARN)
+				l3_debug(pc->l3, "resume ack with wrong chid %x",
+					pc->bc);
+			l3dss1_status_send(pc, CAUSE_INVALID_CONTENTS);
+			dev_kfree_skb(skb);
+			return;
+		}
+	} else if (1 == pc->state) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "resume ack without chid err(%d)",
+				ret);
+		l3dss1_status_send(pc, CAUSE_MANDATORY_IE_MISS);
+		dev_kfree_skb(skb);
+		return;
+	}
+	ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	L3DelTimer(&pc->timer);
+	if (mISDN_l3up(pc, CC_RESUME_ACKNOWLEDGE | INDICATION, skb))
+		dev_kfree_skb(skb);
+	newl3state(pc, 10);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, ret);
+}
+
+static void
+l3dss1_resume_rej(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+	u_char		cause;
+
+	if ((ret = l3dss1_get_cause(pc, skb))) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "RES_REJ get_cause err(%d)", ret);
+		if (ret == -1)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else
+			cause = CAUSE_INVALID_CONTENTS;
+		l3dss1_status_send(pc, cause);
+		dev_kfree_skb(skb);
+		return;
+	}
+	ret = check_infoelements(pc, skb, ie_RESUME_REJECT);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	L3DelTimer(&pc->timer);
+	if (mISDN_l3up(pc, CC_RESUME_REJECT | INDICATION, skb))
+		dev_kfree_skb(skb);
+	newl3state(pc, 0);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, ret);
+	release_l3_process(pc);
+}
+
+static void
+l3dss1_global_restart(l3_process_t *pc, u_char pr, void *arg)
+{
+	u_char		*p=NULL, *cp=NULL, ri, ch = 0, chan = 0, chan_len=0;
+	struct sk_buff	*skb = arg, *nskb=NULL;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	l3_process_t	*up, *n;
+	int i=0;
+
+//	newl3state(pc, 2);
+	L3DelTimer(&pc->timer);
+	if (qi->restart_ind.off) {
+		p = skb->data;
+		p += L3_EXTRA_SIZE + qi->restart_ind.off;
+		p++;
+		ri = p[1];
+		if (pc->l3->debug) l3_debug(pc->l3, "Restart %x", ri);
+	} else {
+		l3_debug(pc->l3, "Restart without restart IE");
+		ri = 0x86;
+	}
+	if (qi->channel_id.off) {
+		p = skb->data;
+		p += L3_EXTRA_SIZE + qi->channel_id.off;
+		cp=p;
+		p++;
+		chan_len=p[0];
+
+		if (chan_len==1) {
+			chan = p[1] & 0x3;
+			ch = p[1];
+		} else {
+			chan = p[3];
+			ch = p[1];
+		}
+		
+		if (pc->l3->debug)
+			l3_debug(pc->l3, "Restart for channel %d", chan);
+	}
+	list_for_each_entry_safe(up, n, &pc->l3->plist, list) {
+		if ((ri & 7) == 7)
+			dss1man(up, CC_RESTART | REQUEST, NULL);
+		else if (up->real_bc == chan) {
+			mISDN_l3up(up, CC_RESTART | REQUEST, NULL);
+
+			l3_debug(up->l3, "Resetting channel\n");
+			release_l3_process(up);
+		}
+	}
+	dev_kfree_skb(skb);
+	switch(chan_len) {
+	case 0:
+		nskb = MsgStart(pc, MT_RESTART_ACKNOWLEDGE, 3);
+		p = skb_put(nskb, 3);
+		
+		break;
+	case 1:
+		nskb = MsgStart(pc, MT_RESTART_ACKNOWLEDGE, 6);
+		p = skb_put(nskb, 6);
+		if (chan) {
+			*p++ = IE_CHANNEL_ID;
+			*p++ = 1;
+			*p++ = ch | 0x80;
+		}
+		break;
+	case 3:
+		nskb = MsgStart(pc, MT_RESTART_ACKNOWLEDGE, 8);
+		p = skb_put(nskb, 8);
+
+		/*copy channel ie*/
+		for (i=0; i<5; i++)
+			*p++ = *cp++;
+		break;
+	}
+	
+	*p++ = IE_RESTART_IND;
+	*p++ = 1;
+	*p++ = ri;
+	if (l3_msg(pc->l3, DL_DATA | REQUEST, 0, 0, nskb))
+		kfree_skb(nskb);
+}
+
+
+static void
+l3dss1_restart_ack_up(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	printk(KERN_NOTICE "Restart Acknowledge to upper layer\n");
+		
+	if (mISDN_l3up(pc, CC_RESTART | CONFIRM, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_restart_ack(l3_process_t *pc, u_char pr, void *arg)
+{
+	printk(KERN_NOTICE "Restart Acknowledge\n");
+}
+
+static void
+l3dss1_dummy(l3_process_t *pc, u_char pr, void *arg)
+{
+}
+
+static void
+l3dss1_hold_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (!test_bit(FLG_PTP, &pc->l3->Flag)) {
+		if ((pc->state & VALID_HOLD_STATES_PTMP) == 0) { /* not a valid HOLD state for PtMP */
+			return;
+		}
+	}
+	switch(pc->aux_state) {
+		case AUX_IDLE:
+			break;
+		default:
+			int_errtxt("RETRIEVE_REQ in wrong aux state %d\n", pc->aux_state);
+		case AUX_HOLD_IND: /* maybe collition, ignored */
+			return;
+	}
+	if (arg)
+		SendMsg(pc, arg, -1);
+	else
+		l3dss1_message(pc, MT_HOLD);
+	pc->aux_state = AUX_HOLD_REQ;
+	L3AddTimer(&pc->aux_timer, THOLD, CC_THOLD);
+}
+
+static void
+l3dss1_hold_ack_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	switch(pc->aux_state) {
+		case AUX_HOLD_IND:
+			break;
+		default:
+			int_errtxt("HOLD_ACK in wrong aux state %d\n", pc->aux_state);
+			return;
+	}
+	if (arg)
+		SendMsg(pc, arg, -1);
+	else
+		l3dss1_message(pc, MT_HOLD_ACKNOWLEDGE);
+	pc->aux_state = AUX_CALL_HELD;
+}
+
+static void
+l3dss1_hold_rej_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	switch(pc->aux_state) {
+		case AUX_HOLD_IND:
+			break;
+		default:
+			int_errtxt("HOLD_REJ in wrong aux state %d\n", pc->aux_state);
+			return;
+	}
+	if (arg)
+		SendMsg(pc, arg, -1);
+	else
+		l3dss1_message_cause(pc, MT_HOLD_REJECT, CAUSE_RESOURCES_UNAVAIL); // FIXME
+	pc->aux_state = AUX_IDLE;
+}
+
+static void
+l3dss1_hold_ind(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+
+	ret = check_infoelements(pc, skb, ie_HOLD);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	if (test_bit(FLG_PTP, &pc->l3->Flag)) {
+		if ((pc->state & VALID_HOLD_STATES_PTP) == 0) { /* not a valid HOLD state for PtP */
+			l3dss1_message_cause(pc, MT_HOLD_REJECT, CAUSE_NOTCOMPAT_STATE);
+			dev_kfree_skb(skb);
+			return;
+		}
+	} else {
+		if ((pc->state & VALID_HOLD_STATES_PTMP) == 0) { /* not a valid HOLD state for PtMP */
+			l3dss1_message_cause(pc, MT_HOLD_REJECT, CAUSE_NOTCOMPAT_STATE);
+			dev_kfree_skb(skb);
+			return;
+		}
+	}
+	switch(pc->aux_state) {
+		case AUX_HOLD_REQ:
+			L3DelTimer(&pc->aux_timer);
+		case AUX_IDLE:
+			if (mISDN_l3up(pc, CC_HOLD | INDICATION, skb))
+				dev_kfree_skb(skb);
+			else {
+				pc->aux_state = AUX_HOLD_IND;
+			}
+			break;
+		default:
+			l3dss1_message_cause(pc, MT_HOLD_REJECT, CAUSE_NOTCOMPAT_STATE);
+			dev_kfree_skb(skb);
+			return;
+	}
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, ret);
+}
+
+static void
+l3dss1_hold_rej(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+	u_char		cause;
+
+	if ((ret = l3dss1_get_cause(pc, skb))) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "HOLD_REJ get_cause err(%d)", ret);
+		if (ret == -1)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else
+			cause = CAUSE_INVALID_CONTENTS;
+		l3dss1_status_send(pc, cause);
+		dev_kfree_skb(skb);
+		return;
+	}
+	ret = check_infoelements(pc, skb, ie_HOLD_REJECT);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	switch(pc->aux_state) {
+		case AUX_HOLD_REQ:
+			L3DelTimer(&pc->aux_timer);
+			break;
+		default:
+			int_errtxt("HOLD_REJ in wrong aux state %d\n", pc->aux_state);
+	}
+	pc->aux_state = AUX_IDLE;
+	if (mISDN_l3up(pc, CC_HOLD_REJECT | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_hold_ignore(l3_process_t *pc, u_char pr, void *arg)
+{
+	dev_kfree_skb(arg);
+}
+
+static void
+l3dss1_hold_req_ignore(l3_process_t *pc, u_char pr, void *arg)
+{
+}
+
+static void
+l3dss1_hold_ack(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+
+	ret = check_infoelements(pc, skb, ie_HOLD_ACKNOWLEDGE);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	switch(pc->aux_state) {
+		case AUX_HOLD_REQ:
+			L3DelTimer(&pc->aux_timer);
+			if (mISDN_l3up(pc, CC_HOLD_ACKNOWLEDGE | INDICATION, skb))
+				dev_kfree_skb(skb);
+			pc->aux_state = AUX_CALL_HELD;
+			break;
+		default:
+			int_errtxt("HOLD_ACK in wrong aux state %d\n", pc->aux_state);
+			dev_kfree_skb(skb);
+	}
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, ret);
+}
+
+static void
+l3dss1_retrieve_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	if (!test_bit(FLG_PTP, &pc->l3->Flag)) {
+		if ((pc->state & (VALID_HOLD_STATES_PTMP | SBIT(12))) == 0) { /* not a valid RETRIEVE state for PtMP */
+			return;
+		}
+	}
+	switch(pc->aux_state) {
+		case AUX_CALL_HELD:
+			break;
+		default:
+			int_errtxt("RETRIEVE_REQ in wrong aux state %d\n", pc->aux_state);
+		case AUX_RETRIEVE_IND: /* maybe collition, ignored */
+			return;
+	}
+	if (arg) {
+		SendMsg(pc, arg, -1);
+	} else {
+		newl3state(pc, -1);
+		l3dss1_message(pc, MT_RETRIEVE);
+	}
+	pc->aux_state = AUX_RETRIEVE_REQ;
+	L3AddTimer(&pc->aux_timer, TRETRIEVE, CC_TRETRIEVE);
+}
+
+static void
+l3dss1_retrieve_ack_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	switch(pc->aux_state) {
+		case AUX_RETRIEVE_IND:
+			break;
+		default:
+			int_errtxt("HOLD_REJ in wrong aux state %d\n", pc->aux_state);
+			return;
+	}
+	if (arg)
+		SendMsg(pc, arg, -1);
+	else
+		l3dss1_message(pc, MT_RETRIEVE_ACKNOWLEDGE);
+	pc->aux_state = AUX_IDLE;
+}
+
+static void
+l3dss1_retrieve_rej_req(l3_process_t *pc, u_char pr, void *arg)
+{
+	switch(pc->aux_state) {
+		case AUX_RETRIEVE_IND:
+			break;
+		default:
+			int_errtxt("HOLD_REJ in wrong aux state %d\n", pc->aux_state);
+			return;
+	}
+	if (arg)
+		SendMsg(pc, arg, -1);
+	else
+		l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_RESOURCES_UNAVAIL); // FIXME
+	pc->aux_state = AUX_CALL_HELD;
+}
+
+
+static void
+l3dss1_retrieve_ind(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+
+	if (test_bit(FLG_PTP, &pc->l3->Flag)) {
+		if ((pc->state & (VALID_HOLD_STATES_PTP | SBIT(12))) == 0) { /* not a valid RETRIEVE state for PtP */
+			l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_NOTCOMPAT_STATE);
+			dev_kfree_skb(skb);
+			return;
+		}
+	} else {
+		if ((pc->state & (VALID_HOLD_STATES_PTMP | SBIT(12))) == 0) { /* not a valid RETRIEVE state for PtMP */
+			l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_NOTCOMPAT_STATE);
+			dev_kfree_skb(skb);
+			return;
+		}
+	}
+	ret = check_infoelements(pc, skb, ie_RETRIEVE);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	switch(pc->aux_state) {
+		case AUX_RETRIEVE_REQ:
+			L3DelTimer(&pc->aux_timer);
+		case AUX_CALL_HELD:
+			if (!(ret = l3dss1_get_channel_id(pc, skb))) {
+				if ((0 == pc->bc) || (3 == pc->bc)) {
+					if (pc->l3->debug & L3_DEB_WARN)
+						l3_debug(pc->l3, "RETRIEVE with wrong chid %x",
+							pc->bc);
+					l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_INVALID_CONTENTS);
+					dev_kfree_skb(skb);
+					return;
+				}
+			}
+			if (mISDN_l3up(pc, CC_RETRIEVE | INDICATION, skb))
+				dev_kfree_skb(skb);
+			else {
+				pc->aux_state = AUX_RETRIEVE_IND;
+			}
+			break;
+		default:
+			l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_NOTCOMPAT_STATE);
+			dev_kfree_skb(skb);
+			return;
+	}
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, ret);
+}
+
+static void
+l3dss1_retrieve_ack(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+
+	ret = check_infoelements(pc, skb, ie_RETRIEVE_ACKNOWLEDGE);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	switch(pc->aux_state) {
+		case AUX_RETRIEVE_REQ:
+			L3DelTimer(&pc->aux_timer);
+			if (!(ret = l3dss1_get_channel_id(pc, skb))) {
+				if ((0 == pc->bc) || (3 == pc->bc)) {
+					if (pc->l3->debug & L3_DEB_WARN)
+						l3_debug(pc->l3, "RETRIEVE ACK with wrong chid %x",
+							pc->bc);
+					l3dss1_status_send(pc, CAUSE_INVALID_CONTENTS);
+					dev_kfree_skb(skb);
+					return;
+				}
+			}
+			if (mISDN_l3up(pc, CC_RETRIEVE_ACKNOWLEDGE | INDICATION, skb))
+				dev_kfree_skb(skb);
+			pc->aux_state = AUX_IDLE;
+			break;
+		default:
+			int_errtxt("RETRIEVE_ACK in wrong aux state %d\n", pc->aux_state);
+	}
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3dss1_std_ie_err(pc, ret);
+}
+
+static void
+l3dss1_retrieve_rej(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	int		ret;
+	u_char		cause;
+
+	if ((ret = l3dss1_get_cause(pc, skb))) {
+		if (pc->l3->debug & L3_DEB_WARN)
+			l3_debug(pc->l3, "RETRIEVE_REJ get_cause err(%d)", ret);
+		if (ret == -1)
+			cause = CAUSE_MANDATORY_IE_MISS;
+		else
+			cause = CAUSE_INVALID_CONTENTS;
+		l3dss1_status_send(pc, cause);
+		dev_kfree_skb(skb);
+		return;
+	}
+	ret = check_infoelements(pc, skb, ie_RETRIEVE_REJECT);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3dss1_std_ie_err(pc, ret);
+		dev_kfree_skb(skb);
+		return;
+	}
+	switch(pc->aux_state) {
+		case AUX_RETRIEVE_REQ:
+			L3DelTimer(&pc->aux_timer);
+			pc->aux_state = AUX_CALL_HELD;
+			break;
+		default:
+			int_errtxt("RETRIEVE_REJ in wrong aux state %d\n", pc->aux_state);
+	}
+	pc->aux_state = AUX_IDLE;
+	if (mISDN_l3up(pc, CC_RETRIEVE_REJECT | INDICATION, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l3dss1_thold(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->aux_timer);
+#if 0
+	pc->cause = 102;	/* Timer expiry */
+	pc->para.loc = 0;	/* local */
+#endif
+	mISDN_l3up(pc, CC_HOLD_REJECT | INDICATION, NULL);
+	pc->aux_state = AUX_IDLE;
+}
+
+static void
+l3dss1_tretrieve(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->aux_timer);
+#if 0
+	pc->cause = 102;	/* Timer expiry */
+	pc->para.loc = 0;	/* local */
+#endif
+	mISDN_l3up(pc, CC_RETRIEVE_REJECT | INDICATION, NULL);
+	pc->aux_state = AUX_CALL_HELD;
+}
+
+static void
+l3dss1_t302(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	newl3state(pc, 11);
+	l3dss1_message_cause(pc, MT_DISCONNECT, CAUSE_INVALID_NUMBER);
+	mISDN_l3up(pc, CC_TIMEOUT | INDICATION, NULL);
+}
+
+static void
+l3dss1_t303(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	if (pc->n303 > 0) {
+		pc->n303--;
+		if (pc->t303skb) {
+			struct sk_buff	*skb;
+			if (pc->n303 > 0) {
+				skb = skb_clone(pc->t303skb, GFP_ATOMIC);
+			} else {
+				skb = pc->t303skb;
+				pc->t303skb = NULL;
+			}
+			if (skb)
+				SendMsg(pc, skb, -1);
+		}
+		L3AddTimer(&pc->timer, T303, CC_T303);
+		return;
+	}
+	if (pc->t303skb)
+		kfree_skb(pc->t303skb);
+	pc->t303skb = NULL;
+	l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, CAUSE_TIMER_EXPIRED);
+	mISDN_l3up(pc, CC_TIMEOUT | INDICATION, NULL);
+	release_l3_process(pc);
+}
+
+static void
+l3dss1_t304(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	newl3state(pc, 11);
+	l3dss1_message_cause(pc, MT_DISCONNECT, CAUSE_TIMER_EXPIRED);
+	mISDN_l3up(pc, CC_TIMEOUT | INDICATION, NULL);
+}
+
+static void
+l3dss1_t305(l3_process_t *pc, u_char pr, void *arg)
+{
+	int cause;
+	
+	L3DelTimer(&pc->timer);
+
+	
+	if (pc->cause != NO_CAUSE) {
+		printk(KERN_NOTICE "Using buffered cause %x\n",pc->cause);
+		cause = pc->cause;
+	}
+	else {
+		cause=CAUSE_NORMAL_CLEARING;
+	}
+	
+	newl3state(pc, 19);
+	l3dss1_message_cause(pc, MT_RELEASE, cause);
+	L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3dss1_t310(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	newl3state(pc, 11);
+	l3dss1_message_cause(pc, MT_DISCONNECT, CAUSE_TIMER_EXPIRED);
+	mISDN_l3up(pc, CC_TIMEOUT | INDICATION, NULL);
+}
+
+static void
+l3dss1_t313(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	newl3state(pc, 11);
+	l3dss1_message_cause(pc, MT_DISCONNECT, CAUSE_TIMER_EXPIRED);
+	mISDN_l3up(pc, CC_TIMEOUT | INDICATION, NULL);
+}
+
+static void
+l3dss1_t308_1(l3_process_t *pc, u_char pr, void *arg)
+{
+	newl3state(pc, 19);
+	L3DelTimer(&pc->timer);
+	l3dss1_message(pc, MT_RELEASE);
+	L3AddTimer(&pc->timer, T308, CC_T308_2);
+}
+
+static void
+l3dss1_t308_2(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	mISDN_l3up(pc, CC_TIMEOUT | INDICATION, NULL);
+	release_l3_process(pc);
+}
+
+static void
+l3dss1_t318(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+#if 0
+	pc->cause = 102;	/* Timer expiry */
+	pc->para.loc = 0;	/* local */
+#endif
+	mISDN_l3up(pc, CC_RESUME_REJECT | INDICATION, NULL);
+	newl3state(pc, 19);
+	l3dss1_message(pc, MT_RELEASE);
+	L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3dss1_t319(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+#if 0
+	pc->cause = 102;	/* Timer expiry */
+	pc->para.loc = 0;	/* local */
+#endif
+	mISDN_l3up(pc, CC_SUSPEND_REJECT | INDICATION, NULL);
+	newl3state(pc, 10);
+}
+
+static void
+l3dss1_dl_reset(l3_process_t *pc, u_char pr, void *arg)
+{
+	struct sk_buff	*nskb, *skb = alloc_skb(L3_EXTRA_SIZE + 10, GFP_ATOMIC);
+	Q931_info_t	*qi;
+	u_char		*p;
+
+	if (!skb)
+		return;
+	qi = (Q931_info_t *)skb_put(skb, L3_EXTRA_SIZE);
+	mISDN_initQ931_info(qi);
+	qi->type = MT_DISCONNECT;
+	qi->cause.off = 1;
+	p = skb_put(skb, 5);
+	p++;
+	*p++ = IE_CAUSE;
+	*p++ = 2;
+	*p++ = 0x80 | CAUSE_LOC_USER;
+	*p++ = 0x80 | CAUSE_TEMPORARY_FAILURE;
+	nskb = skb_clone(skb, GFP_ATOMIC);
+	l3dss1_disconnect_req(pc, pr, skb);
+	if (nskb) {
+		if (mISDN_l3up(pc, CC_DISCONNECT | REQUEST, nskb))
+			dev_kfree_skb(nskb);
+	}
+}
+
+static void
+l3dss1_dl_release(l3_process_t *pc, u_char pr, void *arg)
+{
+	newl3state(pc, 0);
+#if 0
+        pc->cause = 0x1b;          /* Destination out of order */
+        pc->para.loc = 0;
+#endif
+	release_l3_process(pc);
+}
+
+static void
+l3dss1_dl_reestablish(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	L3AddTimer(&pc->timer, T309, CC_T309);
+	l3_msg(pc->l3, DL_ESTABLISH | REQUEST, 0, 0, NULL);
+}
+
+static void
+l3dss1_dl_reest_status(l3_process_t *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+
+	l3dss1_status_send(pc, CAUSE_NORMALUNSPECIFIED);
+}
+
+/* *INDENT-OFF* */
+static struct stateentry downstatelist[] =
+{
+	{SBIT(0),
+	 CC_SETUP | REQUEST, l3dss1_setup_req},
+	{SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) |
+		SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(25),
+	 CC_INFORMATION | REQUEST, l3dss1_information_req},
+	{ALL_STATES,
+	 CC_NOTIFY | REQUEST, l3dss1_notify_req},
+	{SBIT(10),
+	 CC_PROGRESS | REQUEST, l3dss1_progress_req},
+	{SBIT(0),
+	 CC_RESUME | REQUEST, l3dss1_resume_req},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) |
+		SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25),
+	 CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
+	{SBIT(6) | SBIT(11) | SBIT(12),
+	 CC_RELEASE | REQUEST, l3dss1_release_req},
+	{ALL_STATES,
+	 CC_RESTART | REQUEST, l3dss1_restart},
+	{SBIT(6) | SBIT(25),
+	 CC_SETUP | RESPONSE, l3dss1_release_cmpl_req},
+	{ALL_STATES,
+	 CC_RELEASE_COMPLETE | REQUEST, l3dss1_release_cmpl_req},
+	{SBIT(6) | SBIT(25),
+	 CC_PROCEEDING | REQUEST, l3dss1_proceed_req},
+	{SBIT(6),
+	 CC_SETUP_ACKNOWLEDGE | REQUEST, l3dss1_setup_ack_req},
+	{SBIT(25),
+	 CC_SETUP_ACKNOWLEDGE | REQUEST, l3dss1_dummy},
+	{SBIT(6) | SBIT(9) | SBIT(25),
+	 CC_ALERTING | REQUEST, l3dss1_alert_req},
+	{SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
+	 CC_CONNECT | REQUEST, l3dss1_connect_req},
+	{SBIT(10),
+	 CC_SUSPEND | REQUEST, l3dss1_suspend_req},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10),
+	 CC_HOLD | REQUEST, l3dss1_hold_req},
+	{ALL_STATES,
+	 CC_HOLD | REQUEST, l3dss1_hold_req_ignore},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10),
+	 CC_HOLD_ACKNOWLEDGE | REQUEST, l3dss1_hold_ack_req},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10),
+	 CC_HOLD_REJECT | REQUEST, l3dss1_hold_rej_req},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(12),
+	 CC_RETRIEVE | REQUEST, l3dss1_retrieve_req},
+	{ALL_STATES,
+	 CC_RETRIEVE| REQUEST, l3dss1_hold_req_ignore},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(12),
+	 CC_RETRIEVE_ACKNOWLEDGE | REQUEST, l3dss1_retrieve_ack_req},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(12),
+	 CC_RETRIEVE_REJECT | REQUEST, l3dss1_retrieve_rej_req},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10),
+	 CC_HOLD  | REQUEST, l3dss1_hold_req},
+	{ALL_STATES,
+	 CC_FACILITY | REQUEST, l3dss1_facility_req},
+	{ALL_STATES,
+	 CC_STATUS_ENQUIRY | REQUEST, l3dss1_status_enq_req},
+};
+
+#define DOWNSLLEN \
+	(sizeof(downstatelist) / sizeof(struct stateentry))
+
+static struct stateentry datastatelist[] =
+{
+	{ALL_STATES,
+	 MT_STATUS_ENQUIRY, l3dss1_status_enq},
+	{ALL_STATES,
+	 MT_FACILITY, l3dss1_facility},
+	{SBIT(19),
+	 MT_STATUS, l3dss1_release_ind},
+	{ALL_STATES,
+	 MT_STATUS, l3dss1_status},
+	{SBIT(0),
+	 MT_SETUP, l3dss1_setup},
+	{SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) |
+	 SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+	 MT_SETUP, l3dss1_dummy},
+	{SBIT(1) | SBIT(2),
+	 MT_CALL_PROCEEDING, l3dss1_call_proc},
+	{SBIT(1),
+	 MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack},
+	{SBIT(2) | SBIT(3),
+	 MT_ALERTING, l3dss1_alerting},
+	{SBIT(2) | SBIT(3),
+	 MT_PROGRESS, l3dss1_progress},
+	{SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+	 MT_INFORMATION, l3dss1_information},
+	{ALL_STATES,
+	 MT_NOTIFY, l3dss1_notify},
+	{SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+	 MT_RELEASE_COMPLETE, l3dss1_release_cmpl},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25),
+	 MT_RELEASE, l3dss1_release},
+	{SBIT(19),  MT_RELEASE, l3dss1_release_ind},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25),
+	 MT_DISCONNECT, l3dss1_disconnect},
+	{SBIT(19),
+	 MT_DISCONNECT, l3dss1_dummy},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
+	 MT_CONNECT, l3dss1_connect},
+	{SBIT(8),
+	 MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack},
+	{SBIT(15),
+	 MT_SUSPEND_ACKNOWLEDGE, l3dss1_suspend_ack},
+	{SBIT(15),
+	 MT_SUSPEND_REJECT, l3dss1_suspend_rej},
+	{SBIT(17),
+	 MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack},
+	{SBIT(17),
+	 MT_RESUME_REJECT, l3dss1_resume_rej},
+	{SBIT(12) | SBIT(19),
+	 MT_HOLD, l3dss1_hold_ignore},
+	{ALL_STATES,
+	 MT_HOLD, l3dss1_hold_ind},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10),
+	 MT_HOLD_REJECT, l3dss1_hold_rej},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10),
+	 MT_HOLD_ACKNOWLEDGE, l3dss1_hold_ack},
+	{ALL_STATES,
+	 MT_RETRIEVE, l3dss1_retrieve_ind},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(12),
+	 MT_RETRIEVE_REJECT, l3dss1_retrieve_rej},
+	{SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(12),
+	 MT_RETRIEVE_ACKNOWLEDGE, l3dss1_retrieve_ack},
+};
+
+#define DATASLLEN \
+	(sizeof(datastatelist) / sizeof(struct stateentry))
+
+static struct stateentry globalmes_list[] =
+{
+	{ALL_STATES,
+	 MT_STATUS, l3dss1_status},
+	{SBIT(0),
+	 MT_RESTART, l3dss1_global_restart},
+	{SBIT(0),
+	 MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack_up},
+	{SBIT(1),
+	 MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack},
+};
+#define GLOBALM_LEN \
+	(sizeof(globalmes_list) / sizeof(struct stateentry))
+
+static struct stateentry manstatelist[] =
+{
+        {SBIT(2),
+         DL_ESTABLISH | INDICATION, l3dss1_dl_reset},
+        {SBIT(10),
+         DL_ESTABLISH | CONFIRM, l3dss1_dl_reest_status},
+        {SBIT(10),
+         DL_RELEASE | INDICATION, l3dss1_dl_reestablish},
+        {ALL_STATES,
+         DL_RELEASE | INDICATION, l3dss1_dl_release},
+	{SBIT(25),
+	 CC_T302, l3dss1_t302},
+	{SBIT(1),
+	 CC_T303, l3dss1_t303},
+	{SBIT(2),
+	 CC_T304, l3dss1_t304},
+	{SBIT(3),
+	 CC_T310, l3dss1_t310},
+	{SBIT(8),
+	 CC_T313, l3dss1_t313},
+	{SBIT(11),
+	 CC_T305, l3dss1_t305},
+	{SBIT(15),
+	 CC_T319, l3dss1_t319},
+	{SBIT(17),
+	 CC_T318, l3dss1_t318},
+	{SBIT(19),
+	 CC_T308_1, l3dss1_t308_1},
+	{SBIT(19),
+	 CC_T308_2, l3dss1_t308_2},
+	{SBIT(10),
+	 CC_T309, l3dss1_dl_release},
+	{SBIT(6),
+	 CC_TCTRL, l3dss1_reset},
+	{ALL_STATES,
+	 CC_THOLD, l3dss1_thold},
+	{ALL_STATES,
+	 CC_TRETRIEVE, l3dss1_tretrieve},
+	{ALL_STATES,
+	 CC_RESTART | REQUEST, l3dss1_restart},
+};
+
+#define MANSLLEN \
+        (sizeof(manstatelist) / sizeof(struct stateentry))
+/* *INDENT-ON* */
+
+
+static void
+global_handler(layer3_t *l3, u_int mt, struct sk_buff *skb)
+{
+	u_int		i;
+	l3_process_t	*proc = l3->global;
+
+	proc->callref = skb->data[2]; /* cr flag */
+	for (i = 0; i < GLOBALM_LEN; i++)
+		if ((mt == globalmes_list[i].primitive) &&
+		    ((1 << proc->state) & globalmes_list[i].state))
+			break;
+	if (i == GLOBALM_LEN) {
+		if (l3->debug & L3_DEB_STATE) {
+			l3_debug(l3, "dss1 global state %d mt %x unhandled",
+				proc->state, mt);
+		}
+		l3dss1_status_send(proc, CAUSE_INVALID_CALLREF);
+		dev_kfree_skb(skb);
+	} else {
+		if (l3->debug & L3_DEB_STATE) {
+			l3_debug(l3, "dss1 global %d mt %x",
+				proc->state, mt);
+		}
+		globalmes_list[i].rout(proc, mt, skb);
+	}
+}
+
+static int
+dss1_fromdown(layer3_t *l3, struct sk_buff *skb, mISDN_head_t *hh)
+{
+	u_int		i;
+	int		cause, callState, ret = -EINVAL;
+	char		*ptr;
+	l3_process_t	*proc;
+	Q931_info_t	*qi;
+
+	switch (hh->prim) {
+		case (DL_DATA | INDICATION):
+		case (DL_UNITDATA | INDICATION):
+			break;
+		case (DL_ESTABLISH | CONFIRM):
+		case (DL_ESTABLISH | INDICATION):
+		case (DL_RELEASE | INDICATION):
+		case (DL_RELEASE | CONFIRM):
+			l3_msg(l3, hh->prim, hh->dinfo, 0, NULL);
+			dev_kfree_skb(skb);
+			return(0);
+			break;
+		case (DL_DATA | CONFIRM):
+		case (DL_UNITDATA | CONFIRM):
+			dev_kfree_skb(skb);
+			return(0);
+			break;
+                default:
+                        printk(KERN_WARNING "%s: unknown pr=%04x dinfo=%x\n",
+                        	__FUNCTION__, hh->prim, hh->dinfo);
+                        return(-EINVAL);
+	}
+	if (skb->len < 3) {
+		l3_debug(l3, "dss1up frame too short(%d)", skb->len);
+		dev_kfree_skb(skb);
+		return(0);
+	}
+	if (skb->data[0] != PROTO_DIS_EURO) {
+		if (l3->debug & L3_DEB_PROTERR) {
+			l3_debug(l3, "dss1up%sunexpected discriminator %x message len %d",
+				 (hh->prim == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+				 skb->data[0], skb->len);
+		}
+		dev_kfree_skb(skb);
+		return(0);
+	}
+	ret = parseQ931(skb);
+	if (ret < 0) {
+		if (l3->debug & L3_DEB_PROTERR)
+			l3_debug(l3, "dss1up: parse IE error %d", ret);
+		printk(KERN_WARNING "dss1up: parse IE error %d\n", ret);
+		dev_kfree_skb(skb);
+		return(0);
+	}
+	if (l3->debug & L3_DEB_MSG)
+		mISDN_LogL3Msg(skb);
+	qi = (Q931_info_t *)skb->data;
+	ptr = skb->data;
+	ptr += L3_EXTRA_SIZE;
+	if (l3->debug & L3_DEB_STATE)
+		l3_debug(l3, "dss1up cr %d", qi->cr);
+	if (qi->crlen == 0) {	/* Dummy Callref */
+		switch(qi->type) {
+			case MT_FACILITY:
+				l3dss1_facility(l3->dummy, hh->prim, skb);
+			return(0);
+			default:
+			if (l3->debug & L3_DEB_WARN)
+				l3_debug(l3, "dss1up dummy Callref (no facility msg or ie)");
+
+			break;
+		}
+
+		return(0);
+	} else if ((qi->cr & 0x7fff) == 0) {	/* Global CallRef */
+		if (l3->debug & L3_DEB_STATE)
+			l3_debug(l3, "dss1up Global CallRef");
+		global_handler(l3, qi->type, skb);
+		return(0);
+	} else if (!(proc = getl3proc(l3, qi->cr))) {
+		/* No transaction process exist, that means no call with
+		 * this callreference is active
+		 */
+		if (qi->type == MT_SETUP) {
+			/* Setup creates a new l3 process */
+			if (qi->cr & 0x8000) {
+				/* Setup with wrong CREF flag */
+				if (l3->debug & L3_DEB_STATE)
+					l3_debug(l3, "dss1up wrong CRef flag");
+				dev_kfree_skb(skb);
+				return(0);
+			}
+			if (!(proc = new_l3_process(l3, qi->cr, N303, MISDN_ID_ANY))) {
+				/* May be to answer with RELEASE_COMPLETE and
+				 * CAUSE 0x2f "Resource unavailable", but this
+				 * need a new_l3_process too ... arghh
+				 */
+				dev_kfree_skb(skb);
+				return(0);
+			}
+			/* register this ID in L4 */
+			ret = mISDN_l3up(proc, CC_NEW_CR | INDICATION, NULL);
+			if (ret) {
+				printk(KERN_WARNING "dss1up: cannot register ID(%x)\n",
+					proc->id);
+				dev_kfree_skb(skb);
+				release_l3_process(proc);
+				return(0);
+			}
+		} else if (qi->type == MT_STATUS) {
+			cause = 0;
+			if (qi->cause.off) {
+				if (ptr[qi->cause.off +1] >= 2)
+					cause = ptr[qi->cause.off + 3] & 0x7f;
+				else
+					cause = ptr[qi->cause.off + 2] & 0x7f;
+			}
+			callState = 0;
+			if (qi->call_state.off) {
+				callState = ptr[qi->call_state.off + 2];
+			}
+			/* ETS 300-104 part 2.4.1
+			 * if setup has not been made and a message type
+			 * MT_STATUS is received with call state == 0,
+			 * we must send nothing
+			 */
+			if (callState != 0) {
+				/* ETS 300-104 part 2.4.2
+				 * if setup has not been made and a message type
+				 * MT_STATUS is received with call state != 0,
+				 * we must send MT_RELEASE_COMPLETE cause 101
+				 */
+				if ((proc = new_l3_process(l3, qi->cr, N303, MISDN_ID_ANY))) {
+					l3dss1_msg_without_setup(proc,
+						CAUSE_NOTCOMPAT_STATE);
+				}
+			}
+			dev_kfree_skb(skb);
+			return(0);
+		} else if (qi->type == MT_RELEASE_COMPLETE) {
+			dev_kfree_skb(skb);
+			return(0);
+		} else {
+			/* ETS 300-104 part 2
+			 * if setup has not been made and a message type
+			 * (except MT_SETUP and RELEASE_COMPLETE) is received,
+			 * we must send MT_RELEASE_COMPLETE cause 81 */
+			
+			printk("We got Message with Invalid Callref\n");
+			
+			if ((proc = new_l3_process(l3, qi->cr, N303, MISDN_ID_ANY))) {
+				l3dss1_msg_without_setup(proc,
+					CAUSE_INVALID_CALLREF);
+			}
+			dev_kfree_skb(skb);
+			return(0);
+		}
+	}
+	if (l3dss1_check_messagetype_validity(proc, qi->type, skb)) {
+		dev_kfree_skb(skb);
+		return(0);
+	}
+	for (i = 0; i < DATASLLEN; i++)
+		if ((qi->type == datastatelist[i].primitive) &&
+		    ((1 << proc->state) & datastatelist[i].state))
+			break;
+	if (i == DATASLLEN) {
+		if (l3->debug & L3_DEB_STATE) {
+			l3_debug(l3, "dss1up%sstate %d mt %#x unhandled",
+				(hh->prim == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+				proc->state, qi->type);
+		}
+		if ((MT_RELEASE_COMPLETE != qi->type) && (MT_RELEASE != qi->type)) {
+			l3dss1_status_send(proc, CAUSE_NOTCOMPAT_STATE);
+		}
+		dev_kfree_skb(skb);
+	} else {
+		if (l3->debug & L3_DEB_STATE) {
+			l3_debug(l3, "dss1up%sstate %d mt %x",
+				(hh->prim == (DL_DATA | INDICATION)) ?
+				" " : "(broadcast) ", proc->state, qi->type);
+		}
+		datastatelist[i].rout(proc, hh->prim, skb);
+	}
+	return(0);
+}
+
+static int
+dss1_fromup(layer3_t *l3, struct sk_buff *skb, mISDN_head_t *hh)
+{
+	u_int		i;
+	int		cr, ret = -EINVAL;
+	l3_process_t	*proc;
+
+	if ((DL_ESTABLISH | REQUEST) == hh->prim) {
+		l3_msg(l3, hh->prim, 0, 0, NULL);
+		dev_kfree_skb(skb);
+		return(0);
+	}
+	proc = getl3proc4id(l3, hh->dinfo);
+	if ((CC_NEW_CR | REQUEST) == hh->prim) {
+		if (proc) {
+			printk(KERN_WARNING "%s: proc(%x) allready exist\n",
+				__FUNCTION__, hh->dinfo);
+			ret = -EBUSY;
+		} else {
+			cr = newcallref(l3);
+			cr |= 0x8000;
+			ret = -ENOMEM;
+			if ((proc = new_l3_process(l3, cr, N303, hh->dinfo))) {
+				ret = 0;
+				dev_kfree_skb(skb);
+			}
+		}
+		return(ret);
+	}
+	if ((l3->debug & L3_DEB_MSG) && skb->len)
+		mISDN_LogL3Msg(skb);
+	
+	if (!proc && hh->dinfo == MISDN_ID_DUMMY) {
+		if (hh->prim == (CC_FACILITY | REQUEST)) {
+			l3dss1_facility_req(l3->dummy, hh->prim, skb->len ? skb : NULL);
+			ret = 0;
+		}
+		return(ret);
+	}
+
+	if (!proc && hh->dinfo == MISDN_ID_GLOBAL) {
+		if (hh->prim == (CC_RESTART | REQUEST)) {
+			if (l3->debug)
+				printk(KERN_NOTICE "Global Restart Req\n");
+			l3dss1_restart_req(l3->dummy, hh->prim, skb->len ? skb : NULL);
+			ret = 0;
+		}
+		return(ret);
+	}
+
+	if (!proc && (hh->prim == (CC_RELEASE_COMPLETE | REQUEST)) ) {
+		/* crich: */
+		if (l3->debug) l3_debug(l3, "mISDN dss1 sending RELEASE_COMPLETE without proc pr=%04x dinof(%x)", hh->prim, hh->dinfo);
+		SendMsg(l3->dummy, skb, -1);
+
+		return 0;
+	}
+
+	if (!proc) {
+		if(debug)
+			printk(KERN_ERR "mISDN dss1 fromup without proc pr=%04x dinfo(%x)\n",
+				hh->prim, hh->dinfo);
+				return(-EINVAL);
+	}
+	for (i = 0; i < DOWNSLLEN; i++)
+		if ((hh->prim == downstatelist[i].primitive) &&
+		    ((1 << proc->state) & downstatelist[i].state))
+			break;
+	if (i == DOWNSLLEN) {
+		if (l3->debug & L3_DEB_STATE) {
+			l3_debug(l3, "dss1down state %d prim %#x unhandled",
+				proc->state, hh->prim);
+		}
+			dev_kfree_skb(skb);
+	} else {
+		if (l3->debug & L3_DEB_STATE) {
+			l3_debug(l3, "dss1down state %d prim %#x para len %d",
+				 proc->state, hh->prim, skb->len);
+		}
+		if (skb->len)
+			downstatelist[i].rout(proc, hh->prim, skb);
+		else {
+			downstatelist[i].rout(proc, hh->prim, NULL);
+			dev_kfree_skb(skb);
+		}
+	}
+	return(0);
+}
+
+static int
+dss1man(l3_process_t *proc, u_int pr, void *arg)
+{
+	u_int	i;
+
+	if (!proc) {
+		printk(KERN_ERR "mISDN dss1man without proc pr=%04x\n", pr);
+		return(-EINVAL);
+	}
+	for (i = 0; i < MANSLLEN; i++)
+		if ((pr == manstatelist[i].primitive) &&
+			((1 << proc->state) & manstatelist[i].state))
+			break;
+		if (i == MANSLLEN) {
+			if (proc->l3->debug & L3_DEB_STATE) {
+				l3_debug(proc->l3, "cr %d dss1man state %d prim %#x unhandled",
+					proc->callref & 0x7fff, proc->state, pr);
+			}
+		} else {
+			if (proc->l3->debug & L3_DEB_STATE) {
+				l3_debug(proc->l3, "cr %d dss1man state %d prim %#x",
+					proc->callref & 0x7fff, proc->state, pr);
+			}
+			manstatelist[i].rout(proc, pr, arg);
+	}
+	return(0);
+}
+
+static int
+dss1_function(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	layer3_t	*l3;
+	int		ret = -EINVAL;
+	mISDN_head_t	*hh;
+
+	l3 = inst->privat;
+	hh = mISDN_HEAD_P(skb);
+	if (debug)
+		printk(KERN_DEBUG  "%s: addr(%08x) prim(%x)\n", __FUNCTION__,  hh->addr, hh->prim);
+	if (!l3)
+		return(ret);
+
+	switch(hh->addr & MSG_DIR_MASK) {
+		case FLG_MSG_DOWN:
+			ret = dss1_fromup(l3, skb, hh);
+			break;
+		case FLG_MSG_UP:
+			ret = dss1_fromdown(l3, skb, hh);
+			break;
+		case MSG_TO_OWNER:
+			/* FIXME: must be handled depending on type */
+			int_errtxt("not implemented yet");
+			break;
+		default:
+			/* FIXME: broadcast must be handled depending on type */
+			if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS) {
+				ret = -EOPNOTSUPP;
+				break;
+			}
+			int_errtxt("not implemented yet");
+			break;
+	}
+	return(ret);
+}
+
+static void
+release_udss1(layer3_t *l3)
+{
+	mISDNinstance_t  *inst = &l3->inst;
+	u_long		flags;
+
+	if (debug)	
+		printk(KERN_DEBUG "release_udss1 refcnt %d l3(%p) inst(%p)\n",
+		u_dss1.refcnt, l3, inst);
+	release_l3(l3);
+#ifdef FIXME
+	if (inst->up.peer) {
+		inst->up.peer->obj->ctrl(inst->up.peer,
+			MGR_DISCONNECT | REQUEST, &inst->up);
+	}
+	if (inst->down.peer) {
+		inst->down.peer->obj->ctrl(inst->down.peer,
+			MGR_DISCONNECT | REQUEST, &inst->down);
+	}
+#endif
+	spin_lock_irqsave(&u_dss1.lock, flags);
+	list_del(&l3->list);
+	spin_unlock_irqrestore(&u_dss1.lock, flags);
+	mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+	if (l3->entity != MISDN_ENTITY_NONE)
+		mISDN_ctrl(inst, MGR_DELENTITY | REQUEST, (void *)((u_long)l3->entity));
+	kfree(l3);
+}
+
+static int
+new_udss1(mISDNstack_t *st, mISDN_pid_t *pid)
+{
+	layer3_t	*nl3;
+	int		err;
+	u_long		flags;
+
+	if (!st || !pid)
+		return(-EINVAL);
+	if (!(nl3 = kmalloc(sizeof(layer3_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc layer3 failed\n");
+		return(-ENOMEM);
+	}
+	memset(nl3, 0, sizeof(layer3_t));
+	memcpy(&nl3->inst.pid, pid, sizeof(mISDN_pid_t));
+	nl3->debug = debug;
+	mISDN_init_instance(&nl3->inst, &u_dss1, nl3, dss1_function);
+	if (!mISDN_SetHandledPID(&u_dss1, &nl3->inst.pid)) {
+		int_error();
+		return(-ENOPROTOOPT);
+	}
+	if ((pid->protocol[3] & ~ISDN_PID_FEATURE_MASK) != ISDN_PID_L3_DSS1USER) {
+		printk(KERN_ERR "udss1 create failed prt %x\n",
+			pid->protocol[3]);
+		kfree(nl3);
+		return(-ENOPROTOOPT);
+	}
+	init_l3(nl3);
+	if (pid->protocol[3] & ISDN_PID_L3_DF_PTP)
+		test_and_set_bit(FLG_PTP, &nl3->Flag);
+	if (pid->protocol[3] & ISDN_PID_L3_DF_EXTCID)
+		test_and_set_bit(FLG_EXTCID, &nl3->Flag);
+	if (pid->protocol[3] & ISDN_PID_L3_DF_CRLEN2)
+		test_and_set_bit(FLG_CRLEN2, &nl3->Flag);
+	if (!(nl3->global = kmalloc(sizeof(l3_process_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "mISDN can't get memory for dss1 global CR\n");
+		release_l3(nl3);
+		kfree(nl3);
+		return(-ENOMEM);
+	}
+	nl3->global->state = 0;
+	nl3->global->callref = 0;
+	nl3->global->id = MISDN_ID_GLOBAL;
+	INIT_LIST_HEAD(&nl3->global->list);
+	nl3->global->n303 = N303;
+	nl3->global->l3 = nl3;
+	nl3->global->t303skb = NULL;
+	L3InitTimer(nl3->global, &nl3->global->timer);
+	L3InitTimer(nl3->global, &nl3->global->aux_timer);
+	if (!(nl3->dummy = kmalloc(sizeof(l3_process_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "mISDN can't get memory for dss1 dummy CR\n");
+		release_l3(nl3);
+		kfree(nl3);
+		return(-ENOMEM);
+	}
+	nl3->dummy->state = 0;
+	nl3->dummy->callref = -1;
+	nl3->dummy->id = MISDN_ID_DUMMY;
+	INIT_LIST_HEAD(&nl3->dummy->list);
+	nl3->dummy->n303 = N303;
+	nl3->dummy->l3 = nl3;
+	nl3->dummy->t303skb = NULL;
+	L3InitTimer(nl3->dummy, &nl3->dummy->timer);
+	L3InitTimer(nl3->dummy, &nl3->dummy->aux_timer);
+	sprintf(nl3->inst.name, "DSS1 %x", st->id >> 8);
+	nl3->p_mgr = dss1man;
+	spin_lock_irqsave(&u_dss1.lock, flags);
+	list_add_tail(&nl3->list, &u_dss1.ilist);
+	spin_unlock_irqrestore(&u_dss1.lock, flags);
+	err = mISDN_ctrl(&nl3->inst, MGR_NEWENTITY | REQUEST, NULL);
+	if (err) {
+		printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%d)\n",
+			__FUNCTION__, err);
+	}
+	err = mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &nl3->inst);
+	if (err) {
+		release_l3(nl3);
+		list_del(&nl3->list);
+		kfree(nl3);
+	} else {
+		mISDN_stPara_t	stp;
+
+	    	if (st->para.down_headerlen)
+		    	nl3->down_headerlen = st->para.down_headerlen;
+		stp.maxdatalen = 0;
+		stp.up_headerlen = L3_EXTRA_SIZE;
+		stp.down_headerlen = 0;
+		mISDN_ctrl(st, MGR_ADDSTPARA | REQUEST, &stp);
+	}
+	return(err);
+}
+
+static char MName[] = "UDSS1";
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+#endif
+#endif
+
+static int
+udss1_manager(void *data, u_int prim, void *arg) {
+	mISDNinstance_t *inst = data;
+	layer3_t	*l3l;
+	u_long		flags;
+
+	if (debug & MISDN_DEBUG_MANAGER)
+		printk(KERN_DEBUG "udss1_manager data:%p prim:%x arg:%p\n", data, prim, arg);
+	if (!data)
+		return(-EINVAL);
+	spin_lock_irqsave(&u_dss1.lock, flags);
+	list_for_each_entry(l3l, &u_dss1.ilist, list) {
+		if (&l3l->inst == inst)
+			break;
+	}
+	if (&l3l->list == &u_dss1.ilist)
+		l3l = NULL;
+	spin_unlock_irqrestore(&u_dss1.lock, flags);
+	if (prim == (MGR_NEWLAYER | REQUEST))
+		return(new_udss1(data, arg));
+	if (!l3l) {
+		if (debug & 0x1)
+			printk(KERN_WARNING "udss1_manager prim(%x) no instance\n", prim);
+		return(-EINVAL);
+	}
+	switch(prim) {
+	    case MGR_NEWENTITY | CONFIRM:
+		l3l->entity = (u_long)arg & 0xffffffff;
+		break;
+	    case MGR_ADDSTPARA | INDICATION:
+	    	l3l->down_headerlen = ((mISDN_stPara_t *)arg)->down_headerlen;
+	    case MGR_CLRSTPARA | INDICATION:
+		break;
+#ifdef FIXME
+	    case MGR_CONNECT | REQUEST:
+		return(mISDN_ConnectIF(inst, arg));
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+		return(mISDN_SetIF(inst, arg, prim, dss1_fromup, dss1_fromdown, l3l));
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		return(mISDN_DisConnectIF(inst, arg));
+#endif
+	    case MGR_RELEASE | INDICATION:
+	    case MGR_UNREGLAYER | REQUEST:
+	    	if (debug & MISDN_DEBUG_MANAGER)
+			printk(KERN_DEBUG "release_udss1 id %x\n", l3l->inst.st->id);
+	    	release_udss1(l3l);
+	    	break;
+	    PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+	    default:
+	    	if (debug & 0x1)
+			printk(KERN_WARNING "udss1 prim %x not handled\n", prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+int UDSS1Init(void)
+{
+	int err;
+	char tmp[32];
+
+	strcpy(tmp, dss1_revision);
+	printk(KERN_INFO "mISDN: DSS1 Rev. %s\n", mISDN_getrev(tmp));
+#ifdef MODULE
+	u_dss1.owner = THIS_MODULE;
+#endif
+	spin_lock_init(&u_dss1.lock);
+	INIT_LIST_HEAD(&u_dss1.ilist);
+	u_dss1.name = MName;
+	u_dss1.DPROTO.protocol[3] = ISDN_PID_L3_DSS1USER |
+		ISDN_PID_L3_DF_PTP |
+		ISDN_PID_L3_DF_EXTCID |
+		ISDN_PID_L3_DF_CRLEN2;
+	u_dss1.own_ctrl = udss1_manager;
+	mISDNl3New();
+	if ((err = mISDN_register(&u_dss1))) {
+		printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
+		mISDNl3Free();
+	} else
+		mISDN_module_register(THIS_MODULE);
+	return(err);
+}
+
+#ifdef MODULE
+void UDSS1_cleanup(void)
+{
+	int err;
+	layer3_t	*l3, *next;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if ((err = mISDN_unregister(&u_dss1))) {
+		printk(KERN_ERR "Can't unregister User DSS1 error(%d)\n", err);
+	}
+	if (!list_empty(&u_dss1.ilist)) {
+		printk(KERN_WARNING "mISDNl3 u_dss1 list not empty\n");
+		list_for_each_entry_safe(l3, next, &u_dss1.ilist, list)
+			release_udss1(l3);
+	}
+	mISDNl3Free();
+}
+
+module_init(UDSS1Init);
+module_exit(UDSS1_cleanup);
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l3helper.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l3helper.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/l3helper.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,288 @@
+/* $Id: l3helper.c,v 1.8 2006/12/27 18:50:50 jolly Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * L3 data struct helper functions
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mISDNif.h>
+#include "dss1.h"
+#include "helper.h"
+
+
+static signed char _mISDN_l3_ie2pos[128] = {
+			-1,-1,-1,-1, 0,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,
+			 2,-1,-1,-1, 3,-1,-1,-1, 4,-1,-1,-1, 5,-1, 6,-1,
+			 7,-1,-1,-1,-1,-1,-1, 8, 9,10,-1,-1,11,-1,-1,-1,
+			-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+			13,-1,14,15,16,17,18,19,-1,-1,-1,-1,20,21,-1,-1,
+			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,22,23,-1,-1,
+			24,25,-1,-1,26,-1,27,-1,28,29,-1,-1,30,31,32,-1
+};
+			
+static unsigned char _mISDN_l3_pos2ie[33] = {
+			0x04, 0x08, 0x10, 0x14, 0x18, 0x1c, 0x1e, 0x20,
+			0x27, 0x28, 0x29, 0x2c, 0x34, 0x40, 0x42, 0x43,
+			0x44, 0x45, 0x46, 0x47, 0x4c, 0x4d, 0x6c, 0x6d,
+			0x70, 0x71, 0x74, 0x76, 0x78, 0x79, 0x7c, 0x7d,
+		       	0x7e
+};
+
+signed int
+mISDN_l3_ie2pos(u_char c)
+{
+	if (c>0x7f)
+		return(-1);
+	return(_mISDN_l3_ie2pos[c]);
+}
+
+unsigned char
+mISDN_l3_pos2ie(int pos)
+{
+	return(_mISDN_l3_pos2ie[pos]);
+}
+
+void
+mISDN_initQ931_info(Q931_info_t *qi) {
+	memset(qi, 0, sizeof(Q931_info_t));
+};
+
+struct sk_buff *
+#ifdef MISDN_MEMDEBUG
+__mid_alloc_l3msg(int len, u_char type, char *fn, int line)
+#else
+mISDN_alloc_l3msg(int len, u_char type)
+#endif
+{
+	struct sk_buff	*skb;
+	Q931_info_t	*qi;
+
+#ifdef MISDN_MEMDEBUG
+	if (!(skb = __mid_alloc_skb(len + L3_EXTRA_SIZE +1, GFP_ATOMIC, fn, line))) {
+#else
+	if (!(skb = alloc_skb(len + L3_EXTRA_SIZE +1, GFP_ATOMIC))) {
+#endif
+		printk(KERN_WARNING "mISDN: No skb for L3\n");
+		return (NULL);
+	}
+	qi = (Q931_info_t *)skb_put(skb, L3_EXTRA_SIZE +1);
+	mISDN_initQ931_info(qi);
+	qi->type = type;
+	return (skb);
+}
+
+void mISDN_AddvarIE(struct sk_buff *skb, u_char *ie)
+{
+	u_char		*p, *ps;
+	ie_info_t	*ies;
+	int		l;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+
+	ies = &qi->bearer_capability;
+	ps = (u_char *) qi;
+	ps += L3_EXTRA_SIZE;
+	if (*ie & 0x80) { /* one octett IE */
+		if (*ie == IE_MORE_DATA)
+			ies = &qi->more_data;
+		else if (*ie == IE_COMPLETE)
+			ies = &qi->sending_complete;
+		else if ((*ie & 0xf0) == IE_CONGESTION)
+			ies = &qi->congestion_level;
+		else {
+			int_error();
+			return;
+		}
+		if (ies->off) { /* already used, no dupes for single octett */
+			int_error();
+			return;
+		}
+		l = 1;
+	} else {
+		if (_mISDN_l3_ie2pos[*ie]<0) {
+			int_error();
+			return;
+		}
+		ies += _mISDN_l3_ie2pos[*ie];
+		if (ies->off) {
+			if (ies->repeated)
+				ies = mISDN_get_last_repeated_ie(qi, ies);
+			l = mISDN_get_free_ext_ie(qi);
+			if (l < 0) { // overflow
+				int_error();
+				return;
+			}
+			ies->ridx = l;
+			ies->repeated = 1;
+			ies = &qi->ext[l].ie;
+			ies->cs_flg = 0;
+			qi->ext[l].v.codeset = 0;
+			qi->ext[l].v.val = *ie;
+		}
+		l = ie[1] + 2;
+	}
+	p = skb_put(skb, l);
+	ies->off = (u16)(p - ps);
+	memcpy(p, ie, l);
+}
+
+void mISDN_AddIE(struct sk_buff *skb, u_char ie, u_char *iep)
+{
+	u_char		*p, *ps;
+	ie_info_t	*ies;
+	int		l;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+
+	if (ie & 0x80) { /* one octett IE */
+		if (ie == IE_MORE_DATA)
+			ies = &qi->more_data;
+		else if (ie == IE_COMPLETE)
+			ies = &qi->sending_complete;
+		else if ((ie & 0xf0) == IE_CONGESTION)
+			ies = &qi->congestion_level;
+		else {
+			int_error();
+			return;
+		}
+		if (ies->off) { /* already used, no dupes for single octett */
+			int_error();
+			return;
+		}
+		l = 0;
+	} else {
+		if (!iep || !iep[0])
+			return;
+		ies = &qi->bearer_capability;
+		if (_mISDN_l3_ie2pos[ie]<0) {
+			int_error();
+			return;
+		}
+		ies += _mISDN_l3_ie2pos[ie];
+		if (ies->off) {
+			if (ies->repeated)
+				ies = mISDN_get_last_repeated_ie(qi, ies);
+			l = mISDN_get_free_ext_ie(qi);
+			if (l < 0) { // overflow
+				int_error();
+				return;
+			}
+			ies->ridx = l;
+			ies->repeated = 1;
+			ies = &qi->ext[l].ie;
+			ies->cs_flg = 0;
+			qi->ext[l].v.codeset = 0;
+			qi->ext[l].v.val = ie;
+		}
+		l = iep[0] + 1;
+	}
+	ps = (u_char *) qi;
+	ps += L3_EXTRA_SIZE;
+	p = skb_put(skb, l+1);
+	ies->off = (u16)(p - ps);
+	*p++ = ie;
+	if (l)
+		memcpy(p, iep, l);
+}
+
+ie_info_t *mISDN_get_last_repeated_ie(Q931_info_t *qi, ie_info_t *ie)
+{
+	while(ie->repeated) {
+		ie = &qi->ext[ie->ridx].ie;
+	}
+	return(ie);
+}
+
+int mISDN_get_free_ext_ie(Q931_info_t *qi)
+{
+	int	i;
+
+	for (i = 0; i < 8; i++) {
+		if (qi->ext[i].ie.off == 0)
+			return(i);
+	}
+	return (-1);
+}
+
+void mISDN_LogL3Msg(struct sk_buff *skb)
+{
+	u_char		*p,*ps, *t, tmp[128];
+	ie_info_t	*ies;
+	int		i,j;
+	Q931_info_t	*qi = (Q931_info_t *)skb->data;
+	mISDN_head_t	*hh;
+
+	hh = mISDN_HEAD_P(skb);
+	printk(KERN_DEBUG "L3Msg prim(%x) id(%x) len(%d)\n",
+		hh->prim, hh->dinfo, skb->len);
+	if (skb->len < sizeof(Q931_info_t))
+		return;
+	ies = &qi->bearer_capability;
+	ps = (u_char *) qi;
+	ps += L3_EXTRA_SIZE;
+	printk(KERN_DEBUG "L3Msg type(%02x) qi(%p) ies(%p) ps(%p)\n",
+		qi->type, qi, ies, ps);
+	for (i=0;i<33;i++) {
+		if (ies[i].off) {
+			p = ps + ies[i].off;
+			t = tmp;
+			*t = 0;
+			for (j=0; j<p[1]; j++) {
+				if (j>40) {
+					sprintf(t, " ...");
+					break;
+				}
+				t += sprintf(t, " %02x", p[j+2]);
+			}
+			printk(KERN_DEBUG "L3Msg ies[%d] off(%d) rep(%d) ridx(%d) ie(%02x/%02x) len(%d)%s\n",
+				i, ies[i].off, ies[i].repeated, ies[i].ridx, _mISDN_l3_pos2ie[i], *p, p[1], tmp);
+		}
+	}
+	for (i=0;i<8;i++) {
+		if (qi->ext[i].ie.off) {
+			p = ps + qi->ext[i].ie.off;
+			t = tmp;
+			*t = 0;
+			if (qi->ext[i].ie.cs_flg) {
+				for (j=0; j<qi->ext[i].cs.len; j++) {
+					if (j>40) {
+						sprintf(t, " ...");
+						break;
+					}
+					t += sprintf(t, " %02x", p[j]);
+				}
+				printk(KERN_DEBUG "L3Msg ext[%d] off(%d) locked(%d) cs(%d) len(%d)%s\n",
+					i, qi->ext[i].ie.off, qi->ext[i].cs.locked, qi->ext[i].cs.codeset,
+					qi->ext[i].cs.len, tmp);
+			} else {
+				for (j=0; j<p[1]; j++) {
+					if (j>40) {
+						sprintf(t, " ...");
+						break;
+					}
+					t += sprintf(t, " %02x", p[j+2]);
+				}
+				printk(KERN_DEBUG "L3Msg ext[%d] off(%d) rep(%d) ridx(%d) cs(%d) ie(%02x/%02x) len(%d) %s\n",
+					i, qi->ext[i].ie.off, qi->ext[i].ie.repeated, qi->ext[i].ie.ridx, 
+					qi->ext[i].v.codeset, qi->ext[i].v.val, *p, p[1], tmp);
+			}
+		}
+	}
+}
+
+EXPORT_SYMBOL(mISDN_l3_pos2ie);
+EXPORT_SYMBOL(mISDN_l3_ie2pos);
+EXPORT_SYMBOL(mISDN_initQ931_info);
+#ifdef MISDN_MEMDEBUG
+EXPORT_SYMBOL(__mid_alloc_l3msg);
+#else
+EXPORT_SYMBOL(mISDN_alloc_l3msg);
+#endif
+EXPORT_SYMBOL(mISDN_AddvarIE);
+EXPORT_SYMBOL(mISDN_AddIE);
+EXPORT_SYMBOL(mISDN_get_last_repeated_ie);
+EXPORT_SYMBOL(mISDN_get_free_ext_ie);
+EXPORT_SYMBOL(mISDN_LogL3Msg);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/lapd.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/lapd.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/lapd.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,345 @@
+/*
+ * vISDN LAPD/q.921 protocol implementation
+ *
+ * Copyright (C) 2004-2006 Daniele Orlandi
+ *
+ * Authors: Daniele "Vihai" Orlandi <daniele at orlandi.com>
+ *
+ * This program is free software and may be modified and distributed
+ * under the terms and conditions of the GNU General Public License.
+ *
+ */
+
+#ifndef _LAPD_H
+#define _LAPD_H
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+#include <linux/socket.h>
+#else
+#include <sys/socket.h>
+#endif
+
+#ifndef ARPHRD_LAPD
+#define ARPHRD_LAPD 8445
+#endif
+
+#ifndef ETH_P_LAPD
+#define ETH_P_LAPD 0x0030	/* LAPD pseudo type */
+#endif
+
+#ifndef AF_LAPD
+#define AF_LAPD 30
+#endif
+
+#ifndef PF_LAPD
+#define PF_LAPD AF_LAPD
+#endif
+
+#ifndef SOL_LAPD
+#define SOL_LAPD 300
+#endif
+
+#define LAPD_SAPI_Q931		0x00
+#define LAPD_SAPI_X25		0x0f
+#define LAPD_SAPI_MGMT		0x10
+
+#define LAPD_BROADCAST_TEI	127
+#define LAPD_DYNAMIC_TEI	255
+
+#define LAPD_DEV_IOC_ACTIVATE	_IOR(0xd0, 0x00, unsigned int)
+#define LAPD_DEV_IOC_DEACTIVATE	_IOR(0xd0, 0x01, unsigned int)
+
+enum
+{
+	LAPD_INTF_TYPE		= 0,
+	LAPD_INTF_MODE		= 1,
+	LAPD_INTF_ROLE		= 2,
+	LAPD_TEI		= 3,
+	LAPD_SAPI		= 4,
+	LAPD_TEI_MGMT_STATUS	= 5,
+	LAPD_TEI_MGMT_T201	= 6,
+	LAPD_TEI_MGMT_N202	= 7,
+	LAPD_TEI_MGMT_T202	= 8,
+	LAPD_DLC_STATE		= 9,
+	LAPD_T200		= 10,
+	LAPD_N200		= 11,
+	LAPD_T203		= 12,
+	LAPD_N201		= 13,
+	LAPD_K			= 14,
+};
+
+enum lapd_intf_type
+{
+	LAPD_INTF_TYPE_BRA = 0,
+	LAPD_INTF_TYPE_PRA = 1,
+};
+
+enum lapd_intf_mode
+{
+	LAPD_INTF_MODE_POINT_TO_POINT = 0,
+	LAPD_INTF_MODE_MULTIPOINT = 1
+};
+
+enum lapd_intf_role
+{
+	LAPD_INTF_ROLE_TE = 0,
+	LAPD_INTF_ROLE_NT = 1
+};
+
+struct sockaddr_lapd
+{
+	sa_family_t	sal_family;
+	__u8            sal_tei;
+};
+
+enum lapd_primitive_type
+{
+	LAPD_PH_DATA_REQUEST = 1,
+	LAPD_PH_DATA_INDICATION,
+	LAPD_PH_ACTIVATE_INDICATION,
+	LAPD_PH_DEACTIVATE_INDICATION,
+	LAPD_PH_ACTIVATE_REQUEST,
+	LAPD_MPH_ERROR_INDICATION,
+	LAPD_MPH_ACTIVATE_INDICATION,
+	LAPD_MPH_DEACTIVATE_INDICATION,
+	LAPD_MPH_DEACTIVATE_REQUEST,
+	LAPD_MPH_INFORMATION_INDICATION,
+};
+
+enum lapd_mph_information_indication
+{
+	LAPD_MPH_II_CONNECTED,
+	LAPD_MPH_II_DISCONNECTED,
+};
+
+struct lapd_prim_hdr
+{
+	__u8 primitive_type;
+	__u8 reserved[3];
+};
+
+struct lapd_ctrl_hdr
+{
+	__u8 param;
+};
+
+#ifdef __KERNEL__
+#include <asm/atomic.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <net/sock.h>
+
+#define lapd_MODULE_NAME "lapd"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define LAPD_HASHBITS		8
+#define LAPD_HASHSIZE		((1 << LAPD_HASHBITS) - 1)
+
+#define LAPD_SK_STATE_NULL			TCP_LAST_ACK
+#define LAPD_SK_STATE_LISTEN			TCP_LISTEN
+#define LAPD_SK_STATE_NORMAL_DLC		TCP_ESTABLISHED
+#define LAPD_SK_STATE_NORMAL_DLC_CLOSING	TCP_CLOSING
+#define LAPD_SK_STATE_BROADCAST_DLC		TCP_SYN_SENT
+#define LAPD_SK_STATE_MGMT			TCP_SYN_RECV
+#define LAPD_SK_STATE_CLOSE			TCP_CLOSE
+
+#ifdef DEBUG_CODE
+#define lapd_debug(format, arg...)			\
+		printk(KERN_DEBUG			\
+			"lapd: "			\
+			format,				\
+			## arg)
+
+#define lapd_debug_ls(ls, format, arg...)			\
+		SOCK_DEBUG(&ls->sk,				\
+			"lapd: "				\
+			"%s "					\
+			format,					\
+			(ls)->dev ? (ls)->dev->dev->name : "",	\
+			## arg)
+#else
+#define lapd_debug(ls, format, arg...) do { } while (0)
+#define lapd_debug_ls(ls, format, arg...) do { } while (0)
+#define lapd_debug_dev(ls, format, arg...) do { } while (0)
+#endif
+
+#define lapd_msg(lvl, format, arg...)			\
+	printk(lvl "lapd: "				\
+		format,					\
+		## arg)
+
+#define lapd_msg_ls(ls, lvl, format, arg...)		\
+	printk(lvl "lapd: "				\
+		"%s: "					\
+		format,					\
+		(ls)->dev ? (ls)->dev->dev->name : "",	\
+		## arg)
+
+extern struct hlist_head lapd_hash[LAPD_HASHSIZE];
+extern rwlock_t lapd_hash_lock;
+
+// Do not changes these values, user mode binary compatibility needs them
+enum lapd_datalink_state
+{
+	LAPD_DLS_NULL					= 0,
+	LAPD_DLS_1_TEI_UNASSIGNED			= 1,
+	LAPD_DLS_2_AWAITING_TEI				= 2,
+	LAPD_DLS_3_ESTABLISH_AWAITING_TEI		= 3,
+	LAPD_DLS_4_TEI_ASSIGNED				= 4,
+	LAPD_DLS_5_AWAITING_ESTABLISH			= 5,
+	LAPD_DLS_6_AWAITING_RELEASE			= 6,
+	LAPD_DLS_7_LINK_CONNECTION_ESTABLISHED		= 7,
+	LAPD_DLS_8_TIMER_RECOVERY			= 8,
+	LAPD_DLS_LISTENING				= 0xFF,
+};
+
+enum lapd_mdl_error_indications
+{
+	LAPD_MDL_ERROR_INDICATION_A = (1 << 0),
+	LAPD_MDL_ERROR_INDICATION_B = (1 << 1),
+	LAPD_MDL_ERROR_INDICATION_C = (1 << 2),
+	LAPD_MDL_ERROR_INDICATION_D = (1 << 3),
+	LAPD_MDL_ERROR_INDICATION_E = (1 << 4),
+	LAPD_MDL_ERROR_INDICATION_F = (1 << 5),
+	LAPD_MDL_ERROR_INDICATION_G = (1 << 6),
+	LAPD_MDL_ERROR_INDICATION_H = (1 << 7),
+	LAPD_MDL_ERROR_INDICATION_I = (1 << 8),
+	LAPD_MDL_ERROR_INDICATION_J = (1 << 9),
+	LAPD_MDL_ERROR_INDICATION_K = (1 << 10),
+	LAPD_MDL_ERROR_INDICATION_L = (1 << 11),
+	LAPD_MDL_ERROR_INDICATION_M = (1 << 12),
+	LAPD_MDL_ERROR_INDICATION_N = (1 << 13),
+	LAPD_MDL_ERROR_INDICATION_O = (1 << 14),
+};
+
+enum lapd_format_errors
+{
+	LAPD_FE_LENGTH,
+	LAPD_FE_N201,
+	LAPD_FE_UNDEFINED_COMMAND,
+	LAPD_FE_I_FIELD_NOT_PERMITTED,
+};
+
+struct lapd_sap
+{
+	atomic_t refcnt;
+
+	// SAP parameters
+
+	int k;
+
+	int N200;
+	int N201;
+
+	int T200;
+	int T203;
+};
+
+//#include "device.h"
+
+struct lapd_new_dlc
+{
+	struct hlist_node node;
+	struct lapd_sock *lapd_sock;
+};
+
+static inline struct lapd_sap *lapd_sap_alloc(void)
+{
+	return kmalloc(sizeof(struct lapd_sap), GFP_ATOMIC);
+}
+
+static inline void lapd_sap_hold(
+	struct lapd_sap *entity)
+{
+	atomic_inc(&entity->refcnt);
+}
+
+static inline void lapd_sap_put(
+	struct lapd_sap *entity)
+{
+	if (atomic_dec_and_test(&entity->refcnt))
+		kfree(entity);
+}
+
+struct lapd_sock
+{
+	struct sock sk;
+
+	struct lapd_device *dev;
+
+	struct sk_buff_head u_queue;
+
+	int retrans_cnt;
+
+	struct timer_list timer_T200;
+	struct timer_list timer_T203;
+
+	u8 v_s;
+	u8 v_r;
+	u8 v_a;
+
+	enum lapd_datalink_state state;
+
+	int peer_receiver_busy;
+	int own_receiver_busy;
+	int reject_exception;
+	int acknowledge_pending;
+	int layer_3_initiated;
+	// ------------------
+
+	struct lapd_sap *sap;
+	struct lapd_utme *usr_tme;
+
+	int tei;
+	int sapi;
+
+	struct hlist_head new_dlcs;
+};
+
+#define to_lapd_sock(obj) container_of(obj, struct lapd_sock, sk)
+
+enum lapd_dl_primitive_type
+{
+	LAPD_DL_RELEASE_INDICATION,
+	LAPD_DL_RELEASE_CONFIRM,
+	LAPD_DL_ESTABLISH_INDICATION,
+	LAPD_DL_ESTABLISH_CONFIRM,
+};
+
+struct lapd_dl_primitive
+{
+	enum lapd_dl_primitive_type type;
+	int param;
+};
+
+struct lapd_sock *lapd_new_sock(
+	struct lapd_sock *parent_lapd_sock,
+	u8 tei, int sapi);
+
+void lapd_mdl_error_indication(
+	struct lapd_sock *lapd_sock,
+	unsigned long indication);
+
+void lapd_dl_primitive(
+	struct lapd_sock *lapd_sock,
+	enum lapd_dl_primitive_type type,
+	int param);
+int lapd_dl_unit_data_indication(
+	struct lapd_sock *lapd_sock,
+	struct sk_buff *skb);
+void lapd_dl_data_indication(
+	struct lapd_sock *lapd_sock,
+	struct sk_buff *skb);
+
+#endif
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer1.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer1.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer1.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,884 @@
+/* $Id: layer1.c,v 1.20 2007/02/13 10:43:45 crich Exp $
+ *
+ * mISDN_l1.c     common low level stuff for I.430 layer1 TE mode
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+static char *l1_revision = "$Revision: 1.20 $";
+
+#include <linux/module.h>
+#include "core.h"
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+
+typedef struct _layer1 {
+	struct list_head	list;
+	u_long			Flags;
+	struct FsmInst		l1m;
+	struct FsmTimer 	timer;
+	int			debug;
+	int			delay;
+	mISDNinstance_t		inst;
+} layer1_t;
+
+/* l1 status_info */
+typedef struct _status_info_l1 {
+	int	len;
+	int	typ;
+	int	protocol;
+	int	status;
+	int	state;
+	u_long	Flags;
+	int	T3;
+	int	delay;
+	int	debug;
+} status_info_l1_t;
+
+static int debug = 0;
+static mISDNobject_t isdnl1;
+
+#define TIMER3_VALUE 7000
+
+#ifdef OBSOLETE
+static
+struct Fsm l1fsm_b =
+{NULL, 0, 0, NULL, NULL};
+#endif
+
+static
+struct Fsm l1fsm_s =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_L1_F2,
+	ST_L1_F3,
+	ST_L1_F4,
+	ST_L1_F5,
+	ST_L1_F6,
+	ST_L1_F7,
+	ST_L1_F8,
+};
+
+#define L1S_STATE_COUNT (ST_L1_F8+1)
+
+static char *strL1SState[] =
+{
+	"ST_L1_F2",
+	"ST_L1_F3",
+	"ST_L1_F4",
+	"ST_L1_F5",
+	"ST_L1_F6",
+	"ST_L1_F7",
+	"ST_L1_F8",
+};
+
+#ifdef mISDN_UINTERFACE
+static
+struct Fsm l1fsm_u =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_L1_RESET,
+	ST_L1_DEACT,
+	ST_L1_SYNC2,
+	ST_L1_TRANS,
+};
+
+#define L1U_STATE_COUNT (ST_L1_TRANS+1)
+
+static char *strL1UState[] =
+{
+	"ST_L1_RESET",
+	"ST_L1_DEACT",
+	"ST_L1_SYNC2",
+	"ST_L1_TRANS",
+};
+#endif
+
+#ifdef OBSOLETE
+enum {
+	ST_L1_NULL,
+	ST_L1_WAIT_ACT,
+	ST_L1_WAIT_DEACT,
+	ST_L1_ACTIV,
+};
+
+#define L1B_STATE_COUNT (ST_L1_ACTIV+1)
+
+static char *strL1BState[] =
+{
+	"ST_L1_NULL",
+	"ST_L1_WAIT_ACT",
+	"ST_L1_WAIT_DEACT",
+	"ST_L1_ACTIV",
+};
+#endif
+enum {
+	EV_PH_ACTIVATE,
+	EV_PH_DEACTIVATE,
+	EV_RESET_IND,
+	EV_DEACT_CNF,
+	EV_DEACT_IND,
+	EV_POWER_UP,
+	EV_ANYSIG_IND,
+	EV_INFO2_IND,
+	EV_INFO4_IND,
+	EV_TIMER_DEACT,
+	EV_TIMER_ACT,
+	EV_TIMER3,
+};
+
+#define L1_EVENT_COUNT (EV_TIMER3 + 1)
+
+static char *strL1Event[] =
+{
+	"EV_PH_ACTIVATE",
+	"EV_PH_DEACTIVATE",
+	"EV_RESET_IND",
+	"EV_DEACT_CNF",
+	"EV_DEACT_IND",
+	"EV_POWER_UP",
+	"EV_ANYSIG_IND",
+	"EV_INFO2_IND",
+	"EV_INFO4_IND",
+	"EV_TIMER_DEACT",
+	"EV_TIMER_ACT",
+	"EV_TIMER3",
+};
+
+static void
+l1m_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	layer1_t *l1 = fi->userdata;
+	logdata_t log;
+
+	va_start(log.args, fmt);
+	log.fmt = fmt;
+	log.head = l1->inst.name;
+	mISDN_ctrl(&l1->inst, MGR_DEBUGDATA | REQUEST, &log);
+	va_end(log.args);
+}
+
+static int
+l1up(layer1_t *l1, u_int prim, int dinfo, int len, void *arg)
+{
+	return(mISDN_queue_data(&l1->inst, FLG_MSG_UP, prim, dinfo, len, arg, 0));
+}
+
+static int
+l1down(layer1_t *l1, u_int prim, int dinfo, int len, void *arg)
+{
+	return(mISDN_queue_data(&l1->inst, FLG_MSG_DOWN, prim, dinfo, len, arg, 0));
+}
+
+static void
+l1_reset(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_L1_F3);
+}
+
+static void
+l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L1_F3);
+	if (test_bit(FLG_L1_ACTIVATING, &l1->Flags))
+		l1down(l1, PH_CONTROL | REQUEST, HW_POWERUP, 0, NULL);
+}
+
+static void
+l1_deact_req_s(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L1_F3);
+	mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2);
+	test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags);
+}
+
+static void
+l1_power_up_s(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) {
+		mISDN_FsmChangeState(fi, ST_L1_F4);
+		l1down(l1, PH_SIGNAL | REQUEST, INFO3_P8, 0, NULL);
+	} else
+		mISDN_FsmChangeState(fi, ST_L1_F3);
+}
+
+static void
+l1_go_F5(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_L1_F5);
+}
+
+static void
+l1_go_F8(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_L1_F8);
+}
+
+static void
+l1_info2_ind(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+#ifdef mISDN_UINTERFACE
+	if (test_bit(FLG_L1_UINT, &l1->Flags))
+		mISDN_FsmChangeState(fi, ST_L1_SYNC2);
+	else
+#endif
+		mISDN_FsmChangeState(fi, ST_L1_F6);
+	l1down(l1, PH_SIGNAL | REQUEST, INFO3_P8, 0, NULL);
+}
+
+static void
+l1_info4_ind(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+#ifdef mISDN_UINTERFACE
+	if (test_bit(FLG_L1_UINT, &l1->Flags))
+		mISDN_FsmChangeState(fi, ST_L1_TRANS);
+	else
+#endif
+		mISDN_FsmChangeState(fi, ST_L1_F7);
+	l1down(l1, PH_SIGNAL | REQUEST, INFO3_P8, 0, NULL);
+	if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags))
+		mISDN_FsmDelTimer(&l1->timer, 4);
+	if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) {
+		if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags))
+			mISDN_FsmDelTimer(&l1->timer, 3);
+		mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2);
+		test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags);
+	}
+}
+
+static void
+l1_timer3(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+	u_int db = HW_D_NOBLOCKED;
+
+	test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags);
+	if (test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags)) {
+		if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))
+			l1up(l1, PH_CONTROL | INDICATION, 0, 4, &db);
+		l1up(l1, PH_DEACTIVATE | INDICATION, 0, 0, NULL);
+		mISDN_queue_data(&l1->inst, l1->inst.id | MSG_BROADCAST,
+			MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_DEACTIVATED,
+			0, NULL, 0);
+	}
+#ifdef mISDN_UINTERFACE
+	if (!test_bit(FLG_L1_UINT, &l1->Flags))
+#endif
+	if (l1->l1m.state != ST_L1_F6) {
+		mISDN_FsmChangeState(fi, ST_L1_F3);
+		l1down(l1, PH_CONTROL | REQUEST, HW_POWERUP, 0, NULL);
+	}
+}
+
+static void
+l1_timer_act(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	test_and_clear_bit(FLG_L1_ACTTIMER, &l1->Flags);
+	test_and_set_bit(FLG_L1_ACTIVATED, &l1->Flags);
+	if (test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags))
+		l1up(l1, PH_ACTIVATE | CONFIRM, 0, 0, NULL);
+	else
+		l1up(l1, PH_ACTIVATE | INDICATION, 0, 0, NULL);
+	mISDN_queue_data(&l1->inst, l1->inst.id | MSG_BROADCAST,
+		MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_ACTIVATED,
+		0, NULL, 0);
+}
+
+static void
+l1_timer_deact(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+	u_int db = HW_D_NOBLOCKED;
+
+	test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags);
+	test_and_clear_bit(FLG_L1_ACTIVATED, &l1->Flags);
+	if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))
+		l1up(l1, PH_CONTROL | INDICATION, 0, 4, &db);
+	l1up(l1, PH_DEACTIVATE | INDICATION, 0, 0, NULL);
+	l1down(l1, PH_CONTROL | REQUEST, HW_DEACTIVATE, 0, NULL);
+	mISDN_queue_data(&l1->inst, l1->inst.id | MSG_BROADCAST,
+		MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_DEACTIVATED,
+		0, NULL, 0);
+}
+
+static void
+l1_activate_s(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+	test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
+	l1down(l1, PH_CONTROL | REQUEST, HW_RESET, 0, NULL);
+}
+
+static void
+l1_activate_no(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+	u_int db = HW_D_NOBLOCKED;
+
+	if ((!test_bit(FLG_L1_DEACTTIMER, &l1->Flags)) && (!test_bit(FLG_L1_T3RUN, &l1->Flags))) {
+		test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags);
+		if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))
+			l1up(l1, PH_CONTROL | INDICATION, 0, 4, &db);
+		l1up(l1, PH_DEACTIVATE | INDICATION, 0, 0, NULL);
+	}
+}
+
+static struct FsmNode L1SFnList[] =
+{
+	{ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s},
+	{ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no},
+	{ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no},
+	{ST_L1_F3, EV_RESET_IND, l1_reset},
+	{ST_L1_F4, EV_RESET_IND, l1_reset},
+	{ST_L1_F5, EV_RESET_IND, l1_reset},
+	{ST_L1_F6, EV_RESET_IND, l1_reset},
+	{ST_L1_F7, EV_RESET_IND, l1_reset},
+	{ST_L1_F8, EV_RESET_IND, l1_reset},
+	{ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf},
+	{ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf},
+	{ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf},
+	{ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf},
+	{ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf},
+	{ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf},
+	{ST_L1_F6, EV_DEACT_IND, l1_deact_req_s},
+	{ST_L1_F7, EV_DEACT_IND, l1_deact_req_s},
+	{ST_L1_F8, EV_DEACT_IND, l1_deact_req_s},
+	{ST_L1_F3, EV_POWER_UP,  l1_power_up_s},
+	{ST_L1_F4, EV_ANYSIG_IND,l1_go_F5},
+	{ST_L1_F6, EV_ANYSIG_IND,l1_go_F8},
+	{ST_L1_F7, EV_ANYSIG_IND,l1_go_F8},
+	{ST_L1_F3, EV_INFO2_IND, l1_info2_ind},
+	{ST_L1_F4, EV_INFO2_IND, l1_info2_ind},
+	{ST_L1_F5, EV_INFO2_IND, l1_info2_ind},
+	{ST_L1_F7, EV_INFO2_IND, l1_info2_ind},
+	{ST_L1_F8, EV_INFO2_IND, l1_info2_ind},
+	{ST_L1_F3, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_F4, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_F5, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_F6, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_F8, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_F3, EV_TIMER3, l1_timer3},
+	{ST_L1_F4, EV_TIMER3, l1_timer3},
+	{ST_L1_F5, EV_TIMER3, l1_timer3},
+	{ST_L1_F6, EV_TIMER3, l1_timer3},
+	{ST_L1_F8, EV_TIMER3, l1_timer3},
+	{ST_L1_F7, EV_TIMER_ACT, l1_timer_act},
+	{ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact},
+	{ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact},
+	{ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact},
+	{ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact},
+	{ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact},
+	{ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
+};
+
+#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode))
+
+#ifdef mISDN_UINTERFACE
+static void
+l1_deact_req_u(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L1_RESET);
+	mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2);
+	test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags);
+	l1down(l1, PH_CONTROL | REQUEST, HW_POWERUP, 0, NULL);
+}
+
+static void
+l1_power_up_u(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+	test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
+}
+
+static void
+l1_info0_ind(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_L1_DEACT);
+}
+
+static void
+l1_activate_u(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	l1down(l1, PH_SIGNAL | REQUEST, INFO1, 0, NULL);
+}
+
+static struct FsmNode L1UFnList[] =
+{
+	{ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u},
+	{ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u},
+	{ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u},
+	{ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u},
+	{ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u},
+	{ST_L1_DEACT, EV_POWER_UP, l1_power_up_u},
+	{ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind},
+	{ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind},
+	{ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind},
+	{ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_RESET, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_DEACT, EV_TIMER3, l1_timer3},
+	{ST_L1_SYNC2, EV_TIMER3, l1_timer3},
+	{ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act},
+	{ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact},
+	{ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact},
+	{ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact},
+};
+
+#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode))
+
+#endif
+#ifdef OBSOLETE
+static void
+l1b_activate(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L1_WAIT_ACT);
+	mISDN_FsmRestartTimer(&l1->timer, l1->delay, EV_TIMER_ACT, NULL, 2);
+}
+
+static void
+l1b_deactivate(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L1_WAIT_DEACT);
+	mISDN_FsmRestartTimer(&l1->timer, 10, EV_TIMER_DEACT, NULL, 2);
+}
+
+static void
+l1b_timer_act(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L1_ACTIV);
+	l1up(l1, PH_ACTIVATE | CONFIRM, 0, 0, NULL);
+}
+
+static void
+l1b_timer_deact(struct FsmInst *fi, int event, void *arg)
+{
+	layer1_t *l1 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L1_NULL);
+	l1up(l1, PH_DEACTIVATE | CONFIRM, 0, 0, NULL);
+}
+
+static struct FsmNode L1BFnList[] =
+{
+	{ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate},
+	{ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act},
+	{ST_L1_ACTIV, EV_PH_DEACTIVATE, l1b_deactivate},
+	{ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact},
+};
+
+#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
+#endif
+
+static int
+l1from_up(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
+{
+	int		err = 0;
+
+	switch(hh->prim) {
+		case (PH_DATA | REQUEST):
+		case (PH_CONTROL | REQUEST):
+			return(mISDN_queue_down(&l1->inst, 0, skb));
+			break;
+		case (PH_ACTIVATE | REQUEST):
+			if (test_bit(FLG_L1_ACTIVATED, &l1->Flags))
+				l1up(l1, PH_ACTIVATE | CONFIRM, 0, 0, NULL);
+			else {
+				test_and_set_bit(FLG_L1_ACTIVATING, &l1->Flags);
+				mISDN_FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL);
+			}
+			break;
+		case (MDL_FINDTEI | REQUEST):
+			return(mISDN_queue_up(&l1->inst, 0, skb));
+			break;
+		default:
+			if (l1->debug)
+				mISDN_debug(l1->inst.st->id, NULL,
+					"l1from_up msg %x unhandled", hh->prim);
+			err = -EINVAL;
+			break;
+	}
+	if (!err)
+		dev_kfree_skb(skb);
+	return(err);
+}
+
+static int
+l1from_down(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
+{
+	int		err = 0;
+
+	if (hh->prim == PH_DATA_IND) {
+		if (test_bit(FLG_L1_ACTTIMER, &l1->Flags))
+			mISDN_FsmEvent(&l1->l1m, EV_TIMER_ACT, NULL);
+		return(mISDN_queue_up(&l1->inst, 0, skb));
+	} else if (hh->prim == PH_DATA_CNF) {
+		return(mISDN_queue_up(&l1->inst, 0, skb));
+	} else if (hh->prim == (PH_CONTROL | INDICATION)) {
+		if (hh->dinfo == HW_RESET)
+			mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL);
+		else if (hh->dinfo == HW_DEACTIVATE)
+			mISDN_FsmEvent(&l1->l1m, EV_DEACT_IND, NULL);
+		else if (hh->dinfo == HW_POWERUP)
+			mISDN_FsmEvent(&l1->l1m, EV_POWER_UP, NULL);
+		else if (l1->debug)
+			mISDN_debug(l1->inst.st->id, NULL,
+				"l1from_down ctrl ind %x unhandled", hh->dinfo);
+	} else if (hh->prim == (PH_CONTROL | CONFIRM)) {
+		if (hh->dinfo == HW_DEACTIVATE)
+			mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL);
+		else if (l1->debug)
+			mISDN_debug(l1->inst.st->id, NULL,
+				"l1from_down ctrl cnf %x unhandled", hh->dinfo);
+	} else if (hh->prim == (PH_SIGNAL | INDICATION)) {
+		if (hh->dinfo == ANYSIGNAL)
+			mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
+		else if (hh->dinfo == LOSTFRAMING)
+			mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
+		else if (hh->dinfo == INFO2)
+			mISDN_FsmEvent(&l1->l1m, EV_INFO2_IND, NULL);
+		else if (hh->dinfo == INFO4_P8)
+			mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
+		else if (hh->dinfo == INFO4_P10)
+			mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
+		else if (l1->debug)
+			mISDN_debug(l1->inst.st->id, NULL,
+				"l1from_down sig %x unhandled", hh->dinfo);
+	} else {
+		if (l1->debug)
+			mISDN_debug(l1->inst.st->id, NULL,
+				"l1from_down msg %x unhandled", hh->prim);
+		err = -EINVAL;
+	}
+	if (!err)
+		dev_kfree_skb(skb);
+	return(err);
+}
+
+static int
+l1_shortstatus(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
+{
+	u_int	temp;
+
+	if (hh->prim == (MGR_SHORTSTATUS | REQUEST)) {
+		temp = hh->dinfo & SSTATUS_ALL;
+		if (temp == SSTATUS_ALL || temp == SSTATUS_L1) {
+			skb_trim(skb, 0);
+			if (hh->dinfo & SSTATUS_BROADCAST_BIT)
+				temp = l1->inst.id | MSG_BROADCAST;
+			else
+				temp = hh->addr | FLG_MSG_TARGET;
+			hh->dinfo = (l1->l1m.state == ST_L1_F7) ?
+				SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED;
+			hh->prim = MGR_SHORTSTATUS | CONFIRM;
+			return(mISDN_queue_message(&l1->inst, temp, skb));
+		}
+	}
+	return(-EOPNOTSUPP);
+}
+
+static int
+l1_function(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	layer1_t	*l1 = inst->privat;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	int		ret = -EINVAL;
+
+	if (debug)
+		printk(KERN_DEBUG  "%s: addr(%08x) prim(%x)\n", __FUNCTION__,  hh->addr, hh->prim);
+
+	if (unlikely((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS))
+		return(l1_shortstatus(l1, skb, hh));
+
+	switch(hh->addr & MSG_DIR_MASK) {
+		case FLG_MSG_DOWN:
+			ret = l1from_up(l1, skb, hh);
+			break;
+		case FLG_MSG_UP:
+			ret = l1from_down(l1, skb, hh);
+			break;
+		case MSG_TO_OWNER:
+			/* FIXME: must be handled depending on type */
+			int_errtxt("not implemented yet");
+			break;
+		default:
+			/* FIXME: must be handled depending on type */
+			int_errtxt("not implemented yet");
+			break;
+	}
+	return(ret);
+}
+
+static void
+release_l1(layer1_t *l1) {
+	mISDNinstance_t	*inst = &l1->inst;
+	u_long		flags;
+
+	mISDN_FsmDelTimer(&l1->timer, 0);
+#ifdef OBSOLETE
+	if (inst->up.peer) {
+		inst->up.peer->obj->ctrl(inst->up.peer,
+			MGR_DISCONNECT | REQUEST, &inst->up);
+	}
+	if (inst->down.peer) {
+		inst->down.peer->obj->ctrl(inst->down.peer,
+			MGR_DISCONNECT | REQUEST, &inst->down);
+	}
+#endif
+	spin_lock_irqsave(&isdnl1.lock, flags);
+	list_del(&l1->list);
+	spin_unlock_irqrestore(&isdnl1.lock, flags);
+	mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+	kfree(l1);
+}
+
+static int
+new_l1(mISDNstack_t *st, mISDN_pid_t *pid) {
+	layer1_t	*nl1;
+	int		err;
+	u_long		flags;
+
+	if (!st || !pid)
+		return(-EINVAL);
+	if (!(nl1 = kmalloc(sizeof(layer1_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc layer1_t failed\n");
+		return(-ENOMEM);
+	}
+	memset(nl1, 0, sizeof(layer1_t));
+	memcpy(&nl1->inst.pid, pid, sizeof(mISDN_pid_t));
+	mISDN_init_instance(&nl1->inst, &isdnl1, nl1, l1_function);
+	if (!mISDN_SetHandledPID(&isdnl1, &nl1->inst.pid)) {
+		int_error();
+		return(-ENOPROTOOPT);
+	}
+	switch(pid->protocol[1]) {
+	    case ISDN_PID_L1_TE_S0:
+	    	sprintf(nl1->inst.name, "l1TES0 %x", st->id >> 8);
+		nl1->l1m.fsm = &l1fsm_s;
+		nl1->l1m.state = ST_L1_F3;
+		nl1->Flags = 0;
+		break;
+	    default:
+		printk(KERN_ERR "layer1 create failed prt %x\n",
+			pid->protocol[1]);
+		kfree(nl1);
+		return(-ENOPROTOOPT);
+	}
+	nl1->debug = debug;
+	nl1->l1m.debug = debug;
+	nl1->l1m.userdata = nl1;
+	nl1->l1m.userint = 0;
+	nl1->l1m.printdebug = l1m_debug;
+	mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer);
+	spin_lock_irqsave(&isdnl1.lock, flags);
+	list_add_tail(&nl1->list, &isdnl1.ilist);
+	spin_unlock_irqrestore(&isdnl1.lock, flags);
+	err = mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &nl1->inst);
+	if (err) {
+		mISDN_FsmDelTimer(&nl1->timer, 0);
+		list_del(&nl1->list);
+		kfree(nl1);
+	}
+	return(err);
+}
+
+static int
+l1_status(layer1_t *l1, status_info_l1_t *si)
+{
+
+	if (!si)
+		return(-EINVAL);
+	memset(si, 0, sizeof(status_info_l1_t));
+	si->len = sizeof(status_info_l1_t) - 2*sizeof(int);
+	si->typ = STATUS_INFO_L1;
+	si->protocol = l1->inst.pid.protocol[1];
+	if (test_bit(FLG_L1_ACTIVATED, &l1->Flags))
+		si->status = 1;
+	si->state = l1->l1m.state;
+	si->Flags = l1->Flags;
+	si->T3 = TIMER3_VALUE;
+	si->debug = l1->delay;
+	si->debug = l1->debug;
+	return(0);
+}
+
+static char MName[] = "ISDNL1";
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+#endif
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#define Isdnl1Init init_module
+#endif
+
+static int
+l1_manager(void *data, u_int prim, void *arg) {
+	mISDNinstance_t	*inst = data;
+	layer1_t	*l1l;
+	int		err = -EINVAL;
+	u_long		flags;
+
+	if (debug & 0x10000)
+		printk(KERN_DEBUG "%s: data(%p) prim(%x) arg(%p)\n",
+			__FUNCTION__, data, prim, arg);
+	if (!data)
+		return(err);
+	spin_lock_irqsave(&isdnl1.lock, flags);
+	list_for_each_entry(l1l, &isdnl1.ilist, list) {
+		if (&l1l->inst == inst) {
+			err = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&isdnl1.lock, flags);
+	if (err && (prim != (MGR_NEWLAYER | REQUEST))) {
+		if (debug)
+			printk(KERN_WARNING "l1_manager connect no instance\n");
+		return(err);
+	}
+
+	switch(prim) {
+	    case MGR_NEWLAYER | REQUEST:
+		err = new_l1(data, arg);
+		break;
+#ifdef OBSOLETE
+	    case MGR_CONNECT | REQUEST:
+		err = mISDN_ConnectIF(inst, arg);
+		break;
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+		err = mISDN_SetIF(inst, arg, prim, l1from_up, l1from_down, l1l);
+		break;
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		err = mISDN_DisConnectIF(inst, arg);
+		break;
+#endif
+	    case MGR_UNREGLAYER | REQUEST:
+	    case MGR_RELEASE | INDICATION:
+		printk(KERN_DEBUG "release_l1 id %x\n", l1l->inst.st->id);
+		release_l1(l1l);
+		break;
+	    case MGR_STATUS | REQUEST:
+		err = l1_status(l1l, arg);
+		break;
+	    PRIM_NOT_HANDLED(MGR_CTRLREADY|INDICATION);
+	    PRIM_NOT_HANDLED(MGR_ADDSTPARA|INDICATION);
+	    PRIM_NOT_HANDLED(MGR_SETSTACK|INDICATION);
+	    default:
+		printk(KERN_WARNING "l1_manager prim %x not handled\n", prim);
+		err = -EINVAL;
+		break;
+	}
+	return(err);
+}
+
+int Isdnl1Init(void)
+{
+	int err;
+
+	printk(KERN_INFO "ISDN L1 driver version %s\n", mISDN_getrev(l1_revision));
+#ifdef MODULE
+	isdnl1.owner = THIS_MODULE;
+#endif
+	isdnl1.name = MName;
+	isdnl1.DPROTO.protocol[1] = ISDN_PID_L1_TE_S0;
+	isdnl1.own_ctrl = l1_manager;
+	spin_lock_init(&isdnl1.lock);
+	INIT_LIST_HEAD(&isdnl1.ilist);
+#ifdef mISDN_UINTERFACE
+	isdnl1.DPROTO.protocol[1] |= ISDN_PID_L1_TE_U;
+	l1fsm_u.state_count = L1U_STATE_COUNT;
+	l1fsm_u.event_count = L1_EVENT_COUNT;
+	l1fsm_u.strEvent = strL1Event;
+	l1fsm_u.strState = strL1UState;
+	mISDN_FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
+#endif
+	l1fsm_s.state_count = L1S_STATE_COUNT;
+	l1fsm_s.event_count = L1_EVENT_COUNT;
+	l1fsm_s.strEvent = strL1Event;
+	l1fsm_s.strState = strL1SState;
+	mISDN_FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
+#ifdef OBSOLETE
+	l1fsm_b.state_count = L1B_STATE_COUNT;
+	l1fsm_b.event_count = L1_EVENT_COUNT;
+	l1fsm_b.strEvent = strL1Event;
+	l1fsm_b.strState = strL1BState;
+	mISDN_FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
+#endif
+	if ((err = mISDN_register(&isdnl1))) {
+		printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
+#ifdef mISDN_UINTERFACE
+		mISDN_FsmFree(&l1fsm_u);
+#endif
+		mISDN_FsmFree(&l1fsm_s);
+#ifdef OBSOLETE
+		mISDN_FsmFree(&l1fsm_b);
+#endif
+	} else
+		mISDN_module_register(THIS_MODULE);
+	return(err);
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	int 		err;
+	layer1_t	*l1, *nl1;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if ((err = mISDN_unregister(&isdnl1))) {
+		printk(KERN_ERR "Can't unregister ISDN layer 1 error(%d)\n", err);
+	}
+	if(!list_empty(&isdnl1.ilist)) {
+		printk(KERN_WARNING "mISDNl1 inst list not empty\n");
+		list_for_each_entry_safe(l1, nl1, &isdnl1.ilist, list)
+			release_l1(l1);
+	}
+#ifdef mISDN_UINTERFACE
+	mISDN_FsmFree(&l1fsm_u);
+#endif
+	mISDN_FsmFree(&l1fsm_s);
+#ifdef OBSOLETE
+	mISDN_FsmFree(&l1fsm_b);
+#endif
+}
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer1.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer1.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer1.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,60 @@
+/* $Id: layer1.h,v 1.5 2006/03/06 12:52:07 keil Exp $
+ *
+ * Layer 1 defines
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <linux/mISDNif.h>
+#include "fsm.h"
+#ifdef MISDN_MEMDEBUG
+#include "memdbg.h"
+#endif
+
+#ifdef OBSOLETE
+#define D_RCVBUFREADY	0
+#define D_XMTBUFREADY	1
+#define D_L1STATECHANGE	2
+#define D_CLEARBUSY	3
+#define D_RX_MON0	4
+#define D_RX_MON1	5
+#define D_TX_MON0	6
+#define D_TX_MON1	7
+#define D_BLOCKEDATOMIC	8
+#define D_LOS		9
+#define D_LOS_OFF	10
+#define D_AIS		11
+#define D_AIS_OFF	12
+#define D_SLIP_TX	13
+#define D_SLIP_RX	14
+
+#define B_RCVBUFREADY	0
+#define B_XMTBUFREADY	1
+#define B_BLOCKEDATOMIC	2
+#define B_DTMFREADY	3
+#endif
+
+#define FLG_L1_ACTIVATING	1
+#define FLG_L1_ACTIVATED	2
+#define FLG_L1_DEACTTIMER	3
+#define FLG_L1_ACTTIMER		4
+#define FLG_L1_T3RUN		5
+#define FLG_L1_PULL_REQ		6
+#define FLG_L1_UINT		7
+#define FLG_L1_DBLOCKED		8
+
+/* L1 Debug */
+#define	L1_DEB_WARN		0x01
+#define	L1_DEB_INTSTAT		0x02
+#define	L1_DEB_ISAC		0x04
+#define	L1_DEB_ISAC_FIFO	0x08
+#define	L1_DEB_HSCX		0x10
+#define	L1_DEB_HSCX_FIFO	0x20
+#define	L1_DEB_LAPD	        0x40
+#define	L1_DEB_IPAC	        0x80
+#define	L1_DEB_RECEIVE_FRAME    0x100
+#define L1_DEB_MONITOR		0x200
+#define DEB_DLOG_HEX		0x400
+#define DEB_DLOG_VERBOSE	0x800
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer2.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer2.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer2.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,2558 @@
+/* $Id: layer2.c,v 1.32 2006/12/21 15:25:06 nadi Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is released under the GPLv2
+ *
+ */
+#include <linux/module.h>
+#include "core.h"
+#include "layer2.h"
+#include "helper.h"
+#include "debug.h"
+
+static char *l2_revision = "$Revision: 1.32 $";
+
+static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
+
+static int debug = 0;
+static mISDNobject_t isdnl2;
+
+static
+struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_L2_1,
+	ST_L2_2,
+	ST_L2_3,
+	ST_L2_4,
+	ST_L2_5,
+	ST_L2_6,
+	ST_L2_7,
+	ST_L2_8,
+};
+
+#define L2_STATE_COUNT (ST_L2_8+1)
+
+static char *strL2State[] =
+{
+	"ST_L2_1",
+	"ST_L2_2",
+	"ST_L2_3",
+	"ST_L2_4",
+	"ST_L2_5",
+	"ST_L2_6",
+	"ST_L2_7",
+	"ST_L2_8",
+};
+
+enum {
+	EV_L2_UI,
+	EV_L2_SABME,
+	EV_L2_DISC,
+	EV_L2_DM,
+	EV_L2_UA,
+	EV_L2_FRMR,
+	EV_L2_SUPER,
+	EV_L2_I,
+	EV_L2_DL_DATA,
+	EV_L2_ACK_PULL,
+	EV_L2_DL_UNITDATA,
+	EV_L2_DL_ESTABLISH_REQ,
+	EV_L2_DL_RELEASE_REQ,
+	EV_L2_MDL_ASSIGN,
+	EV_L2_MDL_REMOVE,
+	EV_L2_MDL_ERROR,
+	EV_L1_DEACTIVATE,
+	EV_L2_T200,
+	EV_L2_T203,
+	EV_L2_SET_OWN_BUSY,
+	EV_L2_CLEAR_OWN_BUSY,
+	EV_L2_FRAME_ERROR,
+};
+
+#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR+1)
+
+static char *strL2Event[] =
+{
+	"EV_L2_UI",
+	"EV_L2_SABME",
+	"EV_L2_DISC",
+	"EV_L2_DM",
+	"EV_L2_UA",
+	"EV_L2_FRMR",
+	"EV_L2_SUPER",
+	"EV_L2_I",
+	"EV_L2_DL_DATA",
+	"EV_L2_ACK_PULL",
+	"EV_L2_DL_UNITDATA",
+	"EV_L2_DL_ESTABLISH_REQ",
+	"EV_L2_DL_RELEASE_REQ",
+	"EV_L2_MDL_ASSIGN",
+	"EV_L2_MDL_REMOVE",
+	"EV_L2_MDL_ERROR",
+	"EV_L1_DEACTIVATE",
+	"EV_L2_T200",
+	"EV_L2_T203",
+	"EV_L2_SET_OWN_BUSY",
+	"EV_L2_CLEAR_OWN_BUSY",
+	"EV_L2_FRAME_ERROR",
+};
+
+inline u_int
+l2headersize(layer2_t *l2, int ui)
+{
+	return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
+		(test_bit(FLG_LAPD, &l2->flag) ? 2 : 1));
+}
+
+inline u_int
+l2addrsize(layer2_t *l2)
+{
+	return (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
+}
+
+static int
+l2_newid(layer2_t *l2)
+{
+	int	id;
+
+	id = l2->next_id++;
+	if (id == 0x7fff)
+		l2->next_id = 1;
+	id |= (l2->entity << 16);
+	return(id);
+}
+
+static int
+l2up(layer2_t *l2, u_int prim, int dinfo, struct sk_buff *skb)
+{
+	return(mISDN_queueup_newhead(&l2->inst, 0, prim, dinfo, skb));
+}
+
+static int
+l2up_create(layer2_t *l2, u_int prim, int dinfo, int len, void *arg)
+{
+	return(mISDN_queue_data(&l2->inst, FLG_MSG_UP, prim, dinfo, len, arg, 0));
+}
+
+static int
+l2down_skb(layer2_t *l2, struct sk_buff *skb) {
+	int ret;
+
+	ret = mISDN_queue_down(&l2->inst, 0, skb);
+	if (ret && l2->debug)
+		printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret);
+	return(ret);
+}
+
+static int
+l2down_raw(layer2_t *l2, struct sk_buff *skb)
+{
+	mISDN_head_t *hh = mISDN_HEAD_P(skb);
+
+	if (hh->prim == PH_DATA_REQ) {
+		if (test_and_set_bit(FLG_L1_BUSY, &l2->flag)) {
+			skb_queue_tail(&l2->down_queue, skb);
+			return(0);
+		}
+		l2->down_id = mISDN_HEAD_DINFO(skb);
+	}
+	return(l2down_skb(l2, skb));
+}
+
+static int
+l2down(layer2_t *l2, u_int prim, int dinfo, struct sk_buff *skb)
+{
+	mISDN_sethead(prim, dinfo, skb);
+	return(l2down_raw(l2, skb));
+}
+
+static int
+l2down_create(layer2_t *l2, u_int prim, int dinfo, int len, void *arg)
+{
+	struct sk_buff	*skb;
+	int		err;
+
+	skb = create_link_skb(prim, dinfo, len, arg, 0);
+	if (!skb)
+		return(-ENOMEM);
+	err = l2down_raw(l2, skb);
+	if (err)
+		dev_kfree_skb(skb);
+	return(err);
+}
+
+#ifdef OBSOLETE
+static int
+l2_chain_down(mISDNinstance_t *inst, struct sk_buff *skb) {
+	return(l2down_raw(inst->privat, skb));
+}
+#endif
+
+static int
+ph_data_confirm(mISDNinstance_t *inst, mISDN_head_t *hh, struct sk_buff *skb) {
+	layer2_t *l2 = inst->privat;
+	struct sk_buff *nskb = skb;
+//	mISDNif_t *next = up->clone;
+	int ret = -EAGAIN;
+
+	if (test_bit(FLG_L1_BUSY, &l2->flag)) {
+		if (hh->dinfo == l2->down_id) {
+			if ((nskb = skb_dequeue(&l2->down_queue))) {
+				l2->down_id = mISDN_HEAD_DINFO(nskb);
+				if (l2down_skb(l2, nskb)) {
+					dev_kfree_skb(nskb);
+					l2->down_id = MISDN_ID_NONE;
+				}
+			} else
+				l2->down_id = MISDN_ID_NONE;
+#ifdef FIXME
+			if (next)
+				ret = next->func(next, skb);
+#endif
+			if (ret) {
+				dev_kfree_skb(skb);
+				ret = 0;
+			}
+			if (l2->down_id == MISDN_ID_NONE) {
+				test_and_clear_bit(FLG_L1_BUSY, &l2->flag);
+				mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
+			}
+		}
+	}
+#ifdef FIXME
+	if (ret && next)
+		ret = next->func(next, skb);
+#endif
+	if (!test_and_set_bit(FLG_L1_BUSY, &l2->flag)) {
+		if ((nskb = skb_dequeue(&l2->down_queue))) {
+			l2->down_id = mISDN_HEAD_DINFO(nskb);
+			if (l2down_skb(l2, nskb)) {
+				dev_kfree_skb(nskb);
+				l2->down_id = MISDN_ID_NONE;
+				test_and_clear_bit(FLG_L1_BUSY, &l2->flag);
+			}
+		} else
+			test_and_clear_bit(FLG_L1_BUSY, &l2->flag);
+	}
+	return(ret);
+}
+
+static int
+l2mgr(layer2_t *l2, u_int prim, void *arg) {
+	long c = (long)arg;
+
+	printk(KERN_WARNING "l2mgr: addr:%x prim %x %c\n", l2->inst.id, prim, (char)c);
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		!test_bit(FLG_FIXED_TEI, &l2->flag)) {
+		struct sk_buff  *skb;
+		switch(c) {
+			case 'C':
+			case 'D':
+			case 'G':
+			case 'H':
+				skb = create_link_skb(prim, 0, 0, NULL, 0);
+				if (!skb)
+					break;
+				if (l2_tei(l2->tm, skb))
+					dev_kfree_skb(skb);
+				break;
+		}
+	}
+	return(0);
+}
+
+static void
+set_peer_busy(layer2_t *l2) {
+	test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
+	if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue))
+		test_and_set_bit(FLG_L2BLOCK, &l2->flag);
+}
+
+static void
+clear_peer_busy(layer2_t *l2) {
+	if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag))
+		test_and_clear_bit(FLG_L2BLOCK, &l2->flag);
+}
+
+static void
+InitWin(layer2_t *l2)
+{
+	int i;
+
+	for (i = 0; i < MAX_WINDOW; i++)
+		l2->windowar[i] = NULL;
+}
+
+static int
+freewin(layer2_t *l2)
+{
+	int i, cnt = 0;
+
+	for (i = 0; i < MAX_WINDOW; i++) {
+		if (l2->windowar[i]) {
+			cnt++;
+			dev_kfree_skb(l2->windowar[i]);
+			l2->windowar[i] = NULL;
+		}
+	}
+	return cnt;
+}
+
+static void
+ReleaseWin(layer2_t *l2)
+{
+	int cnt;
+
+	if((cnt = freewin(l2)))
+		printk(KERN_WARNING "isdnl2 freed %d skbuffs in release\n", cnt);
+}
+
+inline unsigned int
+cansend(layer2_t *l2)
+{
+	unsigned int p1;
+
+	if(test_bit(FLG_MOD128, &l2->flag))
+		p1 = (l2->vs - l2->va) % 128;
+	else
+		p1 = (l2->vs - l2->va) % 8;
+	return ((p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag));
+}
+
+inline void
+clear_exception(layer2_t *l2)
+{
+	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+	test_and_clear_bit(FLG_REJEXC, &l2->flag);
+	test_and_clear_bit(FLG_OWN_BUSY, &l2->flag);
+	clear_peer_busy(l2);
+}
+
+static int
+sethdraddr(layer2_t *l2, u_char *header, int rsp)
+{
+	u_char *ptr = header;
+	int crbit = rsp;
+
+	if (test_bit(FLG_LAPD, &l2->flag)) {
+		if (test_bit(FLG_LAPD_NET, &l2->flag))
+			crbit = !crbit;
+		*ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0);
+		*ptr++ = (l2->tei << 1) | 1;
+		return (2);
+	} else {
+		if (test_bit(FLG_ORIG, &l2->flag))
+			crbit = !crbit;
+		if (crbit)
+			*ptr++ = l2->addr.B;
+		else
+			*ptr++ = l2->addr.A;
+		return (1);
+	}
+}
+
+inline static void
+enqueue_super(layer2_t *l2, struct sk_buff *skb)
+{
+	if (l2down(l2, PH_DATA | REQUEST, l2_newid(l2), skb))
+		dev_kfree_skb(skb);
+}
+
+inline static void
+enqueue_ui(layer2_t *l2, struct sk_buff *skb)
+{
+	if (l2down(l2, PH_DATA | REQUEST, mISDN_HEAD_DINFO(skb), skb))
+		dev_kfree_skb(skb);
+}
+
+inline int
+IsUI(u_char * data)
+{
+	return ((data[0] & 0xef) == UI);
+}
+
+inline int
+IsUA(u_char * data)
+{
+	return ((data[0] & 0xef) == UA);
+}
+
+inline int
+IsDM(u_char * data)
+{
+	return ((data[0] & 0xef) == DM);
+}
+
+inline int
+IsDISC(u_char * data)
+{
+	return ((data[0] & 0xef) == DISC);
+}
+
+inline int
+IsRR(u_char * data, layer2_t *l2)
+{
+	if (test_bit(FLG_MOD128, &l2->flag))
+		return (data[0] == RR);
+	else
+		return ((data[0] & 0xf) == 1);
+}
+
+inline int
+IsSFrame(u_char * data, layer2_t *l2)
+{
+	register u_char d = *data;
+
+	if (!test_bit(FLG_MOD128, &l2->flag))
+		d &= 0xf;
+	return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c));
+}
+
+inline int
+IsSABME(u_char * data, layer2_t *l2)
+{
+	u_char d = data[0] & ~0x10;
+
+	return (test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM);
+}
+
+inline int
+IsREJ(u_char * data, layer2_t *l2)
+{
+	return (test_bit(FLG_MOD128, &l2->flag) ? data[0] == REJ : (data[0] & 0xf) == REJ);
+}
+
+inline int
+IsFRMR(u_char * data)
+{
+	return ((data[0] & 0xef) == FRMR);
+}
+
+inline int
+IsRNR(u_char * data, layer2_t *l2)
+{
+	return (test_bit(FLG_MOD128, &l2->flag) ? data[0] == RNR : (data[0] & 0xf) == RNR);
+}
+
+int
+iframe_error(layer2_t *l2, struct sk_buff *skb)
+{
+	u_int	i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1);
+	int	rsp = *skb->data & 0x2;
+
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+	if (rsp)
+		return 'L';
+	if (skb->len < i)
+		return 'N';
+	if ((skb->len - i) > l2->maxlen)
+		return 'O';
+	return 0;
+}
+
+int
+super_error(layer2_t *l2, struct sk_buff *skb)
+{
+	if (skb->len != l2addrsize(l2) +
+	    (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1))
+		return 'N';
+	return 0;
+}
+
+int
+unnum_error(layer2_t *l2, struct sk_buff *skb, int wantrsp)
+{
+	int rsp = (*skb->data & 0x2) >> 1;
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+	if (rsp != wantrsp)
+		return 'L';
+	if (skb->len != l2addrsize(l2) + 1)
+		return 'N';
+	return 0;
+}
+
+int
+UI_error(layer2_t *l2, struct sk_buff *skb)
+{
+	int rsp = *skb->data & 0x2;
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+	if (rsp)
+		return 'L';
+	if (skb->len > l2->maxlen + l2addrsize(l2) + 1)
+		return 'O';
+	return 0;
+}
+
+int
+FRMR_error(layer2_t *l2, struct sk_buff *skb)
+{
+	u_int	headers = l2addrsize(l2) + 1;
+	u_char	*datap = skb->data + headers;
+	int	rsp = *skb->data & 0x2;
+
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+	if (!rsp)
+		return 'L';
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		if (skb->len < headers + 5)
+			return 'N';
+		else if (l2->debug)
+			l2m_debug(&l2->l2m, "FRMR information %2x %2x %2x %2x %2x",
+				datap[0], datap[1], datap[2],
+				datap[3], datap[4]);
+	} else {
+		if (skb->len < headers + 3)
+			return 'N';
+		else if (l2->debug)
+			l2m_debug(&l2->l2m, "FRMR information %2x %2x %2x",
+				datap[0], datap[1], datap[2]);
+	}
+	return 0;
+}
+
+static unsigned int
+legalnr(layer2_t *l2, unsigned int nr)
+{
+	if(test_bit(FLG_MOD128, &l2->flag))
+		return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128);
+	else
+		return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8);
+}
+
+static void
+setva(layer2_t *l2, unsigned int nr)
+{
+	struct sk_buff	*skb;
+
+	while (l2->va != nr) {
+		l2->va++;
+		if(test_bit(FLG_MOD128, &l2->flag))
+			l2->va %= 128;
+		else
+			l2->va %= 8;
+		if (l2->windowar[l2->sow]) {
+			skb_trim(l2->windowar[l2->sow], 0);
+			skb_queue_tail(&l2->tmp_queue, l2->windowar[l2->sow]);
+			l2->windowar[l2->sow] = NULL;
+		}
+		l2->sow = (l2->sow + 1) % l2->window;
+	}
+	while((skb =skb_dequeue(&l2->tmp_queue))) {
+		if (l2up(l2, DL_DATA | CONFIRM, mISDN_HEAD_DINFO(skb), skb))
+			dev_kfree_skb(skb);
+	}
+}
+
+static void
+send_uframe(layer2_t *l2, struct sk_buff *skb, u_char cmd, u_char cr)
+{
+	u_char tmp[MAX_HEADER_LEN];
+	int i;
+
+	i = sethdraddr(l2, tmp, cr);
+	tmp[i++] = cmd;
+	if (skb)
+		skb_trim(skb, 0);
+	else if (!(skb = alloc_skb(i, GFP_ATOMIC))) {
+		printk(KERN_WARNING "%s: can't alloc skbuff\n", __FUNCTION__);
+		return;
+	}
+	memcpy(skb_put(skb, i), tmp, i);
+	enqueue_super(l2, skb);
+}
+
+
+inline u_char
+get_PollFlag(layer2_t *l2, struct sk_buff * skb)
+{
+	return (skb->data[l2addrsize(l2)] & 0x10);
+}
+
+inline u_char
+get_PollFlagFree(layer2_t *l2, struct sk_buff *skb)
+{
+	u_char PF;
+
+	PF = get_PollFlag(l2, skb);
+	dev_kfree_skb(skb);
+	return (PF);
+}
+
+inline void
+start_t200(layer2_t *l2, int i)
+{
+	mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
+	test_and_set_bit(FLG_T200_RUN, &l2->flag);
+}
+
+inline void
+restart_t200(layer2_t *l2, int i)
+{
+	mISDN_FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i);
+	test_and_set_bit(FLG_T200_RUN, &l2->flag);
+}
+
+inline void
+stop_t200(layer2_t *l2, int i)
+{
+	if(test_and_clear_bit(FLG_T200_RUN, &l2->flag))
+		mISDN_FsmDelTimer(&l2->t200, i);
+}
+
+inline void
+st5_dl_release_l2l3(layer2_t *l2)
+{
+	int pr;
+
+	if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) {
+		pr = DL_RELEASE | CONFIRM;
+	} else {
+		pr = DL_RELEASE | INDICATION;
+	}
+	l2up_create(l2, pr, 0, 0, NULL);
+}
+
+inline void
+lapb_dl_release_l2l3(layer2_t *l2, int f)
+{
+	if (test_bit(FLG_LAPB, &l2->flag))
+		l2down_create(l2, PH_DEACTIVATE | REQUEST, 0, 0, NULL);
+	l2up_create(l2, DL_RELEASE | f, 0, 0, NULL);
+}
+
+static void
+establishlink(struct FsmInst *fi)
+{
+	layer2_t *l2 = fi->userdata;
+	u_char cmd;
+
+	clear_exception(l2);
+	l2->rc = 0;
+	cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10;
+	send_uframe(l2, NULL, cmd, CMD);
+	mISDN_FsmDelTimer(&l2->t203, 1);
+	restart_t200(l2, 1);
+	test_and_clear_bit(FLG_PEND_REL, &l2->flag);
+	freewin(l2);
+	mISDN_FsmChangeState(fi, ST_L2_5);
+}
+
+static void
+l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg)
+{
+	struct sk_buff *skb = arg;
+	layer2_t *l2 = fi->userdata;
+
+	if (get_PollFlagFree(l2, skb))
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'C');
+	else
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'D');
+
+}
+
+static void
+l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
+{
+	struct sk_buff *skb = arg;
+	layer2_t *l2 = fi->userdata;
+
+	if (get_PollFlagFree(l2, skb))
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'B');
+	else {
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'E');
+		establishlink(fi);
+		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+	}
+}
+
+static void
+l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg)
+{
+	struct sk_buff *skb = arg;
+	layer2_t *l2 = fi->userdata;
+
+	if (get_PollFlagFree(l2, skb))
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'B');
+	else {
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'E');
+	}
+	establishlink(fi);
+	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+}
+
+static void
+l2_go_st3(struct FsmInst *fi, int event, void *arg)
+{
+	dev_kfree_skb((struct sk_buff *)arg);
+	mISDN_FsmChangeState(fi, ST_L2_3);
+}
+
+static void
+l2_mdl_assign(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t	*l2 = fi->userdata;
+	struct sk_buff	*skb = arg;
+	mISDN_head_t	*hh;
+
+	mISDN_FsmChangeState(fi, ST_L2_3);
+	skb_trim(skb, 0);
+	hh = mISDN_HEAD_P(skb);
+	hh->prim = MDL_ASSIGN | INDICATION;
+	hh->dinfo = 0;
+	if (l2_tei(l2->tm, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	skb_queue_tail(&l2->ui_queue, skb);
+	mISDN_FsmChangeState(fi, ST_L2_2);
+	if ((skb = create_link_skb(MDL_ASSIGN | INDICATION, 0, 0, NULL, 0))) {
+		if (l2_tei(l2->tm, skb))
+			dev_kfree_skb(skb);
+	}
+}
+
+static void
+l2_queue_ui(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	skb_queue_tail(&l2->ui_queue, skb);
+}
+
+static void
+tx_ui(layer2_t *l2)
+{
+	struct sk_buff *skb;
+	u_char header[MAX_HEADER_LEN];
+	int i;
+
+	i = sethdraddr(l2, header, CMD);
+	if (test_bit(FLG_LAPD_NET, &l2->flag))
+		header[1] = 0xff; /* tei 127 */
+	header[i++] = UI;
+	while ((skb = skb_dequeue(&l2->ui_queue))) {
+		memcpy(skb_push(skb, i), header, i);
+		enqueue_ui(l2, skb);
+	}
+}
+
+static void
+l2_send_ui(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	skb_queue_tail(&l2->ui_queue, skb);
+	tx_ui(l2);
+}
+
+static void
+l2_got_ui(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	skb_pull(skb, l2headersize(l2, 1));
+/*
+ *		in states 1-3 for broadcast
+ */
+	if (l2up(l2, DL_UNITDATA | INDICATION, mISDN_HEAD_DINFO(skb), skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l2_establish(struct FsmInst *fi, int event, void *arg)
+{
+	struct sk_buff *skb = arg;
+	layer2_t *l2 = fi->userdata;
+
+	if (!test_bit(FLG_LAPD_NET, &l2->flag)) {
+		establishlink(fi);
+		test_and_set_bit(FLG_L3_INIT, &l2->flag);
+	}
+	dev_kfree_skb(skb);
+}
+
+static void
+l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg)
+{
+	struct sk_buff *skb = arg;
+	layer2_t *l2 = fi->userdata;
+
+	discard_queue(&l2->i_queue);
+	test_and_set_bit(FLG_L3_INIT, &l2->flag);
+	test_and_clear_bit(FLG_PEND_REL, &l2->flag);
+	dev_kfree_skb(skb);
+}
+
+static void
+l2_l3_reestablish(struct FsmInst *fi, int event, void *arg)
+{
+	struct sk_buff *skb = arg;
+	layer2_t *l2 = fi->userdata;
+
+	discard_queue(&l2->i_queue);
+	establishlink(fi);
+	test_and_set_bit(FLG_L3_INIT, &l2->flag);
+	dev_kfree_skb(skb);
+}
+
+static void
+l2_release(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	skb_trim(skb, 0);
+	if (l2up(l2, DL_RELEASE | CONFIRM, 0, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+l2_pend_rel(struct FsmInst *fi, int event, void *arg)
+{
+	struct sk_buff *skb = arg;
+	layer2_t *l2 = fi->userdata;
+
+	test_and_set_bit(FLG_PEND_REL, &l2->flag);
+	dev_kfree_skb(skb);
+}
+
+static void
+l2_disconnect(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	discard_queue(&l2->i_queue);
+	freewin(l2);
+	mISDN_FsmChangeState(fi, ST_L2_6);
+	l2->rc = 0;
+	send_uframe(l2, NULL, DISC | 0x10, CMD);
+	mISDN_FsmDelTimer(&l2->t203, 1);
+	restart_t200(l2, 2);
+	if (skb)
+		dev_kfree_skb(skb);
+}
+
+static void
+l2_start_multi(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t	*l2 = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	l2->vs = 0;
+	l2->va = 0;
+	l2->vr = 0;
+	l2->sow = 0;
+	clear_exception(l2);
+	send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP);
+	mISDN_FsmChangeState(fi, ST_L2_7);
+	mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
+	skb_trim(skb, 0);
+	if (l2up(l2, DL_ESTABLISH | INDICATION, 0, skb))
+		dev_kfree_skb(skb);
+
+	mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
+		MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED,
+		0, NULL, 0);
+}
+
+static void
+l2_send_UA(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
+}
+
+static void
+l2_send_DM(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	send_uframe(l2, skb, DM | get_PollFlag(l2, skb), RSP);
+}
+
+static void
+l2_restart_multi(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t	*l2 = fi->userdata;
+	struct sk_buff	*skb = arg;
+	int		est = 0;
+
+	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
+
+	l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'F');
+
+	if (l2->vs != l2->va) {
+		discard_queue(&l2->i_queue);
+		est = 1;
+	}
+
+	clear_exception(l2);
+	l2->vs = 0;
+	l2->va = 0;
+	l2->vr = 0;
+	l2->sow = 0;
+	mISDN_FsmChangeState(fi, ST_L2_7);
+	stop_t200(l2, 3);
+	mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
+
+	if (est) {
+		l2up_create(l2, DL_ESTABLISH | INDICATION, 0, 0, NULL);
+		mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
+			MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED,
+			0, NULL, 0);
+	}
+
+	if (skb_queue_len(&l2->i_queue) && cansend(l2))
+		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+}
+
+static void
+l2_stop_multi(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t	*l2 = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	mISDN_FsmChangeState(fi, ST_L2_4);
+	mISDN_FsmDelTimer(&l2->t203, 3);
+	stop_t200(l2, 4);
+
+	send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
+	discard_queue(&l2->i_queue);
+	freewin(l2);
+	lapb_dl_release_l2l3(l2, INDICATION);
+
+	mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
+		MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_RELEASED,
+		0, NULL, 0);
+}
+
+static void
+l2_connected(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t	*l2 = fi->userdata;
+	struct sk_buff	*skb = arg;
+	int		pr=-1;
+
+	if (!get_PollFlag(l2, skb)) {
+		l2_mdl_error_ua(fi, event, arg);
+		return;
+	}
+	dev_kfree_skb(skb);
+	if (test_and_clear_bit(FLG_PEND_REL, &l2->flag))
+		l2_disconnect(fi, event, NULL);
+	if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) {
+		pr = DL_ESTABLISH | CONFIRM;
+	} else if (l2->vs != l2->va) {
+		discard_queue(&l2->i_queue);
+		pr = DL_ESTABLISH | INDICATION;
+	}
+	stop_t200(l2, 5);
+	l2->vr = 0;
+	l2->vs = 0;
+	l2->va = 0;
+	l2->sow = 0;
+	mISDN_FsmChangeState(fi, ST_L2_7);
+	mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4);
+	if (pr != -1)
+		l2up_create(l2, pr, 0, 0, NULL);
+
+	if (skb_queue_len(&l2->i_queue) && cansend(l2))
+		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+
+	mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
+		MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED,
+		0, NULL, 0);
+}
+
+static void
+l2_released(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	if (!get_PollFlag(l2, skb)) {
+		l2_mdl_error_ua(fi, event, arg);
+		return;
+	}
+	dev_kfree_skb(skb);
+	stop_t200(l2, 6);
+	lapb_dl_release_l2l3(l2, CONFIRM);
+	mISDN_FsmChangeState(fi, ST_L2_4);
+
+	mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
+		MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_RELEASED,
+		0, NULL, 0);
+}
+
+static void
+l2_reestablish(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	if (!get_PollFlagFree(l2, skb)) {
+		establishlink(fi);
+		test_and_set_bit(FLG_L3_INIT, &l2->flag);
+	}
+}
+
+static void
+l2_st5_dm_release(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	if (get_PollFlagFree(l2, skb)) {
+		stop_t200(l2, 7);
+	 	if (!test_bit(FLG_L3_INIT, &l2->flag))
+			discard_queue(&l2->i_queue);
+		if (test_bit(FLG_LAPB, &l2->flag))
+			l2down_create(l2, PH_DEACTIVATE | REQUEST, 0, 0, NULL);
+		st5_dl_release_l2l3(l2);
+		mISDN_FsmChangeState(fi, ST_L2_4);
+	}
+}
+
+static void
+l2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	if (get_PollFlagFree(l2, skb)) {
+		stop_t200(l2, 8);
+		lapb_dl_release_l2l3(l2, CONFIRM);
+		mISDN_FsmChangeState(fi, ST_L2_4);
+		mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
+			MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_RELEASED,
+			0, NULL, 0);
+	}
+}
+
+void
+enquiry_cr(layer2_t *l2, u_char typ, u_char cr, u_char pf)
+{
+	struct sk_buff *skb;
+	u_char tmp[MAX_HEADER_LEN];
+	int i;
+
+	i = sethdraddr(l2, tmp, cr);
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		tmp[i++] = typ;
+		tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
+	} else
+		tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
+	if (!(skb = alloc_skb(i, GFP_ATOMIC))) {
+		printk(KERN_WARNING "isdnl2 can't alloc sbbuff for enquiry_cr\n");
+		return;
+	}
+	memcpy(skb_put(skb, i), tmp, i);
+	enqueue_super(l2, skb);
+}
+
+inline void
+enquiry_response(layer2_t *l2)
+{
+	if (test_bit(FLG_OWN_BUSY, &l2->flag))
+		enquiry_cr(l2, RNR, RSP, 1);
+	else
+		enquiry_cr(l2, RR, RSP, 1);
+	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+}
+
+inline void
+transmit_enquiry(layer2_t *l2)
+{
+	if (test_bit(FLG_OWN_BUSY, &l2->flag))
+		enquiry_cr(l2, RNR, CMD, 1);
+	else
+		enquiry_cr(l2, RR, CMD, 1);
+	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+	start_t200(l2, 9);
+}
+
+
+static void
+nrerrorrecovery(struct FsmInst *fi)
+{
+	layer2_t *l2 = fi->userdata;
+
+	l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'J');
+	establishlink(fi);
+	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+}
+
+static void
+invoke_retransmission(layer2_t *l2, unsigned int nr)
+{
+	u_int	p1;
+
+	if (l2->vs != nr) {
+		while (l2->vs != nr) {
+			(l2->vs)--;
+			if(test_bit(FLG_MOD128, &l2->flag)) {
+				l2->vs %= 128;
+				p1 = (l2->vs - l2->va) % 128;
+			} else {
+				l2->vs %= 8;
+				p1 = (l2->vs - l2->va) % 8;
+			}
+			p1 = (p1 + l2->sow) % l2->window;
+			if (l2->windowar[p1])
+				skb_queue_head(&l2->i_queue, l2->windowar[p1]);
+			else
+				printk(KERN_WARNING "%s: windowar[%d] is NULL\n", __FUNCTION__, p1);
+			l2->windowar[p1] = NULL;
+		}
+		mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
+	}
+}
+
+static void
+l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+	int PollFlag, rsp, typ = RR;
+	unsigned int nr;
+
+	rsp = *skb->data & 0x2;
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+
+	skb_pull(skb, l2addrsize(l2));
+	if (IsRNR(skb->data, l2)) {
+		set_peer_busy(l2);
+		typ = RNR;
+	} else
+		clear_peer_busy(l2);
+	if (IsREJ(skb->data, l2))
+		typ = REJ;
+
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		PollFlag = (skb->data[1] & 0x1) == 0x1;
+		nr = skb->data[1] >> 1;
+	} else {
+		PollFlag = (skb->data[0] & 0x10);
+		nr = (skb->data[0] >> 5) & 0x7;
+	}
+	dev_kfree_skb(skb);
+
+	if (PollFlag) {
+		if (rsp)
+			l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'A');
+		else
+			enquiry_response(l2);
+	}
+	if (legalnr(l2, nr)) {
+		if (typ == REJ) {
+			setva(l2, nr);
+			invoke_retransmission(l2, nr);
+			stop_t200(l2, 10);
+			if (mISDN_FsmAddTimer(&l2->t203, l2->T203,
+					EV_L2_T203, NULL, 6))
+				l2m_debug(&l2->l2m, "Restart T203 ST7 REJ");
+		} else if ((nr == l2->vs) && (typ == RR)) {
+			setva(l2, nr);
+			stop_t200(l2, 11);
+			mISDN_FsmRestartTimer(&l2->t203, l2->T203,
+					EV_L2_T203, NULL, 7);
+		} else if ((l2->va != nr) || (typ == RNR)) {
+			setva(l2, nr);
+			if (typ != RR)
+				mISDN_FsmDelTimer(&l2->t203, 9);
+			restart_t200(l2, 12);
+		}
+		if (skb_queue_len(&l2->i_queue) && (typ == RR)) {
+			mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+		}
+	} else
+		nrerrorrecovery(fi);
+}
+
+static void
+l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	if (!test_bit(FLG_L3_INIT, &l2->flag))
+		skb_queue_tail(&l2->i_queue, skb);
+	else
+		dev_kfree_skb(skb);
+}
+
+static void
+l2_feed_i_pull(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	skb_queue_tail(&l2->i_queue, skb);
+	mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+}
+
+static void
+l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	skb_queue_tail(&l2->i_queue, skb);
+}
+
+static void
+l2_got_iframe(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t	*l2 = fi->userdata;
+	struct sk_buff	*skb = arg;
+	int		PollFlag, i;
+	u_int		ns, nr;
+
+	i = l2addrsize(l2);
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		PollFlag = ((skb->data[i + 1] & 0x1) == 0x1);
+		ns = skb->data[i] >> 1;
+		nr = (skb->data[i + 1] >> 1) & 0x7f;
+	} else {
+		PollFlag = (skb->data[i] & 0x10);
+		ns = (skb->data[i] >> 1) & 0x7;
+		nr = (skb->data[i] >> 5) & 0x7;
+	}
+	if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
+		dev_kfree_skb(skb);
+		if (PollFlag)
+			enquiry_response(l2);
+	} else {
+		if (l2->vr == ns) {
+			l2->vr++;
+			if(test_bit(FLG_MOD128, &l2->flag))
+				l2->vr %= 128;
+			else
+				l2->vr %= 8;
+			test_and_clear_bit(FLG_REJEXC, &l2->flag);
+			if (PollFlag)
+				enquiry_response(l2);
+			else
+				test_and_set_bit(FLG_ACK_PEND, &l2->flag);
+			skb_pull(skb, l2headersize(l2, 0));
+			if (l2up(l2, DL_DATA | INDICATION, mISDN_HEAD_DINFO(skb), skb))
+				dev_kfree_skb(skb);
+		} else {
+			/* n(s)!=v(r) */
+			dev_kfree_skb(skb);
+			if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
+				if (PollFlag)
+					enquiry_response(l2);
+			} else {
+				enquiry_cr(l2, REJ, RSP, PollFlag);
+				test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+			}
+		}
+	}
+	if (legalnr(l2, nr)) {
+		if (!test_bit(FLG_PEER_BUSY, &l2->flag) && (fi->state == ST_L2_7)) {
+			if (nr == l2->vs) {
+				stop_t200(l2, 13);
+				mISDN_FsmRestartTimer(&l2->t203, l2->T203,
+						EV_L2_T203, NULL, 7);
+			} else if (nr != l2->va)
+				restart_t200(l2, 14);
+		}
+		setva(l2, nr);
+	} else {
+		nrerrorrecovery(fi);
+		return;
+	}
+	if (skb_queue_len(&l2->i_queue) && (fi->state == ST_L2_7))
+		mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+	if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag))
+		enquiry_cr(l2, RR, RSP, 0);
+}
+
+static void
+l2_got_tei(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t	*l2 = fi->userdata;
+	struct sk_buff	*skb = arg;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+
+	l2->tei = hh->dinfo;
+	dev_kfree_skb(skb);
+	if (fi->state == ST_L2_3) {
+		establishlink(fi);
+		test_and_set_bit(FLG_L3_INIT, &l2->flag);
+	} else
+		mISDN_FsmChangeState(fi, ST_L2_4);
+	if (skb_queue_len(&l2->ui_queue))
+		tx_ui(l2);
+}
+
+static void
+l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
+		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
+	} else if (l2->rc == l2->N200) {
+		mISDN_FsmChangeState(fi, ST_L2_4);
+		test_and_clear_bit(FLG_T200_RUN, &l2->flag);
+		discard_queue(&l2->i_queue);
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'G');
+		if (test_bit(FLG_LAPB, &l2->flag))
+			l2down_create(l2, PH_DEACTIVATE | REQUEST, 0, 0, NULL);
+		st5_dl_release_l2l3(l2);
+	} else {
+		l2->rc++;
+		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
+		send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ?
+			SABME : SABM) | 0x10, CMD);
+	}
+}
+
+static void
+l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
+		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
+	} else if (l2->rc == l2->N200) {
+		mISDN_FsmChangeState(fi, ST_L2_4);
+		test_and_clear_bit(FLG_T200_RUN, &l2->flag);
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'H');
+		lapb_dl_release_l2l3(l2, CONFIRM);
+	} else {
+		l2->rc++;
+		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200,
+			    NULL, 9);
+		send_uframe(l2, NULL, DISC | 0x10, CMD);
+	}
+}
+
+static void
+l2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
+		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
+		return;
+	}
+	test_and_clear_bit(FLG_T200_RUN, &l2->flag);
+	l2->rc = 0;
+	mISDN_FsmChangeState(fi, ST_L2_8);
+	transmit_enquiry(l2);
+	l2->rc++;
+}
+
+static void
+l2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
+		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9);
+		return;
+	}
+	test_and_clear_bit(FLG_T200_RUN, &l2->flag);
+	if (l2->rc == l2->N200) {
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'I');
+		establishlink(fi);
+		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+	} else {
+		transmit_enquiry(l2);
+		l2->rc++;
+	}
+}
+
+static void
+l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	if (test_bit(FLG_LAPD, &l2->flag) &&
+		test_bit(FLG_DCHAN_BUSY, &l2->flag)) {
+		mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9);
+		return;
+	}
+	mISDN_FsmChangeState(fi, ST_L2_8);
+	transmit_enquiry(l2);
+	l2->rc = 0;
+}
+
+static void
+l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t	*l2 = fi->userdata;
+	struct sk_buff	*skb, *nskb, *oskb;
+	u_char		header[MAX_HEADER_LEN];
+	u_int		i, p1;
+
+	if (!cansend(l2))
+		return;
+
+	skb = skb_dequeue(&l2->i_queue);
+	if (!skb)
+		return;
+
+	if(test_bit(FLG_MOD128, &l2->flag))
+		p1 = (l2->vs - l2->va) % 128;
+	else
+		p1 = (l2->vs - l2->va) % 8;
+	p1 = (p1 + l2->sow) % l2->window;
+	if (l2->windowar[p1]) {
+		printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n",
+		       p1);
+		dev_kfree_skb(l2->windowar[p1]);
+	}
+	l2->windowar[p1] = skb;
+	i = sethdraddr(l2, header, CMD);
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		header[i++] = l2->vs << 1;
+		header[i++] = l2->vr << 1;
+		l2->vs = (l2->vs + 1) % 128;
+	} else {
+		header[i++] = (l2->vr << 5) | (l2->vs << 1);
+		l2->vs = (l2->vs + 1) % 8;
+	}
+
+	nskb = skb_clone(skb, GFP_ATOMIC);
+	p1 = skb_headroom(nskb);
+	if (p1 >= i)
+		memcpy(skb_push(nskb, i), header, i);
+	else {
+		printk(KERN_WARNING
+			"isdnl2 pull_iqueue skb header(%d/%d) too short\n", i, p1);
+		oskb = nskb;
+		nskb = alloc_skb(oskb->len + i, GFP_ATOMIC);
+		if (!nskb) {
+			dev_kfree_skb(oskb);
+			printk(KERN_WARNING "%s: no skb mem\n", __FUNCTION__);
+			return;
+		}
+		memcpy(skb_put(nskb, i), header, i);
+		memcpy(skb_put(nskb, oskb->len), oskb->data, oskb->len);
+		dev_kfree_skb(oskb);
+	}
+	l2down(l2, PH_DATA_REQ, mISDN_HEAD_DINFO(skb), nskb);
+	test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+	if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) {
+		mISDN_FsmDelTimer(&l2->t203, 13);
+		mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11);
+	}
+}
+
+static void
+l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+	int PollFlag, rsp, rnr = 0;
+	unsigned int nr;
+
+	rsp = *skb->data & 0x2;
+	if (test_bit(FLG_ORIG, &l2->flag))
+		rsp = !rsp;
+
+	skb_pull(skb, l2addrsize(l2));
+
+	if (IsRNR(skb->data, l2)) {
+		set_peer_busy(l2);
+		rnr = 1;
+	} else
+		clear_peer_busy(l2);
+
+	if (test_bit(FLG_MOD128, &l2->flag)) {
+		PollFlag = (skb->data[1] & 0x1) == 0x1;
+		nr = skb->data[1] >> 1;
+	} else {
+		PollFlag = (skb->data[0] & 0x10);
+		nr = (skb->data[0] >> 5) & 0x7;
+	}
+	dev_kfree_skb(skb);
+	if (rsp && PollFlag) {
+		if (legalnr(l2, nr)) {
+			if (rnr) {
+				restart_t200(l2, 15);
+			} else {
+				stop_t200(l2, 16);
+				mISDN_FsmAddTimer(&l2->t203, l2->T203,
+					    EV_L2_T203, NULL, 5);
+				setva(l2, nr);
+			}
+			invoke_retransmission(l2, nr);
+			mISDN_FsmChangeState(fi, ST_L2_7);
+			if (skb_queue_len(&l2->i_queue) && cansend(l2))
+				mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
+		} else
+			nrerrorrecovery(fi);
+	} else {
+		if (!rsp && PollFlag)
+			enquiry_response(l2);
+		if (legalnr(l2, nr)) {
+			setva(l2, nr);
+		} else
+			nrerrorrecovery(fi);
+	}
+}
+
+static void
+l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	skb_pull(skb, l2addrsize(l2) + 1);
+
+	if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) ||		/* I or S */
+	    (IsUA(skb->data) && (fi->state == ST_L2_7))) {
+		l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'K');
+		establishlink(fi);
+		test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+	}
+	dev_kfree_skb(skb);
+}
+
+static void
+l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	discard_queue(&l2->ui_queue);
+	l2->tei = -1;
+	mISDN_FsmChangeState(fi, ST_L2_1);
+	dev_kfree_skb(skb);
+}
+
+static void
+l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	discard_queue(&l2->ui_queue);
+	l2->tei = -1;
+	skb_trim(skb, 0);
+	if (l2up(l2, DL_RELEASE | INDICATION, 0, skb))
+		dev_kfree_skb(skb);
+	mISDN_FsmChangeState(fi, ST_L2_1);
+}
+
+static void
+l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	discard_queue(&l2->i_queue);
+	discard_queue(&l2->ui_queue);
+	freewin(l2);
+	l2->tei = -1;
+	stop_t200(l2, 17);
+	st5_dl_release_l2l3(l2);
+	mISDN_FsmChangeState(fi, ST_L2_1);
+	dev_kfree_skb(skb);
+}
+
+static void
+l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	discard_queue(&l2->ui_queue);
+	l2->tei = -1;
+	stop_t200(l2, 18);
+	if (l2up(l2, DL_RELEASE | CONFIRM, 0, skb))
+		dev_kfree_skb(skb);
+	mISDN_FsmChangeState(fi, ST_L2_1);
+}
+
+static void
+l2_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	discard_queue(&l2->i_queue);
+	discard_queue(&l2->ui_queue);
+	freewin(l2);
+	l2->tei = -1;
+	stop_t200(l2, 17);
+	mISDN_FsmDelTimer(&l2->t203, 19);
+	if (l2up(l2, DL_RELEASE | INDICATION, 0, skb))
+		dev_kfree_skb(skb);
+	mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
+		MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_RELEASED,
+		0, NULL, 0);
+	mISDN_FsmChangeState(fi, ST_L2_1);
+}
+
+static void
+l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	discard_queue(&l2->i_queue);
+	discard_queue(&l2->ui_queue);
+	if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
+		if (!l2up(l2, DL_RELEASE | INDICATION, 0, skb))
+			return;
+	dev_kfree_skb(skb);
+}
+
+static void
+l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	discard_queue(&l2->i_queue);
+	discard_queue(&l2->ui_queue);
+	freewin(l2);
+	stop_t200(l2, 19);
+	st5_dl_release_l2l3(l2);
+	mISDN_FsmChangeState(fi, ST_L2_4);
+	dev_kfree_skb(skb);
+}
+
+static void
+l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	discard_queue(&l2->ui_queue);
+	stop_t200(l2, 20);
+	if (l2up(l2, DL_RELEASE | CONFIRM, 0, skb))
+		dev_kfree_skb(skb);
+	mISDN_FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_persistant_da(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	discard_queue(&l2->i_queue);
+	discard_queue(&l2->ui_queue);
+	freewin(l2);
+	stop_t200(l2, 19);
+	mISDN_FsmDelTimer(&l2->t203, 19);
+	if (l2up(l2, DL_RELEASE | INDICATION, 0, skb))
+		dev_kfree_skb(skb);
+	mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
+		MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_RELEASED,
+		0, NULL, 0);
+	mISDN_FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_set_own_busy(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	if(!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) {
+		enquiry_cr(l2, RNR, RSP, 0);
+		test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+	}
+	if (skb)
+		dev_kfree_skb(skb);
+}
+
+static void
+l2_clear_own_busy(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	if(!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) {
+		enquiry_cr(l2, RR, RSP, 0);
+		test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+	}
+	if (skb)
+		dev_kfree_skb(skb);
+}
+
+static void
+l2_frame_error(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	l2mgr(l2, MDL_ERROR | INDICATION, arg);
+}
+
+static void
+l2_frame_error_reest(struct FsmInst *fi, int event, void *arg)
+{
+	layer2_t *l2 = fi->userdata;
+
+	l2mgr(l2, MDL_ERROR | INDICATION, arg);
+	establishlink(fi);
+	test_and_clear_bit(FLG_L3_INIT, &l2->flag);
+}
+
+static struct FsmNode L2FnList[] =
+{
+	{ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
+	{ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
+	{ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish},
+	{ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3},
+	{ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
+	{ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish},
+	{ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release},
+	{ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel},
+	{ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect},
+	{ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect},
+	{ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest},
+	{ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull},
+	{ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
+	{ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign},
+	{ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui},
+	{ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui},
+	{ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui},
+	{ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui},
+	{ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui},
+	{ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui},
+	{ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui},
+	{ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei},
+	{ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei},
+	{ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
+	{ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove},
+	{ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove},
+	{ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove},
+	{ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove},
+	{ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove},
+	{ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
+	{ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
+	{ST_L2_4, EV_L2_SABME, l2_start_multi},
+	{ST_L2_5, EV_L2_SABME, l2_send_UA},
+	{ST_L2_6, EV_L2_SABME, l2_send_DM},
+	{ST_L2_7, EV_L2_SABME, l2_restart_multi},
+	{ST_L2_8, EV_L2_SABME, l2_restart_multi},
+	{ST_L2_4, EV_L2_DISC, l2_send_DM},
+	{ST_L2_5, EV_L2_DISC, l2_send_DM},
+	{ST_L2_6, EV_L2_DISC, l2_send_UA},
+	{ST_L2_7, EV_L2_DISC, l2_stop_multi},
+	{ST_L2_8, EV_L2_DISC, l2_stop_multi},
+	{ST_L2_4, EV_L2_UA, l2_mdl_error_ua},
+	{ST_L2_5, EV_L2_UA, l2_connected},
+	{ST_L2_6, EV_L2_UA, l2_released},
+	{ST_L2_7, EV_L2_UA, l2_mdl_error_ua},
+	{ST_L2_8, EV_L2_UA, l2_mdl_error_ua},
+	{ST_L2_4, EV_L2_DM, l2_reestablish},
+	{ST_L2_5, EV_L2_DM, l2_st5_dm_release},
+	{ST_L2_6, EV_L2_DM, l2_st6_dm_release},
+	{ST_L2_7, EV_L2_DM, l2_mdl_error_dm},
+	{ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm},
+	{ST_L2_1, EV_L2_UI, l2_got_ui},
+	{ST_L2_2, EV_L2_UI, l2_got_ui},
+	{ST_L2_3, EV_L2_UI, l2_got_ui},
+	{ST_L2_4, EV_L2_UI, l2_got_ui},
+	{ST_L2_5, EV_L2_UI, l2_got_ui},
+	{ST_L2_6, EV_L2_UI, l2_got_ui},
+	{ST_L2_7, EV_L2_UI, l2_got_ui},
+	{ST_L2_8, EV_L2_UI, l2_got_ui},
+	{ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
+	{ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
+	{ST_L2_7, EV_L2_SUPER, l2_st7_got_super},
+	{ST_L2_8, EV_L2_SUPER, l2_st8_got_super},
+	{ST_L2_7, EV_L2_I, l2_got_iframe},
+	{ST_L2_8, EV_L2_I, l2_got_iframe},
+	{ST_L2_5, EV_L2_T200, l2_st5_tout_200},
+	{ST_L2_6, EV_L2_T200, l2_st6_tout_200},
+	{ST_L2_7, EV_L2_T200, l2_st7_tout_200},
+	{ST_L2_8, EV_L2_T200, l2_st8_tout_200},
+	{ST_L2_7, EV_L2_T203, l2_st7_tout_203},
+	{ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
+	{ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
+	{ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy},
+	{ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
+	{ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy},
+	{ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error},
+	{ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error},
+	{ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
+	{ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
+	{ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
+	{ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da},
+	{ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
+	{ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
+	{ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da},
+	{ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da},
+	{ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da},
+	{ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da},
+	{ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da},
+};
+
+#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
+
+static int
+ph_data_indication(layer2_t *l2, mISDN_head_t *hh, struct sk_buff *skb) {
+	u_char	*datap = skb->data;
+	int	ret = -EINVAL;
+	int	psapi, ptei;
+	u_int	l;
+	int	c = 0;
+
+
+	l = l2addrsize(l2);
+	if (skb->len <= l) {
+		mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N');
+		return(ret);
+	}
+	if (test_bit(FLG_LAPD, &l2->flag)) {
+		psapi = *datap++;
+		ptei = *datap++;
+		if ((psapi & 1) || !(ptei & 1)) {
+			printk(KERN_WARNING "l2 D-channel addr:%x frame wrong EA0/EA1\n", l2->inst.id);
+			return(ret);
+		}
+		psapi >>= 2;
+		ptei >>= 1;
+		if ((psapi != l2->sapi) && (psapi != TEI_SAPI)) {
+			/* not our bussiness */
+			// printk(KERN_DEBUG "%s: sapi %d/%d sapi mismatch\n", __FUNCTION__,
+			//	psapi, l2->sapi);
+			dev_kfree_skb(skb);
+			return(0);
+		}
+		if (ptei == GROUP_TEI) {
+			if (psapi == TEI_SAPI) {
+				hh->prim = MDL_UNITDATA | INDICATION;
+				return(l2_tei(l2->tm, skb));
+			}
+		} else if ((ptei != l2->tei) || (psapi == TEI_SAPI)) {
+			/* not our bussiness */
+			// printk(KERN_DEBUG "%s: tei %d/%d sapi %d mismatch\n", __FUNCTION__,
+			//	ptei, l2->tei, psapi);
+			dev_kfree_skb(skb);
+			return(0);
+		}
+	} else
+		datap += l;
+	if (!(*datap & 1)) {	/* I-Frame */
+		if(!(c = iframe_error(l2, skb)))
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_I, skb);
+	} else if (IsSFrame(datap, l2)) {	/* S-Frame */
+		if(!(c = super_error(l2, skb)))
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SUPER, skb);
+	} else if (IsUI(datap)) {
+		if(!(c = UI_error(l2, skb)))
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UI, skb);
+	} else if (IsSABME(datap, l2)) {
+		if(!(c = unnum_error(l2, skb, CMD)))
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SABME, skb);
+	} else if (IsUA(datap)) {
+		if(!(c = unnum_error(l2, skb, RSP)))
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UA, skb);
+	} else if (IsDISC(datap)) {
+		if(!(c = unnum_error(l2, skb, CMD)))
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DISC, skb);
+	} else if (IsDM(datap)) {
+		if(!(c = unnum_error(l2, skb, RSP)))
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DM, skb);
+	} else if (IsFRMR(datap)) {
+		if(!(c = FRMR_error(l2, skb)))
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_FRMR, skb);
+	} else {
+		c = 'L';
+	}
+	if (c) {
+		printk(KERN_WARNING "l2 D-channel frame error %c\n",c);
+		mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
+	}
+	return(ret);
+}
+
+static int
+l2from_down(layer2_t *l2, struct sk_buff *askb, mISDN_head_t *hh)
+{
+	int 		ret = -EINVAL;
+	struct sk_buff	*cskb = askb;
+
+//	printk(KERN_DEBUG "%s: prim(%x)\n", __FUNCTION__, hh->prim);
+	if (hh->prim == (PH_DATA | CONFIRM))
+		return(ph_data_confirm(&l2->inst, hh, askb));
+	if (hh->prim == (MDL_FINDTEI | REQUEST)) {
+		ret = -ESRCH;
+		if (test_bit(FLG_LAPD, &l2->flag)) {
+			if (l2->tei == hh->dinfo) {
+				void *p = ((u_char *)askb->data);
+				teimgr_t **tp = p;
+				if (tp) {
+					*tp = l2->tm;
+					dev_kfree_skb(askb);
+					return(0);
+				}
+			}
+		}
+#ifdef FIXME
+		if (next && next->func)
+			ret = next->func(next, askb);
+#endif
+		return(ret);
+	}
+#ifdef FIXME
+	if (next) {
+		if (next->func) {
+			if (!(cskb = skb_clone(askb, GFP_ATOMIC)))
+				return(next->func(next, askb));
+			else
+				sh = *hh;
+		}
+	}
+#endif
+	switch (hh->prim) {
+		case (PH_DATA_IND):
+			ret = ph_data_indication(l2, hh, cskb);
+			break;
+		case (PH_CONTROL | INDICATION):
+			if (hh->dinfo == HW_D_BLOCKED)
+				test_and_set_bit(FLG_DCHAN_BUSY, &l2->flag);
+			else if (hh->dinfo == HW_D_NOBLOCKED)
+				test_and_clear_bit(FLG_DCHAN_BUSY, &l2->flag);
+			else
+				break;
+			break;
+		case (PH_ACTIVATE | CONFIRM):
+		case (PH_ACTIVATE | INDICATION):
+			test_and_set_bit(FLG_L1_ACTIV, &l2->flag);
+			if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) 
+				ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_ESTABLISH_REQ, cskb);
+			break;
+		case (PH_DEACTIVATE | INDICATION):
+		case (PH_DEACTIVATE | CONFIRM):
+			test_and_clear_bit(FLG_L1_ACTIV, &l2->flag);
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, cskb);
+			if (ret)
+				dev_kfree_skb(cskb);
+			ret = 0;
+			break;
+		default:
+			if (l2->debug)
+				l2m_debug(&l2->l2m, "l2 unknown pr %x", hh->prim);
+			ret = -EINVAL;
+			break;
+	}
+	if (ret) {
+		dev_kfree_skb(cskb);
+		ret = 0;
+	}
+#ifdef FIXME
+	if (next && next->func) {
+		*hh = sh;
+		ret = next->func(next, askb);
+	}
+#endif
+	return(ret);
+}
+
+static int
+l2from_up(layer2_t *l2, struct sk_buff *skb, mISDN_head_t *hh) {
+	int		ret = -EINVAL;
+
+	if (hh->addr & FLG_MSG_CLONED)
+		return(l2down_raw(l2, skb));
+	switch (hh->prim) {
+		case (DL_DATA | REQUEST):
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb);
+			break;
+		case (DL_UNITDATA | REQUEST):
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, skb);
+			break;
+		case (DL_ESTABLISH | REQUEST):
+			if (test_bit(FLG_L1_ACTIV, &l2->flag)) {
+				if (test_bit(FLG_LAPD, &l2->flag) ||
+					test_bit(FLG_ORIG, &l2->flag)) {
+					ret = mISDN_FsmEvent(&l2->l2m,
+						EV_L2_DL_ESTABLISH_REQ, skb);
+				}
+			} else {
+				if (test_bit(FLG_LAPD, &l2->flag) ||
+					test_bit(FLG_ORIG, &l2->flag)) {
+					test_and_set_bit(FLG_ESTAB_PEND,
+						&l2->flag);
+				}
+				ret = l2down(l2, PH_ACTIVATE | REQUEST, 0, skb);
+			}
+			break;
+		case (DL_RELEASE | REQUEST):
+			if (test_bit(FLG_LAPB, &l2->flag))
+				l2down_create(l2, PH_DEACTIVATE | REQUEST,
+					0, 0, NULL);
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ, skb);
+			break;
+		case (MDL_ASSIGN | REQUEST):
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, skb);
+			break;
+		case (MDL_REMOVE | REQUEST):
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, skb);
+			break;
+		case (MDL_ERROR | RESPONSE):
+			ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, skb);
+		case (MDL_STATUS | REQUEST):
+			l2up_create(l2, MDL_STATUS | CONFIRM, hh->dinfo, 1,
+				(void *)((u_long)l2->tei));
+			break;
+		default:
+			if (l2->debug)
+				l2m_debug(&l2->l2m, "l2 unknown pr %04x", hh->prim);
+	}
+	return(ret);
+}
+
+static int
+l2_shortstatus(layer2_t *l2, struct sk_buff *skb, mISDN_head_t *hh)
+{
+	u_int	temp;
+
+	if (hh->prim == (MGR_SHORTSTATUS | REQUEST)) {
+		temp = hh->dinfo & SSTATUS_ALL;
+		if (temp == SSTATUS_ALL || temp == SSTATUS_L2) {
+			skb_trim(skb, 0);
+			if (hh->dinfo & SSTATUS_BROADCAST_BIT)
+				temp = l2->inst.id | MSG_BROADCAST;
+			else
+				temp = hh->addr | FLG_MSG_TARGET;
+			switch(l2->l2m.state) {
+				case ST_L2_7:
+				case ST_L2_8:
+					hh->dinfo = SSTATUS_L2_ESTABLISHED;
+					break;
+				default:
+					hh->dinfo = SSTATUS_L2_RELEASED;
+			}
+			hh->prim = MGR_SHORTSTATUS | CONFIRM;
+			return(mISDN_queue_message(&l2->inst, temp, skb));
+		}
+	}
+	return(-EOPNOTSUPP);
+}
+
+static int
+l2_function(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	layer2_t	*l2 = inst->privat;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	int		ret = -EINVAL;
+
+	if (debug)
+		printk(KERN_DEBUG  "%s: addr(%08x) prim(%x)\n", __FUNCTION__,  hh->addr, hh->prim);
+	if (!l2)
+		return(ret);
+
+	if (unlikely((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS))
+		return(l2_shortstatus(l2, skb, hh));
+
+	switch(hh->addr & MSG_DIR_MASK) {
+		case FLG_MSG_DOWN:
+			ret = l2from_up(l2, skb, hh);
+			break;
+		case FLG_MSG_UP:
+			ret = l2from_down(l2, skb, hh);
+			break;
+		case MSG_TO_OWNER:
+			/* FIXME: must be handled depending on type */
+			int_errtxt("not implemented yet");
+			break;
+		default:
+			/* FIXME: broadcast must be handled depending on type */
+			int_errtxt("not implemented yet");
+			break;
+	}
+	return(ret);
+}
+
+int
+tei_l2(layer2_t *l2, struct sk_buff *skb)
+{
+	mISDN_head_t	*hh;
+	int		ret = -EINVAL;
+
+	if (!l2 || !skb)
+		return(ret);
+	hh = mISDN_HEAD_P(skb);
+	if (l2->debug)
+		printk(KERN_DEBUG "%s: prim(%x)\n", __FUNCTION__, hh->prim);
+	switch(hh->prim) {
+	    case (MDL_UNITDATA | REQUEST):
+		ret = l2down(l2, PH_DATA_REQ, l2_newid(l2), skb);
+		break;
+	    case (MDL_ASSIGN | REQUEST):
+		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, skb);
+		break;
+	    case (MDL_REMOVE | REQUEST):
+		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, skb);
+		break;
+	    case (MDL_ERROR | RESPONSE):
+		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, skb);
+		break;
+	case (MDL_ERROR | REQUEST):
+		/* ETS 300-125 5.3.2.1 Test: TC13010*/
+		printk(KERN_NOTICE "MDL_ERROR|REQ (tei_l2)\n");
+		ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, skb);
+		break;
+	    case (MDL_FINDTEI | REQUEST):
+	    	ret = l2down_skb(l2, skb);
+		break;
+	}
+	return(ret);
+}
+
+static void
+l2m_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	layer2_t *l2 = fi->userdata;
+	logdata_t log;
+
+	va_start(log.args, fmt);
+	log.fmt = fmt;
+	log.head = l2->inst.name;
+	mISDN_ctrl(&l2->inst, MGR_DEBUGDATA | REQUEST, &log);
+	va_end(log.args);
+}
+
+static void
+release_l2(layer2_t *l2)
+{
+	mISDNinstance_t	*inst = &l2->inst;
+	u_long		flags;
+
+	mISDN_FsmDelTimer(&l2->t200, 21);
+	mISDN_FsmDelTimer(&l2->t203, 16);
+	discard_queue(&l2->i_queue);
+	discard_queue(&l2->ui_queue);
+	discard_queue(&l2->down_queue);
+	ReleaseWin(l2);
+	if (test_bit(FLG_LAPD, &l2->flag))
+		release_tei(l2->tm);
+#ifdef OBSOLETE
+	if (inst->up.peer) {
+		inst->up.peer->obj->ctrl(inst->up.peer,
+			MGR_DISCONNECT | REQUEST, &inst->up);
+	}
+	if (inst->down.peer) {
+		inst->down.peer->obj->ctrl(inst->down.peer,
+			MGR_DISCONNECT | REQUEST, &inst->down);
+	}
+	if (l2->cloneif) {
+		printk(KERN_DEBUG "%s: cloneif(%p) owner(%p) peer(%p)\n",
+			__FUNCTION__, l2->cloneif, l2->cloneif->owner, l2->cloneif->peer);
+		if (l2->cloneif->predecessor)
+			l2->cloneif->predecessor->clone = l2->cloneif->clone;
+		if (l2->cloneif->clone)
+			l2->cloneif->clone->predecessor = l2->cloneif->predecessor;
+		if (l2->cloneif->owner &&
+			(l2->cloneif->owner->up.clone == l2->cloneif))
+			l2->cloneif->owner->up.clone = l2->cloneif->clone;
+		kfree(l2->cloneif);
+		l2->cloneif = NULL;
+	}
+#endif
+	spin_lock_irqsave(&isdnl2.lock, flags);
+	list_del(&l2->list);
+	spin_unlock_irqrestore(&isdnl2.lock, flags);
+	mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+	if (l2->entity != MISDN_ENTITY_NONE)
+		mISDN_ctrl(inst, MGR_DELENTITY | REQUEST, (void *)((u_long)l2->entity));
+	kfree(l2);
+}
+
+static int
+new_l2(mISDNstack_t *st, mISDN_pid_t *pid) {
+	layer2_t	*nl2;
+	int		err;
+	u_char		*p;
+	u_long		flags;
+
+	if (!st || !pid)
+		return(-EINVAL);
+	if (!(nl2 = kmalloc(sizeof(layer2_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc layer2 failed\n");
+		return(-ENOMEM);
+	}
+	memset(nl2, 0, sizeof(layer2_t));
+	nl2->debug = debug;
+	nl2->next_id = 1;
+	nl2->down_id = MISDN_ID_NONE;
+	mISDN_init_instance(&nl2->inst, &isdnl2, nl2, l2_function);
+	nl2->inst.extentions = EXT_INST_CLONE;
+	memcpy(&nl2->inst.pid, pid, sizeof(mISDN_pid_t));
+	if (!mISDN_SetHandledPID(&isdnl2, &nl2->inst.pid)) {
+		int_error();
+		return(-ENOPROTOOPT);
+	}
+	switch(pid->protocol[2] & ~ISDN_PID_FEATURE_MASK) {
+	    case ISDN_PID_L2_LAPD_NET:
+	    	sprintf(nl2->inst.name, "lapdn %x", st->id>>8);
+		test_and_set_bit(FLG_LAPD, &nl2->flag);
+		test_and_set_bit(FLG_LAPD_NET, &nl2->flag);
+		test_and_set_bit(FLG_FIXED_TEI, &nl2->flag);
+		test_and_set_bit(FLG_MOD128, &nl2->flag);
+		nl2->sapi = 0;
+		nl2->tei = 88;
+		nl2->maxlen = MAX_DFRAME_LEN;
+		nl2->window = 1;
+		nl2->T200 = 1000;
+		nl2->N200 = 3;
+		nl2->T203 = 10000;
+		if (create_teimgr(nl2)) {
+			kfree(nl2);
+			return(-EINVAL);
+		}
+		break;
+	    case ISDN_PID_L2_LAPD:
+	    	sprintf(nl2->inst.name, "lapd %x", st->id>>8);
+		test_and_set_bit(FLG_LAPD, &nl2->flag);
+		test_and_set_bit(FLG_MOD128, &nl2->flag);
+		test_and_set_bit(FLG_ORIG, &nl2->flag);
+		nl2->sapi = 0;
+		nl2->tei = -1;
+		if (pid->protocol[2] & ISDN_PID_L2_DF_PTP) {
+			test_and_set_bit(FLG_PTP, &nl2->flag);
+			test_and_set_bit(FLG_FIXED_TEI, &nl2->flag);
+			nl2->tei = 0;
+		}
+		
+		nl2->maxlen = MAX_DFRAME_LEN;
+
+		if (pid->protocol[3] & ISDN_PID_L3_DF_CRLEN2) {
+			if (debug) 
+				printk("layer2: Windowsize 7\n");
+			nl2->window = 7;
+		} else {
+			if (debug) 
+				printk("layer2: Windowsize 1\n");
+			nl2->window = 1;
+		}
+		
+		nl2->T200 = 1000;
+		nl2->N200 = 3;
+		nl2->T203 = 10000;
+		if (create_teimgr(nl2)) {
+			kfree(nl2);
+			return(-EINVAL);
+		}
+		break;
+	    case ISDN_PID_L2_B_X75SLP:
+		test_and_set_bit(FLG_LAPB, &nl2->flag);
+		sprintf(nl2->inst.name, "lapb %x", st->id >> 8);
+		nl2->window = 7;
+		nl2->maxlen = MAX_DATA_SIZE;
+		nl2->T200 = 1000;
+		nl2->N200 = 4;
+		nl2->T203 = 5000;
+		nl2->addr.A = 3;
+		nl2->addr.B = 1;
+		if (nl2->inst.pid.global == 1)
+			test_and_set_bit(FLG_ORIG, &nl2->flag);
+		if (pid->param[2] && pid->pbuf) {
+			p = pid->pbuf + pid->param[2];
+			if (*p>=4) {
+				p++;
+				nl2->addr.A = *p++;
+				nl2->addr.B = *p++;
+				if (*p++ == 128)
+					test_and_set_bit(FLG_MOD128, &nl2->flag);
+				nl2->window = *p++;
+				if (nl2->window > 7)
+					nl2->window = 7;
+			}
+		}
+		break;
+	    default:
+		printk(KERN_ERR "layer2 create failed prt %x\n",
+			pid->protocol[2]);
+		kfree(nl2);
+		return(-ENOPROTOOPT);
+	}
+	skb_queue_head_init(&nl2->i_queue);
+	skb_queue_head_init(&nl2->ui_queue);
+	skb_queue_head_init(&nl2->down_queue);
+	skb_queue_head_init(&nl2->tmp_queue);
+	InitWin(nl2);
+	nl2->l2m.fsm = &l2fsm;
+	if (test_bit(FLG_LAPB, &nl2->flag) ||
+		test_bit(FLG_PTP, &nl2->flag) ||
+		test_bit(FLG_LAPD_NET, &nl2->flag))
+		nl2->l2m.state = ST_L2_4;
+	else
+		nl2->l2m.state = ST_L2_1;
+	nl2->l2m.debug = debug;
+	nl2->l2m.userdata = nl2;
+	nl2->l2m.userint = 0;
+	nl2->l2m.printdebug = l2m_debug;
+
+	mISDN_FsmInitTimer(&nl2->l2m, &nl2->t200);
+	mISDN_FsmInitTimer(&nl2->l2m, &nl2->t203);
+	spin_lock_irqsave(&isdnl2.lock, flags);
+	list_add_tail(&nl2->list, &isdnl2.ilist);
+	spin_unlock_irqrestore(&isdnl2.lock, flags);
+	err = mISDN_ctrl(&nl2->inst, MGR_NEWENTITY | REQUEST, NULL);
+	if (err) {
+		printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%d)\n",
+			__FUNCTION__, err);
+	}
+	err = mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &nl2->inst);
+	if (err) {
+		mISDN_FsmDelTimer(&nl2->t200, 0);
+		mISDN_FsmDelTimer(&nl2->t203, 0);
+		list_del(&nl2->list);
+		kfree(nl2);
+		nl2 = NULL;
+	} else {
+		mISDN_stPara_t	stp;
+
+	    	if (st->para.maxdatalen)
+		    	nl2->maxlen = st->para.maxdatalen;
+		stp.maxdatalen = 0;
+		stp.up_headerlen = 0;
+		stp.down_headerlen = l2headersize(nl2, 0);
+		mISDN_ctrl(st, MGR_ADDSTPARA | REQUEST, &stp);
+	}
+	return(err);
+}
+
+#ifdef OBSOLETE
+static int
+clone_l2(layer2_t *l2, mISDNinstance_t **new_ip) {
+	int err;
+	layer2_t	*nl2;
+	mISDNstack_t	*st;
+
+	if (!l2)
+		return(-EINVAL);
+	if (!new_ip)
+		return(-EINVAL);
+	st = (mISDNstack_t *)*new_ip;
+	if (!st)
+		return(-EINVAL);
+	err = new_l2(st, &l2->inst.pid, &nl2);
+	if (err) {
+		printk(KERN_ERR "clone l2 failed err(%d)\n", err);
+		return(err);
+	}
+	nl2->cloneif = nif;
+	nif->func = l2from_down;
+	nif->fdata = nl2;
+	nif->owner = l2->inst.down.peer;
+	nif->peer = &nl2->inst;
+	nif->stat = IF_DOWN;
+	nif->predecessor = &nif->owner->up;
+	while(nif->predecessor->clone)
+		nif->predecessor = nif->predecessor->clone;
+	nif->predecessor->clone = nif;
+	nl2->inst.down.owner = &nl2->inst;
+	nl2->inst.down.peer = &l2->inst;
+	nl2->inst.down.func = l2_chain_down;
+	nl2->inst.down.fdata = l2;
+	nl2->inst.down.stat = IF_UP;
+	*new_ip = &nl2->inst;
+	return(err);
+}
+#endif
+
+static int
+l2_status(layer2_t *l2, status_info_l2_t *si)
+{
+
+	if (!si)
+		return(-EINVAL);
+	memset(si, 0, sizeof(status_info_l2_t));
+	si->len = sizeof(status_info_l2_t) - 2*sizeof(int);
+	si->typ = STATUS_INFO_L2;
+	si->protocol = l2->inst.pid.protocol[2];
+	si->state = l2->l2m.state;
+	si->sapi = l2->sapi;
+	si->tei = l2->tei;
+	si->addr = l2->addr;
+	si->maxlen = l2->maxlen;
+	si->flag = l2->flag;
+	si->vs = l2->vs;
+	si->va = l2->va;
+	si->vr = l2->vr;
+	si->rc = l2->rc;
+	si->window = l2->window;
+	si->sow = l2->sow;
+	si->T200 = l2->T200;
+	si->N200 = l2->N200;
+	si->T203 = l2->T203;
+	si->len_i_queue = skb_queue_len(&l2->i_queue);
+	si->len_ui_queue = skb_queue_len(&l2->ui_queue);
+	si->len_d_queue = skb_queue_len(&l2->down_queue);
+	si->debug = l2->debug;
+	if (l2->tm) {
+		si->tei_state = l2->tm->tei_m.state;
+		si->tei_ri = l2->tm->ri;
+		si->T202 = l2->tm->T202;
+		si->N202 = l2->tm->N202;
+		si->tei_debug = l2->tm->debug;
+	}
+	return(0);
+}
+
+static char MName[] = "ISDNL2";
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+#endif
+#endif
+
+static int
+l2_manager(void *data, u_int prim, void *arg) {
+	mISDNinstance_t	*inst = data;
+	layer2_t	*l2l;
+	int		err = -EINVAL;
+	u_long		flags;
+
+	if (debug & 0x1000)
+		printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n", __FUNCTION__,
+			data, prim, arg);
+	if (!data)
+		return(err);
+	spin_lock_irqsave(&isdnl2.lock, flags);
+	list_for_each_entry(l2l, &isdnl2.ilist, list) {
+		if (&l2l->inst == inst) {
+			err = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&isdnl2.lock, flags);
+	if (prim == (MGR_NEWLAYER | REQUEST))
+		return(new_l2(data, arg));
+	if (err) {
+		if (debug & 0x1)
+			printk(KERN_WARNING "l2_manager prim(%x) l2 no instance\n", prim);
+		return(err);
+	}
+	switch(prim) {
+	    case MGR_NEWENTITY | CONFIRM:
+		l2l->entity = (u_long)arg & 0xffffffff;
+		break;
+	    case MGR_ADDSTPARA | INDICATION:
+	    	if (((mISDN_stPara_t *)arg)->maxdatalen)
+		    	l2l->maxlen = ((mISDN_stPara_t *)arg)->maxdatalen;
+	    case MGR_CLRSTPARA | INDICATION:
+		break;
+#ifdef OBSOLETE
+	    case MGR_CLONELAYER | REQUEST:
+		return(clone_l2(l2l, arg));
+	    case MGR_CONNECT | REQUEST:
+		return(mISDN_ConnectIF(inst, arg));
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+		return(mISDN_SetIF(inst, arg, prim, l2from_up, l2from_down, l2l));
+	    case MGR_ADDIF | REQUEST:
+		if (arg) {
+			mISDNif_t *hif = arg;
+			if (hif->stat & IF_UP) {
+				hif->fdata = l2l;
+				hif->func = l2_chain_down;
+			}
+		}
+		break;
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		return(mISDN_DisConnectIF(inst, arg));
+#endif
+	    case MGR_RELEASE | INDICATION:
+	    case MGR_UNREGLAYER | REQUEST:
+		release_l2(l2l);
+		break;
+	    case MGR_STATUS | REQUEST:
+		return(l2_status(l2l, arg));
+	    default:
+		if (debug & 0x1)
+			printk(KERN_WARNING "l2_manager prim %x not handled\n", prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+int Isdnl2_Init(void)
+{
+	int err;
+
+	printk(KERN_INFO "ISDN L2 driver version %s\n", mISDN_getrev(l2_revision));
+#ifdef MODULE
+	isdnl2.owner = THIS_MODULE;
+#endif
+	isdnl2.name = MName;
+	isdnl2.DPROTO.protocol[2] = ISDN_PID_L2_LAPD |
+		ISDN_PID_L2_LAPD_NET |
+		ISDN_PID_L2_DF_PTP;
+	isdnl2.BPROTO.protocol[2] = ISDN_PID_L2_B_X75SLP;
+	isdnl2.own_ctrl = l2_manager;
+	spin_lock_init(&isdnl2.lock);
+	INIT_LIST_HEAD(&isdnl2.ilist);
+	l2fsm.state_count = L2_STATE_COUNT;
+	l2fsm.event_count = L2_EVENT_COUNT;
+	l2fsm.strEvent = strL2Event;
+	l2fsm.strState = strL2State;
+	mISDN_FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
+	TEIInit();
+	if ((err = mISDN_register(&isdnl2))) {
+		printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
+		mISDN_FsmFree(&l2fsm);
+	} else
+		mISDN_module_register(THIS_MODULE);
+	return(err);
+}
+
+void Isdnl2_cleanup(void)
+{
+	int		err;
+	layer2_t	*l2, *nl2;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if ((err = mISDN_unregister(&isdnl2))) {
+		printk(KERN_ERR "Can't unregister ISDN layer 2 error(%d)\n", err);
+	}
+	if(!list_empty(&isdnl2.ilist)) {
+		printk(KERN_WARNING "mISDNl2 l2 list not empty\n");
+		list_for_each_entry_safe(l2, nl2, &isdnl2.ilist, list)
+			release_l2(l2);
+	}
+	TEIFree();
+	mISDN_FsmFree(&l2fsm);
+}
+
+module_init(Isdnl2_Init);
+module_exit(Isdnl2_cleanup);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer2.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer2.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer2.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,140 @@
+/* $Id: layer2.h,v 1.7 2006/03/06 12:52:07 keil Exp $
+ *
+ * Layer 2 defines
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <linux/mISDNif.h>
+#include <linux/skbuff.h>
+#include "fsm.h"
+#ifdef MISDN_MEMDEBUG
+#include "memdbg.h"
+#endif
+
+#define MAX_WINDOW	8
+
+typedef struct _teimgr {
+	int		ri;
+	struct FsmInst	tei_m;
+	struct FsmTimer	t202;
+	int		T202, N202;
+	int		debug;
+	struct _layer2	*l2;
+} teimgr_t;
+
+typedef struct _laddr {
+	u_char	A;
+	u_char	B;
+} laddr_t;
+
+typedef struct _layer2 {
+	struct list_head	list;
+	int			sapi;
+	int			tei;
+	laddr_t			addr;
+	u_int			maxlen;
+	teimgr_t		*tm;
+	u_long			flag;
+	u_int			vs, va, vr;
+	int			rc;
+	u_int			window;
+	u_int			sow;
+	int			entity;
+	struct FsmInst		l2m;
+	struct FsmTimer		t200, t203;
+	int			T200, N200, T203;
+	int			debug;
+	mISDNinstance_t		inst;
+//	mISDNif_t		*cloneif;
+	int			next_id;
+	u_int			down_id;
+	struct sk_buff		*windowar[MAX_WINDOW];
+	struct sk_buff_head	i_queue;
+	struct sk_buff_head	ui_queue;
+	struct sk_buff_head	down_queue;
+	struct sk_buff_head	tmp_queue;
+} layer2_t;
+
+/* l2 status_info */
+typedef struct _status_info_l2 {
+	int	len;
+	int	typ;
+	int	protocol;
+	int	state;
+	int	sapi;
+	int	tei;
+	laddr_t addr;
+	u_int	maxlen;
+	u_long	flag;
+	u_int	vs;
+	u_int	va;
+	u_int	vr;
+	int	rc;
+	u_int	window;
+	u_int	sow;
+	int	T200;
+	int	N200;
+	int	T203;
+	int	len_i_queue;
+	int	len_ui_queue;
+	int	len_d_queue;
+	int	debug;
+	int	tei_state;
+	int	tei_ri;
+	int	T202;
+	int	N202;
+	int	tei_debug;
+} status_info_l2_t;
+
+/* from mISDN_l2.c */
+extern int tei_l2(layer2_t *l2, struct sk_buff *skb);
+
+/* from tei.c */
+extern int l2_tei(teimgr_t *tm, struct sk_buff *skb);
+extern int create_teimgr(layer2_t *l2);
+extern void release_tei(teimgr_t *tm);
+extern int TEIInit(void);
+extern void TEIFree(void);
+
+#define GROUP_TEI	127
+#define TEI_SAPI	63
+#define CTRL_SAPI	0
+
+#define RR	0x01
+#define RNR	0x05
+#define REJ	0x09
+#define SABME	0x6f
+#define SABM	0x2f
+#define DM	0x0f
+#define UI	0x03
+#define DISC	0x43
+#define UA	0x63
+#define FRMR	0x87
+#define XID	0xaf
+
+#define CMD	0
+#define RSP	1
+
+#define LC_FLUSH_WAIT 1
+
+#define FLG_LAPB	0
+#define FLG_LAPD	1
+#define FLG_ORIG	2
+#define FLG_MOD128	3
+#define FLG_PEND_REL	4
+#define FLG_L3_INIT	5
+#define FLG_T200_RUN	6
+#define FLG_ACK_PEND	7
+#define FLG_REJEXC	8
+#define FLG_OWN_BUSY	9
+#define FLG_PEER_BUSY	10
+#define FLG_DCHAN_BUSY	11
+#define FLG_L1_ACTIV	12
+#define FLG_ESTAB_PEND	13
+#define FLG_PTP		14
+#define FLG_FIXED_TEI	15
+#define FLG_L2BLOCK	16
+#define FLG_L1_BUSY	17
+#define FLG_LAPD_NET	18

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer3.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer3.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer3.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,605 @@
+/* $Id: layer3.c,v 1.20 2006/05/29 16:46:10 crich Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ *		This file is (c) under GNU PUBLIC LICENSE
+ *		For changes and modifications please read
+ *		../../../Documentation/isdn/mISDN.cert
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ */
+#include "layer3.h"
+#include "helper.h"
+#include "dss1.h"
+
+const char *l3_revision = "$Revision: 1.20 $";
+
+static
+struct Fsm l3fsm = {NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_L3_LC_REL,
+	ST_L3_LC_ESTAB_WAIT,
+	ST_L3_LC_REL_DELAY, 
+	ST_L3_LC_REL_WAIT,
+	ST_L3_LC_ESTAB,
+};
+
+#define L3_STATE_COUNT (ST_L3_LC_ESTAB+1)
+
+static char *strL3State[] =
+{
+	"ST_L3_LC_REL",
+	"ST_L3_LC_ESTAB_WAIT",
+	"ST_L3_LC_REL_DELAY",
+	"ST_L3_LC_REL_WAIT",
+	"ST_L3_LC_ESTAB",
+};
+
+enum {
+	EV_ESTABLISH_REQ,
+	EV_ESTABLISH_IND,
+	EV_ESTABLISH_CNF,
+	EV_RELEASE_REQ,
+	EV_RELEASE_CNF,
+	EV_RELEASE_IND,
+	EV_TIMEOUT,
+};
+
+#define L3_EVENT_COUNT (EV_TIMEOUT+1)
+
+static char *strL3Event[] =
+{
+	"EV_ESTABLISH_REQ",
+	"EV_ESTABLISH_IND",
+	"EV_ESTABLISH_CNF",
+	"EV_RELEASE_REQ",
+	"EV_RELEASE_CNF",
+	"EV_RELEASE_IND",
+	"EV_TIMEOUT",
+};
+
+static void
+l3m_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	layer3_t *l3 = fi->userdata;
+	logdata_t log;
+
+	va_start(log.args, fmt);
+	log.fmt = fmt;
+	log.head = l3->inst.name;
+	mISDN_ctrl(&l3->inst, MGR_DEBUGDATA | REQUEST, &log);
+	va_end(log.args);
+}
+
+void
+l3_debug(layer3_t *l3, char *fmt, ...)
+{
+	logdata_t log;
+
+	va_start(log.args, fmt);
+	log.fmt = fmt;
+	log.head = l3->inst.name;
+	mISDN_ctrl(&l3->inst, MGR_DEBUGDATA | REQUEST, &log);
+	va_end(log.args);
+}
+
+static int
+l3_newid(layer3_t *l3)
+{
+	int	id;
+
+	id = l3->next_id++;
+	if (id == 0x7fff)
+		l3->next_id = 1;
+	id |= (l3->entity << 16);
+	return(id);
+}
+
+u_char *
+findie(u_char * p, int size, u_char ie, int wanted_set)
+{
+	int l, codeset, maincodeset;
+	u_char *pend = p + size;
+
+	/* skip protocol discriminator, callref and message type */
+	p++;
+	l = (*p++) & 0xf;
+	p += l;
+	p++;
+	codeset = 0;
+	maincodeset = 0;
+	/* while there are bytes left... */
+	while (p < pend) {
+		if ((*p & 0xf0) == 0x90) {
+			codeset = *p & 0x07;
+			if (!(*p & 0x08))
+				maincodeset = codeset;
+		}
+		if (codeset == wanted_set) {
+			if (*p == ie) {
+				/* improved length check (Werner Cornelius) */
+				if (!(*p & 0x80)) {
+					if ((pend - p) < 2)
+						return(NULL);
+					if (*(p+1) > (pend - (p+2)))
+						return(NULL);
+					p++; /* points to len */
+				}
+				return (p);
+			} else if ((*p > ie) && !(*p & 0x80))
+				return (NULL);
+		}
+		if (!(*p & 0x80)) {
+			p++;
+			l = *p;
+			p += l;
+			codeset = maincodeset;
+		}
+		p++;
+	}
+	return (NULL);
+}
+
+int
+getcallref(u_char * p)
+{
+	int l, cr = 0;
+
+	p++;			/* prot discr */
+	if (*p & 0xfe)		/* wrong callref BRI only 1 octet*/
+		return(-2);
+	l = 0xf & *p++;		/* callref length */
+	if (!l)			/* dummy CallRef */
+		return(-1);
+	cr = *p++;
+	return (cr);
+}
+
+int
+newcallref(layer3_t *l3)
+{
+	int max = 127;
+
+	if (test_bit(FLG_CRLEN2, &l3->Flag))
+		max = 32767;
+
+	if (l3->OrigCallRef >= max)
+		l3->OrigCallRef = 1;
+	else
+		l3->OrigCallRef++;
+	return (l3->OrigCallRef);
+}
+
+void
+newl3state(l3_process_t *pc, int state)
+{
+	if (pc->l3->debug & L3_DEB_STATE)
+		l3m_debug(&pc->l3->l3m, "newstate cr %d %d --> %d", 
+			 pc->callref & 0x7F,
+			 pc->state, state);
+	pc->state = state;
+}
+
+static void
+L3ExpireTimer(L3Timer_t *t)
+{
+	t->pc->l3->p_mgr(t->pc, t->event, NULL);
+}
+
+void
+L3InitTimer(l3_process_t *pc, L3Timer_t *t)
+{
+	t->pc = pc;
+	t->tl.function = (void *) L3ExpireTimer;
+	t->tl.data = (long) t;
+	init_timer(&t->tl);
+}
+
+void
+L3DelTimer(L3Timer_t *t)
+{
+	del_timer(&t->tl);
+}
+
+int
+L3AddTimer(L3Timer_t *t,
+	   int millisec, int event)
+{
+	if (timer_pending(&t->tl)) {
+		printk(KERN_WARNING "L3AddTimer: timer already active!\n");
+		return -1;
+	}
+	init_timer(&t->tl);
+	t->event = event;
+	t->tl.expires = jiffies + (millisec * HZ) / 1000;
+	add_timer(&t->tl);
+	return 0;
+}
+
+void
+StopAllL3Timer(l3_process_t *pc)
+{
+	L3DelTimer(&pc->timer);
+	if (pc->t303skb) {
+		dev_kfree_skb(pc->t303skb);
+		pc->t303skb = NULL;
+	}
+}
+
+/*
+static void
+no_l3_proto(struct PStack *st, int pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+
+	mISDN_putstatus(st->l1.hardware, "L3", "no D protocol");
+	if (skb) {
+		dev_kfree_skb(skb);
+	}
+}
+
+static int
+no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
+{
+	printk(KERN_WARNING "mISDN: no specific protocol handler for proto %lu\n",ic->arg & 0xFF);
+	return(-1);
+}
+*/
+
+l3_process_t
+*getl3proc(layer3_t *l3, int cr)
+{
+	l3_process_t *p;
+	
+	list_for_each_entry(p, &l3->plist, list)
+		if (p->callref == cr)
+			return (p);
+	return (NULL);
+}
+
+l3_process_t
+*getl3proc4id(layer3_t *l3, u_int id)
+{
+	l3_process_t *p;
+
+	list_for_each_entry(p, &l3->plist, list)
+		if (p->id == id)
+			return (p);
+	return (NULL);
+}
+
+l3_process_t
+*new_l3_process(layer3_t *l3, int cr, int n303, u_int id)
+{
+	l3_process_t	*p = NULL;
+
+	if (id == MISDN_ID_ANY) {
+		if (l3->entity == MISDN_ENTITY_NONE) {
+			printk(KERN_WARNING "%s: no entity allocated for l3(%x)\n",
+				__FUNCTION__, l3->id);
+			return (NULL);
+		}
+		if (l3->pid_cnt == 0x7FFF)
+			l3->pid_cnt = 0;
+		while(l3->pid_cnt <= 0x7FFF) {
+			l3->pid_cnt++;
+			id = l3->pid_cnt | (l3->entity << 16);
+			p = getl3proc4id(l3, id);
+			if (!p)
+				break;
+		}
+		if (p) {
+			printk(KERN_WARNING "%s: no free process_id for l3(%x) entity(%x)\n",
+				__FUNCTION__, l3->id, l3->entity);
+			return (NULL);
+		}
+	} else {
+		/* id from other entity */
+		p = getl3proc4id(l3, id);
+		if (p) {
+			printk(KERN_WARNING "%s: process_id(%x) allready in use in l3(%x)\n",
+				__FUNCTION__, id, l3->id);
+			return (NULL);
+		}
+	}
+	if (!(p = kmalloc(sizeof(l3_process_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "mISDN can't get memory for cr %d\n", cr);
+		return (NULL);
+	}
+	memset(p, 0, sizeof(l3_process_t));
+
+	p->cause=NO_CAUSE;
+	
+	p->l3 = l3;
+	p->id = id;
+	p->callref = cr;
+	p->n303 = n303;
+	L3InitTimer(p, &p->timer);
+	L3InitTimer(p, &p->aux_timer);
+	list_add_tail(&p->list, &l3->plist);
+	return (p);
+};
+
+void
+release_l3_process(l3_process_t *p)
+{
+	layer3_t *l3;
+
+	if (!p)
+		return;
+	l3 = p->l3;
+	mISDN_l3up(p, CC_RELEASE_CR | INDICATION, NULL);
+	list_del(&p->list);
+	StopAllL3Timer(p);
+	kfree(p);
+	if (list_empty(&l3->plist) && !test_bit(FLG_PTP, &l3->Flag)) {
+		if (l3->debug)
+			l3_debug(l3, "release_l3_process: last process");
+		if (!skb_queue_len(&l3->squeue)) {
+			if (l3->debug)
+				l3_debug(l3, "release_l3_process: release link");
+			mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
+		} else {
+			if (l3->debug)
+				l3_debug(l3, "release_l3_process: not release link");
+		}
+	}
+};
+
+static void
+l3ml3p(layer3_t *l3, int pr)
+{
+	l3_process_t *p, *np;
+
+	list_for_each_entry_safe(p, np, &l3->plist, list) 
+		l3->p_mgr(p, pr, NULL);
+}
+
+int
+mISDN_l3up(l3_process_t *l3p, u_int prim, struct sk_buff *skb)
+{
+	layer3_t *l3;
+	int err = -EINVAL;
+
+	if (!l3p)
+		return(-EINVAL);
+	l3 = l3p->l3;
+	if (!skb)
+		err = mISDN_queue_data(&l3->inst, FLG_MSG_UP, prim, l3p->id, 0, NULL, 0);
+	else
+		err = mISDN_queueup_newhead(&l3->inst, 0, prim, l3p->id, skb);
+	return(err);
+}
+
+static int
+l3down(layer3_t *l3, u_int prim, int dinfo, struct sk_buff *skb) {
+	int err = -EINVAL;
+
+	if (!skb)
+		err = mISDN_queue_data(&l3->inst, FLG_MSG_DOWN, prim, dinfo, 0, NULL, 0);
+	else
+		err = mISDN_queuedown_newhead(&l3->inst, 0, prim, dinfo, skb);
+	return(err);
+}
+
+#define DREL_TIMER_VALUE 40000
+
+static void
+lc_activate(struct FsmInst *fi, int event, void *arg)
+{
+	layer3_t *l3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
+	l3down(l3, DL_ESTABLISH | REQUEST, 0, NULL);
+}
+
+static void
+lc_connect(struct FsmInst *fi, int event, void *arg)
+{
+	layer3_t *l3 = fi->userdata;
+	struct sk_buff *skb;
+	int dequeued = 0;
+
+	mISDN_FsmChangeState(fi, ST_L3_LC_ESTAB);
+	while ((skb = skb_dequeue(&l3->squeue))) {
+		if (l3down(l3, DL_DATA | REQUEST, l3_newid(l3), skb))
+			dev_kfree_skb(skb);
+		dequeued++;
+	}
+	if (list_empty(&l3->plist) &&  dequeued) {
+		if (l3->debug)
+			l3m_debug(fi, "lc_connect: release link");
+		mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
+	} else
+		l3ml3p(l3, DL_ESTABLISH | INDICATION);
+}
+
+static void
+lc_connected(struct FsmInst *fi, int event, void *arg)
+{
+	layer3_t *l3 = fi->userdata;
+	struct sk_buff *skb;
+	int dequeued = 0;
+
+	mISDN_FsmDelTimer(&l3->l3m_timer, 51);
+	mISDN_FsmChangeState(fi, ST_L3_LC_ESTAB);
+	while ((skb = skb_dequeue(&l3->squeue))) {
+		if (l3down(l3, DL_DATA | REQUEST, l3_newid(l3), skb))
+			dev_kfree_skb(skb);
+		dequeued++;
+	}
+	if (list_empty(&l3->plist) &&  dequeued) {
+		if (l3->debug)
+			l3m_debug(fi, "lc_connected: release link");
+		mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
+	} else
+		l3ml3p(l3, DL_ESTABLISH | CONFIRM);
+}
+
+static void
+lc_start_delay(struct FsmInst *fi, int event, void *arg)
+{
+	layer3_t *l3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L3_LC_REL_DELAY);
+	mISDN_FsmAddTimer(&l3->l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
+}
+
+static void
+lc_release_req(struct FsmInst *fi, int event, void *arg)
+{
+	layer3_t *l3 = fi->userdata;
+
+	if (test_bit(FLG_L2BLOCK, &l3->Flag)) {
+		if (l3->debug)
+			l3m_debug(fi, "lc_release_req: l2 blocked");
+		/* restart release timer */
+		mISDN_FsmAddTimer(&l3->l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
+	} else {
+		mISDN_FsmChangeState(fi, ST_L3_LC_REL_WAIT);
+		l3down(l3, DL_RELEASE | REQUEST, 0, NULL);
+	}
+}
+
+static void
+lc_release_ind(struct FsmInst *fi, int event, void *arg)
+{
+	layer3_t *l3 = fi->userdata;
+
+	mISDN_FsmDelTimer(&l3->l3m_timer, 52);
+	mISDN_FsmChangeState(fi, ST_L3_LC_REL);
+	discard_queue(&l3->squeue);
+	l3ml3p(l3, DL_RELEASE | INDICATION);
+}
+
+static void
+lc_release_cnf(struct FsmInst *fi, int event, void *arg)
+{
+	layer3_t *l3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_L3_LC_REL);
+	discard_queue(&l3->squeue);
+	l3ml3p(l3, DL_RELEASE | CONFIRM);
+}
+
+
+/* *INDENT-OFF* */
+static struct FsmNode L3FnList[] =
+{
+	{ST_L3_LC_REL,		EV_ESTABLISH_REQ,	lc_activate},
+	{ST_L3_LC_REL,		EV_ESTABLISH_IND,	lc_connect},
+	{ST_L3_LC_REL,		EV_ESTABLISH_CNF,	lc_connect},
+	{ST_L3_LC_ESTAB_WAIT,	EV_ESTABLISH_CNF,	lc_connected},
+	{ST_L3_LC_ESTAB_WAIT,	EV_RELEASE_REQ,		lc_start_delay},
+	{ST_L3_LC_ESTAB_WAIT,	EV_RELEASE_IND,		lc_release_ind},
+	{ST_L3_LC_ESTAB,	EV_RELEASE_IND,		lc_release_ind},
+	{ST_L3_LC_ESTAB,	EV_RELEASE_REQ,		lc_start_delay},
+        {ST_L3_LC_REL_DELAY,    EV_RELEASE_IND,         lc_release_ind},
+        {ST_L3_LC_REL_DELAY,    EV_ESTABLISH_REQ,       lc_connected},
+        {ST_L3_LC_REL_DELAY,    EV_TIMEOUT,             lc_release_req},
+	{ST_L3_LC_REL_WAIT,	EV_RELEASE_CNF,		lc_release_cnf},
+	{ST_L3_LC_REL_WAIT,	EV_ESTABLISH_REQ,	lc_activate},
+};
+/* *INDENT-ON* */
+
+#define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode))
+
+int
+l3_msg(layer3_t *l3, u_int pr, int dinfo, int len, void *arg)
+{
+	switch (pr) {
+		case (DL_DATA | REQUEST):
+			if (l3->l3m.state == ST_L3_LC_ESTAB) {
+				return(l3down(l3, pr, l3_newid(l3), arg));
+			} else {
+				struct sk_buff *skb = arg;
+
+//				printk(KERN_DEBUG "%s: queue skb %p len(%d)\n",
+//					__FUNCTION__, skb, skb->len);
+				skb_queue_tail(&l3->squeue, skb);
+				mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_REQ, NULL); 
+			}
+			break;
+		case (DL_ESTABLISH | REQUEST):
+			mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_REQ, NULL);
+			break;
+		case (DL_ESTABLISH | CONFIRM):
+			mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_CNF, NULL);
+			break;
+		case (DL_ESTABLISH | INDICATION):
+			mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_IND, NULL);
+			break;
+		case (DL_RELEASE | INDICATION):
+			mISDN_FsmEvent(&l3->l3m, EV_RELEASE_IND, NULL);
+			break;
+		case (DL_RELEASE | CONFIRM):
+			mISDN_FsmEvent(&l3->l3m, EV_RELEASE_CNF, NULL);
+			break;
+		case (DL_RELEASE | REQUEST):
+			mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
+			break;
+	}
+	return(0);
+}
+
+void
+init_l3(layer3_t *l3)
+{
+	INIT_LIST_HEAD(&l3->plist);
+	l3->global = NULL;
+	l3->dummy = NULL;
+	l3->entity = MISDN_ENTITY_NONE;
+	l3->next_id = 1;
+	skb_queue_head_init(&l3->squeue);
+	l3->l3m.fsm = &l3fsm;
+	l3->l3m.state = ST_L3_LC_REL;
+	l3->l3m.debug = l3->debug;
+	l3->l3m.userdata = l3;
+	l3->l3m.userint = 0;
+	l3->l3m.printdebug = l3m_debug;
+        mISDN_FsmInitTimer(&l3->l3m, &l3->l3m_timer);
+}
+
+
+void
+release_l3(layer3_t *l3)
+{
+	l3_process_t *p, *np;
+
+	if (l3->l3m.debug)
+		printk(KERN_DEBUG "release_l3(%p) plist(%s) global(%p) dummy(%p)\n",
+			l3, list_empty(&l3->plist) ? "no" : "yes", l3->global, l3->dummy);
+	list_for_each_entry_safe(p, np, &l3->plist, list)
+		release_l3_process(p);
+	if (l3->global) {
+		StopAllL3Timer(l3->global);
+		kfree(l3->global);
+		l3->global = NULL;
+	}
+	if (l3->dummy) {
+		StopAllL3Timer(l3->dummy);
+		kfree(l3->dummy);
+		l3->dummy = NULL;
+	}
+	mISDN_FsmDelTimer(&l3->l3m_timer, 54);
+	discard_queue(&l3->squeue);
+}
+
+void
+mISDNl3New(void)
+{
+	l3fsm.state_count = L3_STATE_COUNT;
+	l3fsm.event_count = L3_EVENT_COUNT;
+	l3fsm.strEvent = strL3Event;
+	l3fsm.strState = strL3State;
+	mISDN_FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
+}
+
+void
+mISDNl3Free(void)
+{
+	mISDN_FsmFree(&l3fsm);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer3.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer3.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/layer3.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,99 @@
+/* $Id: layer3.h,v 1.13 2006/06/01 11:02:10 crich Exp $
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#include <linux/mISDNif.h>
+#include <linux/skbuff.h>
+#include "fsm.h"
+#ifdef MISDN_MEMDEBUG
+#include "memdbg.h"
+#endif
+
+#define SBIT(state) (1<<state)
+#define ALL_STATES  0x03ffffff
+
+#define PROTO_DIS_EURO	0x08
+
+#define L3_DEB_WARN	0x01
+#define L3_DEB_PROTERR	0x02
+#define L3_DEB_STATE	0x04
+#define L3_DEB_CHARGE	0x08
+#define L3_DEB_CHECK	0x10
+#define L3_DEB_SI	0x20
+#define L3_DEB_MSG	0x80000000
+
+#define FLG_L2BLOCK	1
+#define FLG_PTP		2
+#define FLG_EXTCID	3
+#define FLG_CRLEN2	4
+
+typedef struct _L3Timer {
+	struct _l3_process	*pc;
+	struct timer_list	tl;
+	int			event;
+} L3Timer_t;
+
+typedef struct _l3_process {
+	struct list_head	list;
+	struct _layer3		*l3;
+	int			callref;
+	int			state;
+	L3Timer_t		timer;
+	int			n303;
+	int cause;
+	struct sk_buff		*t303skb;
+	u_int			id;
+	int			bc;
+	int			real_bc;
+	int			err;
+	int			aux_state;
+	L3Timer_t		aux_timer;
+} l3_process_t;
+
+typedef struct _layer3 {
+	struct list_head	list;
+	struct FsmInst		l3m;
+	struct FsmTimer		l3m_timer;
+	int			entity;
+	int			pid_cnt;
+	int			next_id;
+	struct list_head	plist;
+	l3_process_t		*global;
+	l3_process_t		*dummy;
+	int			(*p_mgr)(l3_process_t *, u_int, void *);
+	int			down_headerlen;
+	u_int			id;
+	int			debug;
+	u_long			Flag;
+	mISDNinstance_t		inst;
+	struct sk_buff_head	squeue;
+	int			OrigCallRef;
+} layer3_t;
+
+struct stateentry {
+	int	state;
+	u_int	primitive;
+	void	(*rout) (l3_process_t *, u_char, void *);
+};
+
+extern int		l3_msg(layer3_t *, u_int, int, int, void *);
+extern void		newl3state(l3_process_t *, int);
+extern void		L3InitTimer(l3_process_t *, L3Timer_t *);
+extern void		L3DelTimer(L3Timer_t *);
+extern int		L3AddTimer(L3Timer_t *, int, int);
+extern void		StopAllL3Timer(l3_process_t *);
+extern void		release_l3_process(l3_process_t *);
+extern l3_process_t	*getl3proc(layer3_t *, int);
+extern l3_process_t	*getl3proc4id(layer3_t *, u_int);
+extern l3_process_t	*new_l3_process(layer3_t *, int, int, u_int);
+extern u_char		*findie(u_char *, int, u_char, int);
+extern int		mISDN_l3up(l3_process_t *, u_int, struct sk_buff *);
+extern int		getcallref(u_char * p);
+extern int		newcallref(layer3_t *);
+extern void		init_l3(layer3_t *);
+extern void		release_l3(layer3_t *);
+extern void		mISDNl3New(void);
+extern void		mISDNl3Free(void);
+extern void		l3_debug(layer3_t *, char *, ...);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/listen.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/listen.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/listen.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,207 @@
+/* $Id: listen.c,v 1.8 2004/01/26 22:21:30 keil Exp $
+ *
+ */
+
+#include "m_capi.h"
+#include "helper.h"
+#include "debug.h"
+
+#define listenDebug(listen, lev, fmt, args...) \
+        capidebug(lev, fmt, ## args)
+
+// --------------------------------------------------------------------
+// LISTEN state machine
+
+enum {
+	ST_LISTEN_L_0,
+	ST_LISTEN_L_0_1,
+	ST_LISTEN_L_1,
+	ST_LISTEN_L_1_1,
+}
+
+const ST_LISTEN_COUNT = ST_LISTEN_L_1_1 + 1;
+
+static char *str_st_listen[] = {
+	"ST_LISTEN_L_0",
+	"ST_LISTEN_L_0_1",
+	"ST_LISTEN_L_1",
+	"ST_LISTEN_L_1_1",
+};
+
+enum {
+	EV_LISTEN_REQ,
+	EV_LISTEN_CONF,
+}
+
+const EV_LISTEN_COUNT = EV_LISTEN_CONF + 1;
+
+static char* str_ev_listen[] = {
+	"EV_LISTEN_REQ",
+	"EV_LISTEN_CONF",
+};
+
+static struct Fsm listen_fsm =
+{ 0, 0, 0, 0, 0 };
+
+static void
+listen_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	char tmp[128];
+	char *p = tmp;
+	va_list args;
+	Application_t *app = fi->userdata;
+	
+	if (!fi->debug)
+		return;
+	va_start(args, fmt);
+	p += sprintf(p, "Controller 0x%x ApplId %d listen ",
+		     app->contr->addr, app->ApplId);
+	p += vsprintf(p, fmt, args);
+	*p = 0;
+	listenDebug(app, CAPI_DBG_LISTEN_STATE, tmp);
+	va_end(args);
+}
+
+static void
+listen_req_l_x(struct FsmInst *fi, int event, void *arg, int state)
+{
+	Application_t	*app = fi->userdata;
+	_cmsg		*cmsg = arg;
+
+	mISDN_FsmChangeState(fi, state);
+
+	app->InfoMask = cmsg->InfoMask;
+	app->CIPmask = cmsg->CIPmask;
+	app->CIPmask2 = cmsg->CIPmask2;
+	listenDebug(app, CAPI_DBG_LISTEN_INFO, "set InfoMask to 0x%x", app->InfoMask);
+	listenDebug(app, CAPI_DBG_LISTEN_INFO, "set CIP to 0x%x,0x%x", app->CIPmask,
+		app->CIPmask2);
+
+	capi_cmsg_answer(cmsg);
+	cmsg->Info = CAPI_NOERROR;
+
+	if (mISDN_FsmEvent(&app->listen_m, EV_LISTEN_CONF, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+listen_req_l_0(struct FsmInst *fi, int event, void *arg)
+{
+	listen_req_l_x(fi, event, arg, ST_LISTEN_L_0_1);
+}
+
+static void
+listen_req_l_1(struct FsmInst *fi, int event, void *arg)
+{
+	listen_req_l_x(fi, event, arg, ST_LISTEN_L_1_1);
+}
+
+static void
+listen_conf_l_x_1(struct FsmInst *fi, int event, void *arg, int state)
+{
+	Application_t	*app = fi->userdata;
+	_cmsg		*cmsg = arg;
+
+	if (cmsg->Info != CAPI_NOERROR) {
+		mISDN_FsmChangeState(fi, state);
+	} else { // Info == 0
+		if (app->CIPmask == 0) {
+			test_and_clear_bit(APPL_STATE_LISTEN, &app->state);
+			mISDN_FsmChangeState(fi, ST_LISTEN_L_0);
+		} else {
+			test_and_set_bit(APPL_STATE_LISTEN, &app->state);
+			mISDN_FsmChangeState(fi, ST_LISTEN_L_1);
+		}
+	}
+	SendCmsg2Application(app, cmsg);
+}
+
+static void
+listen_conf_l_0_1(struct FsmInst *fi, int event, void *arg)
+{
+	listen_conf_l_x_1(fi, event, arg, ST_LISTEN_L_0);
+}
+
+static void
+listen_conf_l_1_1(struct FsmInst *fi, int event, void *arg)
+{
+	listen_conf_l_x_1(fi, event, arg, ST_LISTEN_L_1);
+}
+
+static struct FsmNode fn_listen_list[] =
+{
+	{ST_LISTEN_L_0,		EV_LISTEN_REQ,	listen_req_l_0},
+	{ST_LISTEN_L_0_1,	EV_LISTEN_CONF,	listen_conf_l_0_1},
+	{ST_LISTEN_L_1,		EV_LISTEN_REQ,	listen_req_l_1},
+	{ST_LISTEN_L_1_1,	EV_LISTEN_CONF,	listen_conf_l_1_1},
+};
+
+const int FN_LISTEN_COUNT = sizeof(fn_listen_list)/sizeof(struct FsmNode);
+
+// ----------------------------------------------------------------------
+// Methods
+
+void listenConstr(Application_t *app)
+{
+	app->listen_m.fsm = &listen_fsm;
+	app->listen_m.state = ST_LISTEN_L_0;
+	app->listen_m.debug = app->contr->debug & CAPI_DBG_LISTEN_STATE;
+	app->listen_m.userdata = app;
+	app->listen_m.printdebug = listen_debug;
+	app->InfoMask = 0;
+	app->CIPmask = 0;
+	app->CIPmask2 = 0;
+}
+
+void listenDestr(Application_t *app)
+{
+	test_and_clear_bit(APPL_STATE_LISTEN, &app->state);
+	listenDebug(app, CAPI_DBG_LISTEN, "%s", __FUNCTION__);
+}
+
+__u16
+listenSendMessage(Application_t *app, struct sk_buff *skb)
+{
+	_cmsg	*cmsg;
+
+	cmsg = cmsg_alloc();
+	if (!cmsg) {
+		int_error();
+		return (CAPI_MSGOSRESOURCEERR);
+	}
+	capi_message2cmsg(cmsg, skb->data);
+	switch (CMSGCMD(cmsg)) {
+		case CAPI_LISTEN_REQ:
+			if (mISDN_FsmEvent(&app->listen_m, EV_LISTEN_REQ, cmsg))
+				cmsg_free(cmsg);
+			break;
+		default:
+			int_error();
+			cmsg_free(cmsg);
+	}
+	dev_kfree_skb(skb);
+	return(CAPI_NOERROR);
+}
+ 
+int listenHandle(Application_t *app, __u16 CIPValue)
+{
+	if ((app->CIPmask & 1) || 
+	    (app->CIPmask & (1 << CIPValue)))
+		return 1;
+	return 0;
+}
+
+void init_listen(void)
+{
+	listen_fsm.state_count = ST_LISTEN_COUNT;
+	listen_fsm.event_count = EV_LISTEN_COUNT;
+	listen_fsm.strEvent = str_ev_listen;
+	listen_fsm.strState = str_st_listen;
+	
+	mISDN_FsmNew(&listen_fsm, fn_listen_list, FN_LISTEN_COUNT);
+}
+
+void free_listen(void)
+{
+	mISDN_FsmFree(&listen_fsm);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/loop.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/loop.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/loop.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,597 @@
+/*
+ * loop.c  loop driver for looped bchannel pairs
+ *
+ * Author	Andreas Eversberg (jolly at eversberg.eu)
+ *
+ * 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.
+ *
+ */
+
+/* module parameters:
+ * interfaces:
+	Number of loop interfaces. Default is 1.
+
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include "channel.h"
+#include "layer1.h"
+#include "debug.h"
+#include <linux/isdn_compat.h>
+
+#include "loop.h"
+
+static const char *loop_revision = "$Revision: 1.8 $";
+
+static int loop_cnt;
+
+static mISDNobject_t	loop_obj;
+
+static char LoopName[] = "loop";
+
+
+/****************/
+/* module stuff */
+/****************/
+
+static int interfaces;
+static int debug;
+
+#ifdef MODULE
+MODULE_AUTHOR("Andreas Eversberg");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+module_param(interfaces, uint, S_IRUGO | S_IWUSR);
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+#endif
+
+
+/****************************/
+/* Layer 1 D-channel access */
+/****************************/
+
+/* message transfer from layer 1.
+ */
+static int loop_l1hw(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*dch = container_of(inst, channel_t, inst);
+	loop_t		*hc;
+	int		ret = 0;
+	mISDN_head_t	*hh;
+
+	hh = mISDN_HEAD_P(skb);
+	hc = dch->inst.privat;
+	
+	if (debug & DEBUG_LOOP_MSG)
+		printk(KERN_DEBUG "%s: unsupported prim %x\n", __FUNCTION__, hh->prim);
+	ret = -EINVAL;
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+
+/* messages from layer 2 to layer 1 are processed here.
+ */
+static int
+loop_l2l1(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	int		ch;
+	channel_t	*bch = container_of(inst, channel_t, inst);
+	int		ret = -EINVAL;
+	mISDN_head_t	*hh;
+	loop_t	*hc;
+	struct sk_buff	*nskb;
+
+	hh = mISDN_HEAD_P(skb);
+	hc = bch->inst.privat;
+	ch = bch->channel;
+
+	if ((hh->prim == PH_DATA_REQ)
+	 || (hh->prim == (DL_DATA | REQUEST))) {
+		if (skb->len <= 0) {
+			printk(KERN_WARNING "%s: skb too small\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+		if (skb->len > MAX_DATA_MEM) {
+			printk(KERN_WARNING "%s: skb too large\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+		if ((nskb = skb_clone(skb, GFP_ATOMIC)))
+			queue_ch_frame(hc->bch[ch^1], INDICATION, MISDN_ID_ANY, nskb);
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, hh->dinfo, skb));
+	} else if ((hh->prim == (PH_ACTIVATE | REQUEST))
+	 || (hh->prim == (DL_ESTABLISH  | REQUEST))) {
+		/* activate B-channel if not already activated */
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
+	} else if ((hh->prim == (PH_DEACTIVATE | REQUEST))
+	 || (hh->prim == (DL_RELEASE | REQUEST))
+	 || ((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
+	} else
+	if (hh->prim == (PH_CONTROL | REQUEST)) {
+		switch (hh->dinfo) {
+			default:
+			printk(KERN_DEBUG "%s: unknown PH_CONTROL info %x\n", __FUNCTION__, hh->dinfo);
+			ret = -EINVAL;
+		}
+	} else {
+		printk(KERN_WARNING "%s: unknown prim(%x)\n", __FUNCTION__, hh->prim);
+		ret = -EINVAL;
+	}
+	if (!ret) {
+		dev_kfree_skb(skb);
+	}
+	return(ret);
+}
+
+
+
+/**************************
+ * remove card from stack *
+ **************************/
+
+static void
+loop_delete(loop_t *hc)
+{
+	int	ch;
+	u_long	flags;
+
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: entered\n", __FUNCTION__);
+
+	/* free channels */
+	if (hc->dch) {
+		if (debug & DEBUG_LOOP_INIT)
+			printk(KERN_DEBUG "%s: free D-channel\n", __FUNCTION__);
+		mISDN_freechannel(hc->dch);
+		kfree(hc->dch);
+		hc->dch = NULL;
+	}
+	ch = 0;
+	while(ch < LOOP_CHANNELS) {
+		if (hc->bch[ch]) {
+			if (debug & DEBUG_LOOP_INIT)
+				printk(KERN_DEBUG "%s: free B-channel %d\n", __FUNCTION__, ch);
+			mISDN_freechannel(hc->bch[ch]);
+			kfree(hc->bch[ch]);
+			hc->bch[ch] = NULL;
+		}
+		ch++;
+	}
+	
+	/* remove us from list and delete */
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_WARNING "%s: remove instance from list\n", __FUNCTION__);
+	spin_lock_irqsave(&loop_obj.lock, flags);
+	list_del(&hc->list);
+	spin_unlock_irqrestore(&loop_obj.lock, flags);
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_WARNING "%s: delete instance\n", __FUNCTION__);
+	kfree(hc);
+	loop_cnt--;
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_WARNING "%s: card successfully removed\n", __FUNCTION__);
+}
+
+static int
+loop_manager(void *data, u_int prim, void *arg)
+{
+	loop_t	*hc;
+	mISDNinstance_t	*inst = data;
+	struct sk_buff	*skb;
+	channel_t	*dch = NULL;
+	channel_t	*bch = NULL;
+	int		ch = 0;
+	u_long		flags;
+
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim,arg,&loop_obj)
+		printk(KERN_ERR "%s: no data prim %x arg %p\n", __FUNCTION__, prim, arg);
+		return(-EINVAL);
+	}
+
+	/* find channel and card */
+	spin_lock_irqsave(&loop_obj.lock, flags);
+	list_for_each_entry(hc, &loop_obj.ilist, list) {
+		if (hc->dch) if (&hc->dch->inst == inst) {
+			dch = hc->dch;
+			spin_unlock_irqrestore(&loop_obj.lock, flags);
+			if (debug & DEBUG_LOOP_MGR)
+				printk(KERN_DEBUG "%s: D-channel  data %p prim %x arg %p\n", __FUNCTION__, data, prim, arg);
+			goto found;
+		}
+
+		ch = 0;
+		while(ch < LOOP_CHANNELS) {
+			if (hc->bch[ch]) if (&hc->bch[ch]->inst == inst) {
+				bch = hc->bch[ch];
+				spin_unlock_irqrestore(&loop_obj.lock, flags);
+				if (debug & DEBUG_LOOP_MGR)
+					printk(KERN_DEBUG "%s: B-channel %d (0..%d)  data %p prim %x arg %p\n", __FUNCTION__, ch, LOOP_CHANNELS-1, data, prim, arg);
+				goto found;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&loop_obj.lock, flags);
+	printk(KERN_ERR "%s: no card/channel found  data %p prim %x arg %p\n", __FUNCTION__, data, prim, arg);
+	return(-EINVAL);
+
+found:
+	switch(prim) {
+		case MGR_REGLAYER | CONFIRM:
+		if (debug & DEBUG_LOOP_MGR)
+			printk(KERN_DEBUG "%s: MGR_REGLAYER\n", __FUNCTION__);
+		mISDN_setpara(dch, &inst->st->para);
+		break;
+
+		case MGR_UNREGLAYER | REQUEST:
+		if (debug & DEBUG_LOOP_MGR)
+			printk(KERN_DEBUG "%s: MGR_UNREGLAYER\n", __FUNCTION__);
+		if (dch) {
+			if ((skb = create_link_skb(PH_CONTROL | REQUEST, HW_DEACTIVATE, 0, NULL, 0))) {
+				if (loop_l1hw(inst, skb)) dev_kfree_skb(skb);
+			}
+		} else
+		if (bch) {
+			if ((skb = create_link_skb(PH_CONTROL | REQUEST, 0, 0, NULL, 0))) {
+				if (loop_l2l1(inst, skb)) dev_kfree_skb(skb);
+			}
+		}
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+		break;
+
+		case MGR_CLRSTPARA | INDICATION:
+		arg = NULL;
+		// fall through
+		case MGR_ADDSTPARA | INDICATION:
+		if (debug & DEBUG_LOOP_MGR)
+			printk(KERN_DEBUG "%s: MGR_***STPARA\n", __FUNCTION__);
+		mISDN_setpara(dch, arg);
+		break;
+
+		case MGR_RELEASE | INDICATION:
+		if (debug & DEBUG_LOOP_MGR)
+			printk(KERN_DEBUG "%s: MGR_RELEASE = remove port from mISDN\n", __FUNCTION__);
+		if (dch) {
+			loop_delete(hc); /* hc is free */
+		}
+		break;
+#ifdef FIXME
+		case MGR_CONNECT | REQUEST:
+		if (debug & DEBUG_LOOP_MGR)
+			printk(KERN_DEBUG "%s: MGR_CONNECT\n", __FUNCTION__);
+		return(mISDN_ConnectIF(inst, arg));
+
+		case MGR_SETIF | REQUEST:
+		case MGR_SETIF | INDICATION:
+		if (debug & DEBUG_LOOP_MGR)
+			printk(KERN_DEBUG "%s: MGR_SETIF\n", __FUNCTION__);
+		if (dch)
+			return(mISDN_SetIF(inst, arg, prim, loop_l1hw, NULL, dch));
+		if (bch)
+			return(mISDN_SetIF(inst, arg, prim, loop_l2l1, NULL, bch));
+		break;
+
+		case MGR_DISCONNECT | REQUEST:
+		case MGR_DISCONNECT | INDICATION:
+		if (debug & DEBUG_LOOP_MGR)
+			printk(KERN_DEBUG "%s: MGR_DISCONNECT\n", __FUNCTION__);
+		return(mISDN_DisConnectIF(inst, arg));
+#endif
+#if 0
+		case MGR_SELCHANNEL | REQUEST:
+		if (debug & DEBUG_LOOP_MGR)
+			printk(KERN_DEBUG "%s: MGR_SELCHANNEL\n", __FUNCTION__);
+		if (!dch) {
+			printk(KERN_WARNING "%s(MGR_SELCHANNEL|REQUEST): selchannel not dinst\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+		return(SelFreeBChannel(hc, ch, arg));
+#endif
+		
+		case MGR_SETSTACK | INDICATION:
+		if (debug & DEBUG_LOOP_MGR)
+			printk(KERN_DEBUG "%s: MGR_SETSTACK\n", __FUNCTION__);
+		if (bch && inst->pid.global==2) {
+			if ((skb = create_link_skb(PH_ACTIVATE | REQUEST, 0, 0, NULL, 0))) {
+				if (loop_l2l1(inst, skb)) dev_kfree_skb(skb);
+			}
+			if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+			mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION, 0, 0, NULL, 0);
+		else mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION, 0, 0, NULL, 0);
+		}
+		break;
+
+		PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+		PRIM_NOT_HANDLED(MGR_GLOBALOPT | REQUEST);
+		default:
+		printk(KERN_WARNING "%s: prim %x not handled\n", __FUNCTION__, prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+/*************************
+ * create cards instance *
+ *************************/
+
+static int __devinit loop_new(void)
+{
+	int		ret_err=0;
+	int		ch;
+	loop_t	*hc;
+	mISDN_pid_t	pid;
+	mISDNstack_t	*dst = NULL; /* make gcc happy */
+	channel_t	*dch;
+	channel_t	*bch;
+	u_long		flags;
+
+	if (debug & DEBUG_LOOP_INIT)
+	printk(KERN_DEBUG "%s: Registering loop driver #%d\n", __FUNCTION__, loop_cnt+1);
+
+	/* allocate structure */
+	if (!(hc = kmalloc(sizeof(loop_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "No kmem for loop driver\n");
+		ret_err = -ENOMEM;
+		goto free_object;
+	}
+	memset(hc, 0, sizeof(loop_t));
+	hc->idx = loop_cnt;
+	hc->id = loop_cnt + 1;
+
+	sprintf(hc->name, "LOOP#%d", loop_cnt+1);
+
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__);
+	
+	spin_lock_irqsave(&loop_obj.lock, flags);
+	list_add_tail(&hc->list, &loop_obj.ilist);
+	spin_unlock_irqrestore(&loop_obj.lock, flags);
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__);
+
+	spin_lock_init(&hc->lock);
+
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: Registering D-channel, card(%d)\n", __FUNCTION__, loop_cnt+1);
+	dch = kmalloc(sizeof(channel_t), GFP_ATOMIC);
+	if (!dch) {
+		ret_err = -ENOMEM;
+		goto free_channels;
+	}
+	memset(dch, 0, sizeof(channel_t));
+	dch->channel = 0;
+	//dch->debug = debug;
+	dch->inst.obj = &loop_obj;
+	dch->inst.hwlock = &hc->lock;
+	mISDN_init_instance(&dch->inst, &loop_obj, hc, loop_l1hw);
+	dch->inst.pid.layermask = ISDN_LAYER(0);
+	sprintf(dch->inst.name, "LOOP%d", loop_cnt+1);
+	if (mISDN_initchannel(dch, MSK_INIT_DCHANNEL, MAX_DATA_MEM)) {
+		ret_err = -ENOMEM;
+		goto free_channels;
+	}
+	hc->dch = dch;
+
+	ch=0;
+	while(ch < LOOP_CHANNELS) {
+		if (debug & DEBUG_LOOP_INIT)
+			printk(KERN_DEBUG "%s: Registering B-channel, card(%d) ch(%d)\n", __FUNCTION__, loop_cnt+1, ch);
+		bch = kmalloc(sizeof(channel_t), GFP_ATOMIC);
+		if (!bch) {
+			ret_err = -ENOMEM;
+			goto free_channels;
+		}
+		memset(bch, 0, sizeof(channel_t));
+		bch->channel = ch;
+		mISDN_init_instance(&bch->inst, &loop_obj, hc, loop_l2l1);
+		bch->inst.pid.layermask = ISDN_LAYER(0);
+		bch->inst.hwlock = &hc->lock;
+		//bch->debug = debug;
+		sprintf(bch->inst.name, "%s B%d",
+			dch->inst.name, ch+1);
+		if (mISDN_initchannel(bch, MSK_INIT_BCHANNEL, MAX_DATA_MEM)) {
+			kfree(bch);
+			ret_err = -ENOMEM;
+			goto free_channels;
+		}
+		hc->bch[ch] = bch;
+#ifdef FIXME  // TODO
+		if (bch->dev) {
+			bch->dev->wport.pif.func = loop_l2l1;
+			bch->dev->wport.pif.fdata = bch;
+		}
+#endif
+		ch++;
+	}
+
+	/* set D-channel */
+	mISDN_set_dchannel_pid(&pid, 0x00, ISDN_LAYER(0));
+	pid.protocol[0] = ISDN_PID_L0_LOOP;
+	pid.layermask = ISDN_LAYER(0);
+
+	/* add stacks */
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: Adding d-stack: card(%d)\n", __FUNCTION__, loop_cnt+1);
+	if ((ret_err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &dch->inst))) {
+		printk(KERN_ERR  "MGR_ADDSTACK REQUEST dch err(%d)\n", ret_err);
+		free_release:
+		loop_delete(hc); /* hc is free */
+		goto free_object;
+	}
+
+	dst = dch->inst.st;
+
+	ch = 0;
+	while(ch < LOOP_CHANNELS) {
+		if (debug & DEBUG_LOOP_INIT)
+			printk(KERN_DEBUG "%s: Adding b-stack: card(%d) B-channel(%d)\n", __FUNCTION__, loop_cnt+1, ch+1);
+		bch = hc->bch[ch];
+		if ((ret_err = mISDN_ctrl(dst, MGR_NEWSTACK | REQUEST, &bch->inst))) {
+			printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", ret_err);
+			free_delstack:
+			mISDN_ctrl(dst, MGR_DELSTACK | REQUEST, NULL);
+			goto free_release;
+		}
+		ch++;
+	}
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: (before MGR_SETSTACK REQUEST) layermask=0x%x\n", __FUNCTION__, pid.layermask);
+
+	if ((ret_err = mISDN_ctrl(dst, MGR_SETSTACK | REQUEST, &pid))) {
+		printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", ret_err);
+		goto free_delstack;
+	}
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: (after MGR_SETSTACK REQUEST)\n", __FUNCTION__);
+
+	/* delay some time */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((100*HZ)/1000); /* Timeout 100ms */
+
+	/* tell stack, that we are ready */
+	mISDN_ctrl(dst, MGR_CTRLREADY | INDICATION, NULL);
+
+	loop_cnt++;
+	return(0);
+
+	/* if an error ocurred */
+	free_channels:
+	if (hc->dch) {
+		if (debug & DEBUG_LOOP_INIT)
+			printk(KERN_DEBUG "%s: free D-channel\n", __FUNCTION__);
+		mISDN_freechannel(hc->dch);
+		kfree(hc->dch);
+		hc->dch = NULL;
+	}
+	ch = 0;
+	while(ch < LOOP_CHANNELS) {
+		if (hc->bch[ch]) {
+			if (debug & DEBUG_LOOP_INIT)
+				printk(KERN_DEBUG "%s: free B-channel %d\n", __FUNCTION__, ch);
+			mISDN_freechannel(hc->bch[ch]);
+			kfree(hc->bch[ch]);
+			hc->bch[ch] = NULL;
+		}
+		ch++;
+	}
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: before REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, loop_obj.refcnt);
+	spin_lock_irqsave(&loop_obj.lock, flags);
+	list_del(&hc->list);
+	spin_unlock_irqrestore(&loop_obj.lock, flags);
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: after REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, loop_obj.refcnt);
+	kfree(hc);
+
+	free_object:
+	return(ret_err);
+}
+
+
+static void __exit
+loop_cleanup(void)
+{
+	loop_t *hc,*next;
+	int err;
+
+	/* unregister mISDN object */
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: entered (refcnt = %d loop_cnt = %d)\n", __FUNCTION__, loop_obj.refcnt, loop_cnt);
+	if ((err = mISDN_unregister(&loop_obj))) {
+		printk(KERN_ERR "Can't unregister Loop cards error(%d)\n", err);
+	}
+
+	/* remove remaining devices, but this should never happen */
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: now checking ilist (refcnt = %d)\n", __FUNCTION__, loop_obj.refcnt);
+
+	list_for_each_entry_safe(hc, next, &loop_obj.ilist, list) {
+		printk(KERN_ERR "Loop card struct not empty refs %d\n", loop_obj.refcnt);
+		loop_delete(hc);
+	}
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: done (refcnt = %d loop_cnt = %d)\n", __FUNCTION__, loop_obj.refcnt, loop_cnt);
+
+}
+
+static int __init
+loop_init(void)
+{
+	int err;
+	char tmpstr[64];
+
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: init entered\n", __FUNCTION__);
+
+	strcpy(tmpstr, loop_revision);
+	printk(KERN_INFO "mISDN: loop-driver Rev. %s\n", mISDN_getrev(tmpstr));
+
+	memset(&loop_obj, 0, sizeof(loop_obj));
+#ifdef MODULE
+	loop_obj.owner = THIS_MODULE;
+#endif
+	spin_lock_init(&loop_obj.lock);
+	INIT_LIST_HEAD(&loop_obj.ilist);
+	loop_obj.name = LoopName;
+	loop_obj.own_ctrl = loop_manager;
+	loop_obj.DPROTO.protocol[0] = ISDN_PID_L0_LOOP;
+	loop_obj.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS | ISDN_PID_L1_B_64HDLC;
+	loop_obj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS | ISDN_PID_L2_B_RAWDEV;
+
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: registering loop_obj\n", __FUNCTION__);
+	if ((err = mISDN_register(&loop_obj))) {
+		printk(KERN_ERR "Can't register Loop cards error(%d)\n", err);
+		return(err);
+	}
+	if (debug & DEBUG_LOOP_INIT)
+		printk(KERN_DEBUG "%s: new mISDN object (refcnt = %d)\n", __FUNCTION__, loop_obj.refcnt);
+
+	if (interfaces < 1)
+		interfaces = 1;
+	loop_cnt = 0;
+	while(loop_cnt < interfaces)
+	{
+		if ((err = loop_new()))
+			break;
+	}
+
+	if (err)
+	{
+		printk(KERN_ERR "error registering pci driver:%x\n",err);
+		loop_cleanup();
+		return(err);
+	}
+	printk(KERN_INFO "%d devices registered\n", loop_cnt);
+
+	return(0);
+}
+
+
+#ifdef MODULE
+module_init(loop_init);
+module_exit(loop_cleanup);
+#endif
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/loop.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/loop.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/loop.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,28 @@
+/*
+
+ * see notice in loop.c
+ */
+
+#define DEBUG_LOOP_MSG	0x0001
+#define DEBUG_LOOP_INIT 0x0004
+#define DEBUG_LOOP_MGR	0x0008
+
+#define MAX_FRAME_SIZE	2048
+
+#define LOOP_CHANNELS 128
+
+struct misdn_loop {
+	struct list_head	list;
+	char		name[32];
+	int		idx;	/* chip index for module parameters */
+	int		id;	/* chip number starting with 1 */
+
+	spinlock_t	lock;	/* the lock */
+
+	channel_t	*dch;
+	channel_t	*bch[LOOP_CHANNELS];
+};
+
+typedef struct misdn_loop	loop_t;
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/mISDNManufacturer.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/mISDNManufacturer.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/mISDNManufacturer.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,37 @@
+/* $Id: mISDNManufacturer.h,v 1.1 2003/11/11 20:31:34 keil Exp $
+ *
+ * definition of mISDN own Manufacturer functions
+ *
+ */
+
+#ifndef mISDNManufacturer_H
+#define mISDNManufacturer_H
+
+#define mISDN_MANUFACTURER_ID	0x44534963	/* "mISD" */
+
+/* mISDN_MANUFACTURER message layout
+ *
+ * Controller		dword	Controller Address
+ * ManuID		dword	mISDN_MANUFACTURER_ID
+ * Class		dword   Function Class
+ * Function		dword	Function Identifier
+ * Function specific	struct	Data for this Function
+ *
+ * in a CONF the Function specific struct contain at least
+ * a word which is coded as Capi Info word (error code)
+ */
+ 
+/*
+ * HANDSET special functions
+ *
+ */
+#define mISDN_MF_CLASS_HANDSET		1
+
+#define mISDN_MF_HANDSET_ENABLE		1	/* no function specific data */
+#define mISDN_MF_HANDSET_DISABLE	2	/* no function specific data */
+#define mISDN_MF_HANDSET_SETMICVOLUME	3	/* word volume value */
+#define mISDN_MF_HANDSET_SETSPKVOLUME	4	/* word volume value */
+#define mISDN_MF_HANDSET_GETMICVOLUME	5	/* CONF: Info, word volume value */
+#define mISDN_MF_HANDSET_GETSPKVOLUME	6	/* CONF: Info, word volume value */
+
+#endif /* mISDNManufactor_H */

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/m_capi.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/m_capi.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/m_capi.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,659 @@
+/* $Id: m_capi.h,v 1.13 2006/03/06 12:52:07 keil Exp $
+ *
+ * Rewritten CAPI Layer (Layer4 in mISDN)
+ * 
+ * The CAPI layer knows following basic Objects
+ *
+ *  - Controller_t  : the contoller instance
+ *  - Application_t : applications object
+ *  - Plci_t        : PLCI object
+ *  - AppPlci_t     : per application PLCI object
+ *  - Ncci_t	    : NCCI object
+ *
+ * For Supplementary Services
+ *  - SSProcess_t   : a process handling a service request
+ *
+ *  The controller is a Layer4 (D-channel) stack instance of
+ *  mISDN.
+ *
+ *  Applications are owned by the controller and only
+ *  handle this controller, multiplexing multiple
+ *  controller with one application is done in the higher
+ *  driver independ CAPI driver. The application contain
+ *  the Listen state machine.
+ *
+ *  Plcis are owned by the controller and are static (allocated
+ *  together with the controller). They maybe in use or inactiv.
+ *  Currently 8 PLCIs are available on a BRI (2 B-channel) controller
+ *  and 40 on a PRI (30 B-channel). They have a list of the associated
+ *  application PLCIs.
+ *  
+ *  AppPlcis are owned by the application and are
+ *  instance of the PLCI per application. They contain the
+ *  CAPI2.0 PCLI state machine
+ * 
+ *  Nccis are owned by the application Plcis. In the first version
+ *  this driver supports only one NCCI per PLCI.
+ *
+ *
+ */
+
+#ifndef __mISDN_CAPI_H__
+#define __mISDN_CAPI_H__
+
+#include <linux/mISDNif.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/capi.h>
+#include <linux/kernelcapi.h>
+#ifdef OLDCAPI_DRIVER_INTERFACE
+#include "../avmb1/capiutil.h"
+#include "../avmb1/capicmd.h"
+#include "../avmb1/capilli.h"
+#else
+#include <linux/list.h>
+#include <linux/isdn/capiutil.h>
+#include <linux/isdn/capicmd.h>
+#include <linux/isdn/capilli.h>
+#endif
+#include "asn1.h"
+#include "fsm.h"
+#ifdef MISDN_MEMDEBUG
+#include "memdbg.h"
+#define MISDN_KMEM_DEBUG		1
+#endif
+
+// ---------------------------------------------------------------------------
+// common stuff
+//     debuging levels and functions
+// ---------------------------------------------------------------------------
+
+#define CAPI_DBG_WARN		0x00000001
+#define CAPI_DBG_INFO		0x00000004
+#define CAPI_DBG_APPL		0x00000010
+#define CAPI_DBG_APPL_INFO	0x00000040
+#define CAPI_DBG_APPL_MSG	0x00000080
+#define CAPI_DBG_LISTEN		0x00000100
+#define CAPI_DBG_LISTEN_STATE	0x00000200
+#define CAPI_DBG_LISTEN_INFO	0x00000400
+#define CAPI_DBG_CONTR		0x00010000
+#define CAPI_DBG_CONTR_INFO	0x00040000
+#define CAPI_DBG_CONTR_MSG	0x00080000
+#define CAPI_DBG_PLCI		0x00100000
+#define CAPI_DBG_PLCI_STATE	0x00200000
+#define CAPI_DBG_PLCI_INFO	0x00400000
+#define CAPI_DBG_PLCI_L3	0x00800000
+#define CAPI_DBG_NCCI		0x01000000
+#define CAPI_DBG_NCCI_STATE	0x02000000
+#define CAPI_DBG_NCCI_INFO	0x04000000
+#define CAPI_DBG_NCCI_L3	0x08000000
+void capidebug(int, char *, ...);
+
+#ifdef OLDCAPI_DRIVER_INTERFACE
+extern struct capi_driver_interface *cdrv_if;                  
+extern struct capi_driver mISDN_driver;
+#endif
+
+// ---------------------------------------------------------------------------
+// Init/Exit functions
+// ---------------------------------------------------------------------------
+
+void init_listen(void);
+void init_AppPlci(void);
+void init_ncci(void);
+void free_Application(void);
+void free_listen(void);
+void free_AppPlci(void);
+void free_ncci(void);
+
+// ---------------------------------------------------------------------------
+// More CAPI defines
+// ---------------------------------------------------------------------------
+
+/* we implement 64 bit extentions */
+#define CAPI_B3_DATA_IND_HEADER_SIZE	30
+#define CAPI_MSG_DEFAULT_LEN		256
+
+#define CAPIMSG_REQ_DATAHANDLE(m)	(m[18] | (m[19]<<8))
+#define CAPIMSG_RESP_DATAHANDLE(m)	(m[12] | (m[13]<<8))
+
+#define CMSGCMD(cmsg)			CAPICMD((cmsg)->Command, (cmsg)->Subcommand)
+
+#define CAPI_MAXPLCI_BRI		8
+#define CAPI_MAXPLCI_PRI		40
+
+__u16 q931CIPValue(Q931_info_t *);
+
+// ---------------------------------------------------------------------------
+// Basic CAPI types
+// ---------------------------------------------------------------------------
+
+typedef struct _Controller	Controller_t;
+typedef struct _Application	Application_t;
+typedef struct _Ncci 		Ncci_t;
+typedef struct _Plci		Plci_t;
+typedef struct _AppPlci		AppPlci_t;
+typedef struct _SSProcess	SSProcess_t;
+
+// some helper types
+typedef struct _ConfQueue	ConfQueue_t;
+typedef struct _PLInst		PLInst_t;
+
+// Facility types
+typedef struct FacReqParm	FacReqParm_t;
+typedef struct FacConfParm	FacConfParm_t;
+
+// ---------------------------------------------------------------------------
+// Helper structs
+// ---------------------------------------------------------------------------
+
+struct _PLInst {
+	struct list_head	list;
+	u_int			state;
+	mISDNstack_t		*st;
+	mISDNinstance_t		inst;
+};
+
+struct _ConfQueue { 
+	__u32	PktId; 
+	__u16	DataHandle;
+	__u16	MsgId; 
+};
+
+struct Bprotocol {
+	__u16	B1;
+	__u16	B2;
+	__u16	B3;
+	__u8	B1cfg[16];
+	__u8	B2cfg[16];
+	__u8	B3cfg[80];
+};
+
+// ---------------------------------------------------------------------------
+// struct Controller
+// ---------------------------------------------------------------------------
+
+struct _Controller {
+	struct list_head	list;
+	mISDNinstance_t		inst;
+	int			nr_bc;
+	struct list_head	linklist;
+	struct capi_ctr		*ctrl;
+	__u32			addr;
+	int			entity;
+	int			next_id;
+	u_int			debug;
+	int			maxplci;
+	Plci_t			*plcis;
+	struct list_head	Applications;
+	struct list_head	SSProcesse;
+	spinlock_t		list_lock;
+	__u32			NotificationMask;
+	__u16			LastInvokeId;
+	char			infobuf[128];
+};
+
+// ---------------------------------------------------------------------------
+// struct Application
+// ---------------------------------------------------------------------------
+
+struct _Application {
+	struct list_head	head;
+	Controller_t		*contr;
+	__u16			ApplId;
+	__u16			MsgId;
+	__u32			InfoMask;
+	__u32			CIPmask;
+	__u32			CIPmask2;
+	__u32			NotificationMask;
+	u_long			state;
+	struct FsmInst		listen_m;
+	int			maxplci;
+	AppPlci_t		**AppPlcis;
+	capi_register_params	reg_params;
+};
+
+#define APPL_STATE_ACTIV	1
+#define APPL_STATE_RELEASE	2
+#define APPL_STATE_LISTEN	3
+#define APPL_STATE_DESTRUCTOR	4
+#define APPL_STATE_D2TRACE	8
+
+// ---------------------------------------------------------------------------
+// struct Plci
+// ---------------------------------------------------------------------------
+
+struct _Plci {
+	Controller_t		*contr;
+	__u32			addr;
+	__u32			l3id;
+	u_long			state;
+	int			nAppl;
+	struct list_head	AppPlcis;
+};
+
+#define PLCI_STATE_ACTIV	1
+#define PLCI_STATE_ALERTING	2
+#define PLCI_STATE_OUTGOING	3
+#define PLCI_STATE_STACKREADY	4
+#define PLCI_STATE_SENDDELAYED	5
+
+// ---------------------------------------------------------------------------
+// struct AppPlci
+// ---------------------------------------------------------------------------
+
+struct _AppPlci {
+	struct list_head	head;
+	__u32			addr;
+	Plci_t			*plci;
+	Application_t		*appl;
+	Controller_t		*contr;
+	PLInst_t		*link;
+	struct sk_buff_head	delayedq;
+	struct list_head	Nccis;
+	struct FsmInst		plci_m;
+	u_char			cause[4];
+	int			channel;
+	struct Bprotocol	Bprotocol;
+};
+
+// ---------------------------------------------------------------------------
+// struct Ncci
+// ---------------------------------------------------------------------------
+
+struct _Ncci {
+	struct list_head	head;
+	__u32			addr;
+	PLInst_t		*link;
+	Controller_t		*contr;
+	AppPlci_t		*AppPlci;
+	Application_t		*appl;
+	struct FsmInst		ncci_m;
+	int			savedstate;
+	int			window;
+	u_long			state;
+	ConfQueue_t		xmit_skb_handles[CAPI_MAXDATAWINDOW];
+	struct sk_buff		*recv_skb_handles[CAPI_MAXDATAWINDOW];
+	struct sk_buff_head	squeue;
+};
+
+#define NCCI_STATE_FCTRL	1
+#define NCCI_STATE_BUSY		2
+#define NCCI_STATE_L3TRANS	3
+#define	NCCI_STATE_APPLRELEASED	4
+
+// ---------------------------------------------------------------------------
+// struct SSProcess_t
+// ---------------------------------------------------------------------------
+
+struct _SSProcess {
+	struct list_head	head;
+	__u16			invokeId;
+	__u16			Function;  
+	__u32			Handle;
+	__u32			addr;
+	__u16			ApplId;
+	Controller_t		*contr;
+	struct timer_list	tl;
+	__u8			buf[128];
+};
+
+// ---------------------------------------------------------------------------
+// FUNCTION prototypes
+//
+// Controller prototypes
+// ---------------------------------------------------------------------------
+
+int		ControllerConstr(Controller_t **, mISDNstack_t *, mISDN_pid_t *, mISDNobject_t *);
+void		ControllerDestr(Controller_t *);
+void		ControllerRun(Controller_t *);
+void		ControllerDebug(Controller_t *, __u32, char *, ...);
+int		ControllerNewPlci(Controller_t *, Plci_t  **, u_int);
+int		ControllerReleasePlci(Plci_t *);
+Application_t	*getApplication4Id(Controller_t *, __u16);
+Plci_t		*getPlci4Addr(Controller_t *, __u32);
+int		ControllerL4L3(Controller_t *, u_int, int, struct sk_buff *);
+int		ControllerL3L4(mISDNinstance_t *, struct sk_buff *);
+PLInst_t	*ControllerSelChannel(Controller_t *, u_int);
+void		ControllerAddSSProcess(Controller_t *, SSProcess_t *);
+SSProcess_t	*getSSProcess4Id(Controller_t *, __u16);
+int		ControllerNextId(Controller_t *);
+
+// ---------------------------------------------------------------------------
+// Application prototypes
+// ---------------------------------------------------------------------------
+
+int		ApplicationConstr(Controller_t *, __u16, capi_register_params *);
+int		ApplicationDestr(Application_t *, int);
+void		ApplicationDebug(Application_t *appl, __u32 level, char *fmt, ...);
+void		ApplicationSendMessage(Application_t *appl, struct sk_buff *skb);
+void		SendCmsg2Application(Application_t *, _cmsg *);
+void		SendCmsgAnswer2Application(Application_t *, _cmsg *, __u16);
+void		AnswerMessage2Application(Application_t *, struct sk_buff *, __u16);
+void		applManufacturerReq(Application_t *appl, struct sk_buff *skb);
+void		applD2Trace(Application_t *appl, u_char *buf, int len);
+AppPlci_t	*ApplicationNewAppPlci(Application_t *, Plci_t *);
+AppPlci_t	*getAppPlci4addr(Application_t *, __u32);
+void		ApplicationDelAppPlci(Application_t *, AppPlci_t *);
+
+void		listenConstr(Application_t *);
+void		listenDestr(Application_t *);
+__u16		listenSendMessage(Application_t *, struct sk_buff *);
+int		listenHandle(Application_t *, __u16);
+
+// ---------------------------------------------------------------------------
+// PLCI prototypes
+// ---------------------------------------------------------------------------
+
+void	plciInit(Controller_t *);
+void	plciDebug(Plci_t *, __u32, char *, ...);
+int	plci_l3l4(Plci_t *, int, struct sk_buff *);
+void	plciAttachAppPlci(Plci_t *, AppPlci_t *);
+void	plciDetachAppPlci(Plci_t *, AppPlci_t *);
+void	plciNewCrInd(Plci_t *, void *);
+void	plciNewCrReq(Plci_t *);
+int	plciL4L3(Plci_t *, __u32, struct sk_buff *);
+
+// ---------------------------------------------------------------------------
+// AppPLCI prototypes
+// ---------------------------------------------------------------------------
+
+int	AppPlciConstr(AppPlci_t **, Application_t *, Plci_t *);
+void	AppPlciDestr(AppPlci_t *);
+void 	AppPlciDelNCCI(Ncci_t *);
+void 	AppPlci_l3l4(AppPlci_t *, int, void *);
+__u16 	AppPlciSendMessage(AppPlci_t *, struct sk_buff *);
+void	AppPlciRelease(AppPlci_t *);
+int	AppPlciFacHoldReq(AppPlci_t *, FacReqParm_t *, FacConfParm_t *);
+int	AppPlciFacRetrieveReq(AppPlci_t *, FacReqParm_t *, FacConfParm_t *);
+int	AppPlciFacSuspendReq(AppPlci_t *, FacReqParm_t *, FacConfParm_t *);
+int	AppPlciFacResumeReq(AppPlci_t *, FacReqParm_t *, FacConfParm_t *);
+void	AppPlciGetCmsg(AppPlci_t *, _cmsg *);
+Ncci_t	*getNCCI4addr(AppPlci_t *, __u32, int);
+void	ConnectB3Request(AppPlci_t *, struct sk_buff *);
+void	DisconnectB3Request(AppPlci_t *, struct sk_buff *);
+int	AppPlcimISDN_Active(AppPlci_t *);
+
+#define	GET_NCCI_EXACT		1
+#define GET_NCCI_ONLY_PLCI	2
+#define GET_NCCI_PLCI		3
+
+// ---------------------------------------------------------------------------
+// NCCI prototypes
+// ---------------------------------------------------------------------------
+
+Ncci_t	*ncciConstr(AppPlci_t *);
+void	ncciDestr(Ncci_t *);
+void	ncciApplRelease(Ncci_t *);
+void	ncciDelAppPlci(Ncci_t *);
+void	ncciSendMessage(Ncci_t *, struct sk_buff *);
+int	ncci_l3l4(Ncci_t *, mISDN_head_t *, struct sk_buff *);
+void	ncciGetCmsg(Ncci_t *, _cmsg *);
+int	ncci_l3l4_direct(Ncci_t *, mISDN_head_t *, struct sk_buff *);
+void	ncciReleaseLink(Ncci_t *);
+
+// ---------------------------------------------------------------------------
+//  SSProcess prototypes
+// ---------------------------------------------------------------------------
+
+SSProcess_t	*SSProcessConstr(Application_t *, __u16, __u32);
+void		SSProcessDestr(SSProcess_t *);
+int		Supplementary_l3l4(Controller_t *, __u32, struct sk_buff *);
+void		SupplementaryFacilityReq(Application_t *, _cmsg *);
+void		SendSSNotificationEvent(AppPlci_t *, u16);
+
+// ---------------------------------------------------------------------------
+// INFOMASK defines (LISTEN commands)
+// ---------------------------------------------------------------------------
+
+#define CAPI_INFOMASK_CAUSE 	0x0001
+#define CAPI_INFOMASK_DATETIME	0x0002
+#define CAPI_INFOMASK_DISPLAY	0x0004
+#define CAPI_INFOMASK_USERUSER	0x0008
+#define CAPI_INFOMASK_PROGRESS	0x0010
+#define CAPI_INFOMASK_FACILITY	0x0020
+#define CAPI_INFOMASK_CHARGE	0x0040
+#define CAPI_INFOMASK_CALLEDPN	0x0080
+#define CAPI_INFOMASK_CHANNELID	0x0100
+#define CAPI_INFOMASK_EARLYB3	0x0200
+#define CAPI_INFOMASK_REDIRECT	0x0400
+/* bit 11 reserved */
+#define CAPI_INFOMASK_COMPLETE	0x1000
+/* bit 13-31 reserved */
+
+// ---------------------------------------------------------------------------
+// Supplementary Services
+// ---------------------------------------------------------------------------
+
+#define SuppServiceHR			0x00000001
+#define SuppServiceTP			0x00000002
+#define SuppServiceECT			0x00000004
+#define SuppService3PTY			0x00000008
+#define SuppServiceCF			0x00000010
+#define SuppServiceCD			0x00000020
+#define SuppServiceMCID			0x00000040
+#define SuppServiceCCBS			0x00000080
+
+#define mISDNSupportedServices		(SuppServiceCD | \
+					 SuppServiceCF | \
+					 SuppServiceTP | \
+					 SuppServiceHR)
+
+// ---------------------------------------------------------------------------
+// structs for Facillity requests
+// ---------------------------------------------------------------------------
+
+struct FacReqListen {
+	__u32 NotificationMask;
+};
+
+struct FacReqSuspend {
+	__u8 *CallIdentity;
+};
+
+struct FacReqResume {
+	__u8 *CallIdentity;
+};
+
+struct FacReqCFActivate {
+	__u32 Handle;
+	__u16 Procedure;
+	__u16 BasicService;
+	__u8  *ServedUserNumber;
+	__u8  *ForwardedToNumber;
+	__u8  *ForwardedToSubaddress;
+};
+
+struct FacReqCFDeactivate {
+	__u32 Handle;
+	__u16 Procedure;
+	__u16 BasicService;
+	__u8  *ServedUserNumber;
+};
+
+struct FacReqCDeflection {
+	__u16 PresentationAllowed;
+	__u8  *DeflectedToNumber;
+	__u8  *DeflectedToSubaddress;
+};
+
+#define FacReqCFInterrogateParameters FacReqCFDeactivate
+
+struct FacReqCFInterrogateNumbers {
+	__u32 Handle;
+};
+
+struct FacReqParm {
+	__u16 Function;
+	union {
+		struct FacReqListen Listen;
+		struct FacReqSuspend Suspend;
+		struct FacReqResume Resume;
+		struct FacReqCFActivate CFActivate;
+		struct FacReqCFDeactivate CFDeactivate;
+		struct FacReqCFInterrogateParameters CFInterrogateParameters;
+		struct FacReqCFInterrogateNumbers CFInterrogateNumbers;
+		struct FacReqCDeflection CDeflection;
+	} u;
+};
+
+// ---------------------------------------------------------------------------
+// structs for Facillity confirms
+// ---------------------------------------------------------------------------
+
+struct FacConfGetSupportedServices {
+	__u16 SupplementaryServiceInfo;
+	__u32 SupportedServices;
+};
+
+struct FacConfInfo {
+	__u16 SupplementaryServiceInfo;
+};
+
+struct FacConfParm {
+	__u16 Function;
+	union {
+		struct FacConfGetSupportedServices GetSupportedServices;
+		struct FacConfInfo Info;
+	} u;
+};
+
+int capiEncodeWord(__u8 *dest, __u16 i);
+int capiEncodeDWord(__u8 *dest, __u32 i);
+int capiEncodeFacIndCFact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle);
+int capiEncodeFacIndCFdeact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle);
+int capiEncodeFacIndCFNotAct(__u8 *dest, struct ActDivNotification *actNot);
+int capiEncodeFacIndCFNotDeact(__u8 *dest, struct DeactDivNotification *deactNot);
+int capiEncodeFacIndCFinterParameters(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle, 
+				      struct IntResultList *intResultList);
+int capiEncodeFacIndCFinterNumbers(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle, 
+				   struct ServedUserNumberList *list);
+int capiEncodeFacConfParm(__u8 *dest, struct FacConfParm *facConfParm);
+
+int capiEncodeFacIndSuspend(__u8 *dest, __u16  SupplementaryServiceReason);
+
+// ---------------------------------------------------------------------------
+// mISDN kmem cache managment functions
+// ---------------------------------------------------------------------------
+
+/* kmem caches */
+extern struct kmem_cache	*mISDN_cmsg_cp;
+extern struct kmem_cache	*mISDN_AppPlci_cp;
+extern struct kmem_cache	*mISDN_ncci_cp;
+extern struct kmem_cache	*mISDN_sspc_cp;
+
+#ifdef MISDN_KMEM_DEBUG
+typedef struct _kd_cmsg		_kd_cmsg_t;
+typedef struct _kd_Ncci		_kd_Ncci_t;
+typedef struct _kd_AppPlci	_kd_AppPlci_t;
+typedef struct _kd_SSProcess	_kd_SSProcess_t;
+typedef struct _kd_all		_kd_all_t;
+
+typedef	struct __km_dbg_item {
+	struct list_head	head;
+	long			typ;
+	char			*file;
+	u_int			line;
+} km_dbg_item_t;
+
+struct _kd_cmsg {
+	km_dbg_item_t		kdi;
+	_cmsg			cm;
+};
+
+struct _kd_AppPlci {
+	km_dbg_item_t		kdi;
+	AppPlci_t		ap;
+};
+
+struct _kd_Ncci {
+	km_dbg_item_t		kdi;
+	Ncci_t			ni;
+};
+
+struct _kd_SSProcess {
+	km_dbg_item_t		kdi;
+	SSProcess_t		sp;
+};
+
+struct _kd_all {
+	km_dbg_item_t		kdi;
+	union {
+		_cmsg		cm;
+		AppPlci_t	ap;
+		Ncci_t		ni;
+		SSProcess_t	sp;
+	} a;
+};
+
+#define KDB_GET_KDI(kd)		((km_dbg_item_t *)(((u_char *)kd) - sizeof(km_dbg_item_t)))
+#define KDB_GET_KDALL(kd)	((_kd_all_t *)(((u_char *)kd) - sizeof(km_dbg_item_t)))
+
+#define KM_DBG_TYP_CM		1
+#define KM_DBG_TYP_AP		2
+#define KM_DBG_TYP_NI		3
+#define KM_DBG_TYP_SP		4
+
+#define cmsg_alloc()		_kd_cmsg_alloc(__FILE__, __LINE__)
+extern _cmsg			*_kd_cmsg_alloc(char *, int);
+extern void			cmsg_free(_cmsg *cm);
+
+#define AppPlci_alloc()		_kd_AppPlci_alloc(__FILE__, __LINE__)
+extern AppPlci_t		*_kd_AppPlci_alloc(char *, int);
+extern void			AppPlci_free(AppPlci_t *ap);
+
+#define ncci_alloc()		_kd_ncci_alloc(__FILE__, __LINE__)
+extern Ncci_t			*_kd_ncci_alloc(char *, int);
+extern void			ncci_free(Ncci_t *ni);
+
+#define SSProcess_alloc()	_kd_SSProcess_alloc(__FILE__, __LINE__)
+extern SSProcess_t		*_kd_SSProcess_alloc(char *, int);
+extern void			SSProcess_free(SSProcess_t *sp);
+
+#else /* ! MISDN_KMEM_DEBUG */
+
+static __inline__ _cmsg *cmsg_alloc(void)
+{
+	return(kmem_cache_alloc(mISDN_cmsg_cp, GFP_ATOMIC));
+}
+
+static __inline__ void cmsg_free(_cmsg *cm)
+{
+	kmem_cache_free(mISDN_cmsg_cp, cm);
+}
+
+static __inline__ AppPlci_t *AppPlci_alloc(void)
+{
+	return(kmem_cache_alloc(mISDN_AppPlci_cp, GFP_ATOMIC));
+}
+
+static __inline__ void AppPlci_free(AppPlci_t *ap)
+{
+	kmem_cache_free(mISDN_AppPlci_cp, ap);
+}
+
+static __inline__ Ncci_t *ncci_alloc(void)
+{
+	return(kmem_cache_alloc(mISDN_ncci_cp, GFP_ATOMIC));
+}
+
+static __inline__ void ncci_free(Ncci_t *ni)
+{
+	kmem_cache_free(mISDN_ncci_cp, ni);
+}
+
+static __inline__ SSProcess_t *SSProcess_alloc(void)
+{
+	return(kmem_cache_alloc(mISDN_sspc_cp, GFP_ATOMIC));
+}
+
+static __inline__ void SSProcess_free(SSProcess_t *sp)
+{
+	kmem_cache_free(mISDN_sspc_cp, sp);
+}
+
+#endif /* MISDN_KMEM_DEBUG */
+// cmsg_alloc with error handling for void functions
+#define CMSG_ALLOC(cm)	if (!(cm = cmsg_alloc())) {int_error();return;}
+
+#endif


Property changes on: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/m_capi.h
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/memdbg.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/memdbg.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/memdbg.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,288 @@
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/skbuff.h>
+#include <linux/mISDNif.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+static struct list_head mISDN_memdbg_list = LIST_HEAD_INIT(mISDN_memdbg_list);
+static struct list_head mISDN_skbdbg_list = LIST_HEAD_INIT(mISDN_skbdbg_list);
+static spinlock_t	memdbg_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t	skbdbg_lock = SPIN_LOCK_UNLOCKED;
+static kmem_cache_t	*mid_sitem_cache;
+
+#define MAX_FILE_STRLEN		(64 - 3*sizeof(u_int) - sizeof(struct list_head))
+
+#define MID_ITEM_TYP_KMALLOC	1
+#define MID_ITEM_TYP_VMALLOC	2
+
+typedef struct _mid_item {
+	struct list_head	head;
+	u_int			typ;
+	u_int			size;
+	u_int			line;
+	char			file[MAX_FILE_STRLEN];
+} _mid_item_t;
+
+typedef struct _mid_sitem {
+	struct list_head	head;
+	struct sk_buff		*skb;
+	unsigned int		size;
+	int			line;
+	char			file[MAX_FILE_STRLEN];
+} _mid_sitem_t;
+
+void *
+__mid_kmalloc(size_t size, int ord, char *fn, int line)
+{
+	_mid_item_t	*mid;
+	u_long		flags;
+
+	mid = kmalloc(size + sizeof(_mid_item_t), ord);
+	if (mid) {
+		INIT_LIST_HEAD(&mid->head);
+		mid->typ  = MID_ITEM_TYP_KMALLOC;
+		mid->size = size;
+		mid->line = line;
+		memcpy(mid->file, fn, MAX_FILE_STRLEN);
+		mid->file[MAX_FILE_STRLEN-1] = 0;
+		spin_lock_irqsave(&memdbg_lock, flags);
+		list_add_tail(&mid->head, &mISDN_memdbg_list);
+		spin_unlock_irqrestore(&memdbg_lock, flags);
+		return((void *)&mid->file[MAX_FILE_STRLEN]);
+	} else
+		return(NULL);
+}
+
+void
+__mid_kfree(const void *p)
+{
+	_mid_item_t	*mid;
+	u_long		flags;
+
+	if (!p)
+		return;
+	mid = (_mid_item_t *)((u_char *)p - sizeof(_mid_item_t));
+	spin_lock_irqsave(&memdbg_lock, flags);
+	list_del(&mid->head);
+	spin_unlock_irqrestore(&memdbg_lock, flags);
+	kfree(mid);
+}
+
+void *
+__mid_vmalloc(size_t size, char *fn, int line)
+{
+	_mid_item_t	*mid;
+	u_long		flags;
+
+	mid = vmalloc(size + sizeof(_mid_item_t));
+	if (mid) {
+		INIT_LIST_HEAD(&mid->head);
+		mid->typ  = MID_ITEM_TYP_VMALLOC;
+		mid->size = size;
+		mid->line = line;
+		memcpy(mid->file, fn, MAX_FILE_STRLEN);
+		mid->file[MAX_FILE_STRLEN-1] = 0; 
+		spin_lock_irqsave(&memdbg_lock, flags);
+		list_add_tail(&mid->head, &mISDN_memdbg_list);
+		spin_unlock_irqrestore(&memdbg_lock, flags);
+		return((void *)&mid->file[MAX_FILE_STRLEN]);
+	} else
+		return(NULL);
+}
+
+void
+__mid_vfree(const void *p)
+{
+	_mid_item_t	*mid;
+	u_long		flags;
+
+	if (!p)
+		return;
+	mid = (_mid_item_t *)((u_char *)p - sizeof(_mid_item_t));
+	spin_lock_irqsave(&memdbg_lock, flags);
+	list_del(&mid->head);
+	spin_unlock_irqrestore(&memdbg_lock, flags);
+	vfree(mid);
+}
+
+static void
+__mid_skb_destructor(struct sk_buff *skb)
+{
+	struct list_head	*item;
+	_mid_sitem_t		*sid;
+	u_long		flags;
+
+	spin_lock_irqsave(&skbdbg_lock, flags);
+	list_for_each(item, &mISDN_skbdbg_list) {
+		sid = (_mid_sitem_t *)item;
+		if (sid->skb == skb) {
+			list_del(&sid->head);
+			spin_unlock_irqrestore(&skbdbg_lock, flags);
+			kmem_cache_free(mid_sitem_cache, sid);
+			return;
+		}
+	}
+	spin_unlock_irqrestore(&skbdbg_lock, flags);
+	printk(KERN_DEBUG "%s: item(%p) not in list\n", __FUNCTION__, skb);
+}
+
+static __inline__ void
+__mid_sitem_setup(struct sk_buff *skb, unsigned int size, char *fn, int line)
+{
+	_mid_sitem_t	*sid;
+	u_long		flags;
+
+	sid = kmem_cache_alloc(mid_sitem_cache, GFP_ATOMIC);
+	if (!sid) {
+		printk(KERN_DEBUG "%s: no memory for sitem skb %p %s:%d\n",
+			__FUNCTION__, skb, fn, line);
+		return;
+	}
+	INIT_LIST_HEAD(&sid->head);
+	sid->skb = skb;
+	sid->size = size;
+	sid->line = line;
+	memcpy(sid->file, fn, MAX_FILE_STRLEN);
+	sid->file[MAX_FILE_STRLEN-1] = 0; 
+	skb->destructor = __mid_skb_destructor;
+	spin_lock_irqsave(&skbdbg_lock, flags);
+	list_add_tail(&sid->head, &mISDN_skbdbg_list);
+	spin_unlock_irqrestore(&skbdbg_lock, flags);
+}
+
+struct sk_buff *
+__mid_alloc_skb(unsigned int size, int gfp_mask, char *fn, int line)
+{
+	struct sk_buff	*skb = alloc_skb(size, gfp_mask);
+
+	if (!skb)
+		return(NULL);
+	__mid_sitem_setup(skb, size, fn, line);
+	return(skb);
+}
+
+struct sk_buff *
+__mid_dev_alloc_skb(unsigned int size, char *fn, int line)
+{
+	struct sk_buff	*skb = dev_alloc_skb(size);
+
+	if (!skb)
+		return(NULL);
+	__mid_sitem_setup(skb, size, fn, line);
+	return(skb);
+}
+
+struct sk_buff
+*__mid_skb_clone(struct sk_buff *skb, int gfp_mask, char *fn, int line)
+{
+	struct sk_buff	*nskb = skb_clone(skb, gfp_mask);
+
+	if (!nskb)
+		return(NULL);
+	__mid_sitem_setup(nskb, (nskb->end - nskb->head), fn, line);
+	return(nskb);
+}
+
+struct sk_buff
+*__mid_skb_copy(struct sk_buff *skb, int gfp_mask, char *fn, int line)
+{
+	struct sk_buff	*nskb = skb_copy(skb, gfp_mask);
+
+	if (!nskb)
+		return(NULL);
+	__mid_sitem_setup(nskb, (nskb->end - nskb->head), fn, line);
+	return(nskb);
+}
+
+struct sk_buff
+*__mid_skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom, char *fn, int line)
+{
+	struct sk_buff	*nskb = skb_realloc_headroom(skb, headroom);
+
+	if (!nskb || (nskb == skb))
+		return(nskb);
+	__mid_sitem_setup(nskb, (nskb->end - nskb->head), fn, line);
+	return(nskb);
+}
+
+void
+__mid_cleanup(void)
+{
+	struct list_head	*item, *next;
+	_mid_item_t		*mid;
+	_mid_sitem_t		*sid;
+	mISDN_head_t		*hh;
+	int			n = 0;
+	u_long			flags;
+
+	spin_lock_irqsave(&memdbg_lock, flags);
+	list_for_each_safe(item, next, &mISDN_memdbg_list) {
+		mid = (_mid_item_t *)item;
+		switch(mid->typ) {
+			case MID_ITEM_TYP_KMALLOC:
+				printk(KERN_ERR "not freed kmalloc size(%d) from %s:%d\n",
+					mid->size, mid->file, mid->line);
+				kfree(mid);
+				break;
+			case MID_ITEM_TYP_VMALLOC:
+				printk(KERN_ERR "not freed vmalloc size(%d) from %s:%d\n",
+					mid->size, mid->file, mid->line);
+				vfree(mid);
+				break;
+			default:
+				printk(KERN_ERR "unknown mid->typ(%d) size(%d) from %s:%d\n",
+					mid->typ, mid->size, mid->file, mid->line);
+				break;
+		}
+		n++;
+	}
+	spin_unlock_irqrestore(&memdbg_lock, flags);
+	printk(KERN_DEBUG "%s: %d kmalloc item(s) freed\n", __FUNCTION__, n);
+	n = 0;
+	spin_lock_irqsave(&skbdbg_lock, flags);
+	list_for_each_safe(item, next, &mISDN_skbdbg_list) {
+		sid = (_mid_sitem_t *)item;
+		hh = mISDN_HEAD_P(sid->skb);
+		printk(KERN_ERR "not freed skb(%p) size(%d) prim(%x) dinfo(%x) allocated at %s:%d\n",
+			sid->skb, sid->size, hh->prim, hh->dinfo, sid->file, sid->line);
+		/*maybe the skb is still aktiv */
+		sid->skb->destructor = NULL;
+		list_del(&sid->head);
+		kmem_cache_free(mid_sitem_cache, sid);
+		n++;
+	}
+	spin_unlock_irqrestore(&skbdbg_lock, flags);
+	if (mid_sitem_cache)
+		kmem_cache_destroy(mid_sitem_cache);
+	printk(KERN_DEBUG "%s: %d sk_buff item(s) freed\n", __FUNCTION__, n);
+}
+
+int
+__mid_init(void)
+{
+	mid_sitem_cache = kmem_cache_create("mISDN_skbdbg",
+				sizeof(_mid_sitem_t),
+				0, 0, NULL, NULL);
+	if (!mid_sitem_cache)
+		return(-ENOMEM);
+	return(0);
+}
+
+#ifdef MODULE
+EXPORT_SYMBOL(__mid_kmalloc);
+EXPORT_SYMBOL(__mid_kfree);
+EXPORT_SYMBOL(__mid_vmalloc);
+EXPORT_SYMBOL(__mid_vfree);
+EXPORT_SYMBOL(__mid_alloc_skb);
+EXPORT_SYMBOL(__mid_dev_alloc_skb);
+EXPORT_SYMBOL(__mid_skb_clone);
+EXPORT_SYMBOL(__mid_skb_copy);
+EXPORT_SYMBOL(__mid_skb_realloc_headroom);
+
+#endif
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/memdbg.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/memdbg.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/memdbg.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,41 @@
+#ifndef MEMDBG_H
+#define MEMDBG_H
+
+#ifdef MISDN_MEMDEBUG
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+
+#undef kmalloc
+#undef kfree
+#undef vmalloc
+#undef vfree
+#undef alloc_skb
+#undef dev_alloc_skb
+#undef skb_clone
+#undef skb_copy
+#undef skb_realloc_headroom
+
+#define kmalloc(a, b)			__mid_kmalloc(a, b, __FILE__, __LINE__)
+#define kfree(a)			__mid_kfree(a)
+#define vmalloc(s)			__mid_vmalloc(s, __FILE__, __LINE__)
+#define vfree(p)			__mid_vfree(p)
+#define alloc_skb(a, b)			__mid_alloc_skb(a, b, __FILE__, __LINE__)
+#define dev_alloc_skb(a)		__mid_dev_alloc_skb(a, __FILE__, __LINE__)
+#define skb_clone(a, b)			__mid_skb_clone(a, b, __FILE__, __LINE__)
+#define skb_copy(a, b)			__mid_skb_copy(a, b, __FILE__, __LINE__)
+#define skb_realloc_headroom(a, b)	__mid_skb_realloc_headroom(a, b, __FILE__, __LINE__)
+
+extern void		*__mid_kmalloc(size_t, int, char *, int);
+extern void		__mid_kfree(const void *);
+extern void		*__mid_vmalloc(size_t, char *, int);
+extern void		__mid_vfree(const void *);
+extern void		__mid_cleanup(void);
+extern int		__mid_init(void);
+extern struct sk_buff	*__mid_alloc_skb(unsigned int,int, char *, int);
+extern struct sk_buff	*__mid_dev_alloc_skb(unsigned int,char *, int);
+extern struct sk_buff	*__mid_skb_clone(struct sk_buff *, int, char *, int);
+extern struct sk_buff	*__mid_skb_copy(struct sk_buff *, int, char *, int);
+extern struct sk_buff	*__mid_skb_realloc_headroom(struct sk_buff *, unsigned int, char *, int);
+#endif
+
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/ncci.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/ncci.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/ncci.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1412 @@
+/* $Id: ncci.c,v 1.29 2006/09/14 15:51:46 gkelleter Exp $
+ *
+ */
+
+#include "m_capi.h"
+#include "helper.h"
+#include "debug.h"
+#include "dss1.h"
+#include "mISDNManufacturer.h"
+
+static int	ncciL4L3(Ncci_t *, u_int, int, int, void *, struct sk_buff *);
+
+static char	logbuf[8000];
+
+void
+log_skbdata(struct sk_buff *skb)
+{
+	char *t = logbuf;
+
+	t += sprintf(t, "skbdata(%d):", skb->len);
+	mISDN_QuickHex(t, skb->data, skb->len);
+	printk(KERN_DEBUG "%s\n", logbuf);
+}
+
+// --------------------------------------------------------------------
+// NCCI state machine
+//
+// Some rules:
+//   *  EV_AP_*  events come from CAPI Application
+//   *  EV_DL_*  events come from the ISDN stack
+//   *  EV_NC_*  events generated in NCCI handling
+//   *  messages are send in the routine that handle the event
+//
+// --------------------------------------------------------------------
+enum {
+	ST_NCCI_N_0,
+	ST_NCCI_N_0_1,
+	ST_NCCI_N_1,
+	ST_NCCI_N_2,
+	ST_NCCI_N_ACT,
+	ST_NCCI_N_3,
+	ST_NCCI_N_4,
+	ST_NCCI_N_5,
+}
+
+const ST_NCCI_COUNT = ST_NCCI_N_5 + 1;
+
+static char *str_st_ncci[] = {
+	"ST_NCCI_N_0",
+	"ST_NCCI_N_0_1",
+	"ST_NCCI_N_1",
+	"ST_NCCI_N_2",
+	"ST_NCCI_N_ACT",
+	"ST_NCCI_N_3",
+	"ST_NCCI_N_4",
+	"ST_NCCI_N_5",
+}; 
+
+enum {
+	EV_AP_CONNECT_B3_REQ,
+	EV_NC_CONNECT_B3_CONF,
+	EV_NC_CONNECT_B3_IND,
+	EV_AP_CONNECT_B3_RESP,
+	EV_NC_CONNECT_B3_ACTIVE_IND,
+	EV_AP_CONNECT_B3_ACTIVE_RESP,
+	EV_AP_RESET_B3_REQ,
+	EV_NC_RESET_B3_IND,
+	EV_NC_RESET_B3_CONF,
+	EV_AP_RESET_B3_RESP,
+	EV_NC_CONNECT_B3_T90_ACTIVE_IND,
+	EV_AP_DISCONNECT_B3_REQ,
+	EV_NC_DISCONNECT_B3_IND,
+	EV_NC_DISCONNECT_B3_CONF,
+	EV_AP_DISCONNECT_B3_RESP,
+	EV_AP_FACILITY_REQ,
+	EV_AP_MANUFACTURER_REQ,
+	EV_DL_ESTABLISH_IND,
+	EV_DL_ESTABLISH_CONF,
+	EV_DL_RELEASE_IND,
+	EV_DL_RELEASE_CONF,
+	EV_DL_DOWN_IND,
+	EV_NC_LINKDOWN,
+	EV_AP_RELEASE,
+}
+
+const EV_NCCI_COUNT = EV_AP_RELEASE + 1;
+
+static char* str_ev_ncci[] = {
+	"EV_AP_CONNECT_B3_REQ",
+	"EV_NC_CONNECT_B3_CONF",
+	"EV_NC_CONNECT_B3_IND",
+	"EV_AP_CONNECT_B3_RESP",
+	"EV_NC_CONNECT_B3_ACTIVE_IND",
+	"EV_AP_CONNECT_B3_ACTIVE_RESP",
+	"EV_AP_RESET_B3_REQ",
+	"EV_NC_RESET_B3_IND",
+	"EV_NC_RESET_B3_CONF",
+	"EV_AP_RESET_B3_RESP",
+	"EV_NC_CONNECT_B3_T90_ACTIVE_IND",
+	"EV_AP_DISCONNECT_B3_REQ",
+	"EV_NC_DISCONNECT_B3_IND",
+	"EV_NC_DISCONNECT_B3_CONF",
+	"EV_AP_DISCONNECT_B3_RESP",
+	"EV_AP_FACILITY_REQ",
+	"EV_AP_MANUFACTURER_REQ",
+	"EV_DL_ESTABLISH_IND",
+	"EV_DL_ESTABLISH_CONF",
+	"EV_DL_RELEASE_IND",
+	"EV_DL_RELEASE_CONF",
+	"EV_DL_DOWN_IND",
+	"EV_NC_LINKDOWN",
+	"EV_AP_RELEASE",
+};
+
+static struct Fsm ncci_fsm = { 0, 0, 0, 0, 0 };
+static struct Fsm ncciD_fsm = { 0, 0, 0, 0, 0 };
+
+
+static int
+select_NCCIaddr(Ncci_t *ncci) {
+	__u32	addr;
+	Ncci_t	*test;
+
+	if (!ncci->AppPlci)
+		return(-EINVAL);
+	addr = 0x00010000 | ncci->AppPlci->addr;
+	while (addr < 0x00ffffff) { /* OK not more as 255 NCCI */
+		test = getNCCI4addr(ncci->AppPlci, addr, GET_NCCI_EXACT);
+		if (!test) {
+			ncci->addr = addr;
+#ifdef OLDCAPI_DRIVER_INTERFACE
+			ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, ncci->addr, ncci->window);
+#endif
+			return(0);
+		}
+		addr += 0x00010000;
+	}
+	ncci->addr = ncci->AppPlci->addr;
+	return(-EBUSY);
+}
+
+static void
+ncci_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	char tmp[128];
+	char *p = tmp;
+	va_list args;
+	Ncci_t *ncci = fi->userdata;
+	
+	if (!ncci->ncci_m.debug)
+		return;
+	va_start(args, fmt);
+	p += sprintf(p, "NCCI 0x%x: ", ncci->addr);
+	p += vsprintf(p, fmt, args);
+	*p++ = '\n';
+	*p = 0;
+	printk(KERN_DEBUG "%s", tmp);
+	va_end(args);
+}
+
+static inline void
+SKB2Application(Ncci_t *ncci, struct sk_buff *skb)
+{
+	if (!test_bit(NCCI_STATE_APPLRELEASED, &ncci->state)) {
+#ifdef OLDCAPI_DRIVER_INTERFACE
+		ncci->contr->ctrl->handle_capimsg(ncci->contr->ctrl, ncci->appl->ApplId, skb);
+#else
+		capi_ctr_handle_message(ncci->contr->ctrl, ncci->appl->ApplId, skb);
+#endif
+	}
+}
+
+static inline int
+SKB_l4l3(Ncci_t *ncci, struct sk_buff *skb)
+{
+	if (!ncci->link)
+		return(-ENXIO);
+	return(mISDN_queue_down(&ncci->link->inst, 0, skb));
+}
+
+static inline void
+Send2Application(Ncci_t *ncci, _cmsg *cmsg)
+{
+	SendCmsg2Application(ncci->appl, cmsg);
+}
+
+static inline void
+ncciCmsgHeader(Ncci_t *ncci, _cmsg *cmsg, __u8 cmd, __u8 subcmd)
+{
+	capi_cmsg_header(cmsg, ncci->appl->ApplId, cmd, subcmd, 
+			 ncci->appl->MsgId++, ncci->addr);
+}
+
+static void
+ncci_connect_b3_req(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	_cmsg	*cmsg = arg;
+
+	// FIXME
+	if (!ncci->appl) {
+		cmsg_free(cmsg);
+		return;
+	}
+	mISDN_FsmChangeState(fi, ST_NCCI_N_0_1);
+	capi_cmsg_answer(cmsg);
+
+	// TODO: NCPI handling
+	/* We need a real addr now */
+	if (0xffff0000 & ncci->addr) {
+		int_error();
+		cmsg->Info = CapiNoNcciAvailable;
+		ncci->addr = ncci->AppPlci->addr;
+	} else {
+		cmsg->Info = 0;
+		if (select_NCCIaddr(ncci)) {
+			int_error();
+			cmsg->Info = CapiNoNcciAvailable;
+		}
+	}
+	cmsg->adr.adrNCCI = ncci->addr;
+	ncci_debug(fi, "ncci_connect_b3_req NCCI %x cmsg->Info(%x)",
+		ncci->addr, cmsg->Info);
+	if (mISDN_FsmEvent(fi, EV_NC_CONNECT_B3_CONF, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+ncci_connect_b3_ind(struct FsmInst *fi, int event, void *arg)
+{
+	// from DL_ESTABLISH
+	mISDN_FsmChangeState(fi, ST_NCCI_N_1);
+	Send2Application(fi->userdata, arg);
+}
+
+static void
+ncci_connect_b3_resp(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t *ncci = fi->userdata;
+	_cmsg *cmsg = arg;
+  
+	// FIXME
+	if (!ncci->appl) {
+		cmsg_free(cmsg);
+		return;
+	}
+	if (cmsg->Info == 0) {
+		mISDN_FsmChangeState(fi, ST_NCCI_N_2);
+		ncciCmsgHeader(ncci, cmsg, CAPI_CONNECT_B3_ACTIVE, CAPI_IND);
+		event = EV_NC_CONNECT_B3_ACTIVE_IND;
+	} else {
+		mISDN_FsmChangeState(fi, ST_NCCI_N_4);
+		cmsg->Info = 0;
+		ncciCmsgHeader(ncci, cmsg, CAPI_DISCONNECT_B3, CAPI_IND);
+		event = EV_NC_DISCONNECT_B3_IND;
+	}
+	if (mISDN_FsmEvent(&ncci->ncci_m, event, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+ncci_connect_b3_conf(struct FsmInst *fi, int event, void *arg)
+{
+	_cmsg	*cmsg = arg;
+  
+	if (cmsg->Info == 0) {
+		mISDN_FsmChangeState(fi, ST_NCCI_N_2);
+		Send2Application(fi->userdata, cmsg);
+		ncciL4L3(fi->userdata, DL_ESTABLISH | REQUEST, 0, 0, NULL, NULL);
+	} else {
+		mISDN_FsmChangeState(fi, ST_NCCI_N_0);
+		Send2Application(fi->userdata, cmsg);
+		ncciDestr(fi->userdata);
+	}
+}
+
+static void
+ncci_disconnect_b3_req(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	_cmsg	*cmsg = arg;
+	__u16	Info = 0;
+
+	if (ncci->appl) { //FIXME
+		/* TODO: handle NCPI and wait for all DATA_B3_REQ confirmed on
+		 * related protocols (voice, T30)
+		 */ 
+		capi_cmsg_answer(cmsg);
+		cmsg->Info = Info;
+		if (mISDN_FsmEvent(fi, EV_NC_DISCONNECT_B3_CONF, cmsg))
+			cmsg_free(cmsg);
+	} else {
+		cmsg_free(cmsg);
+		mISDN_FsmChangeState(fi, ST_NCCI_N_4);
+	}
+	ncciL4L3(ncci, DL_RELEASE | REQUEST, 0, 0, NULL, NULL);
+}
+
+static void
+ncci_disconnect_b3_conf(struct FsmInst *fi, int event, void *arg)
+{
+	_cmsg	*cmsg = arg;
+
+	if (cmsg->Info == 0) {
+		mISDN_FsmChangeState(fi, ST_NCCI_N_4);
+	}
+	Send2Application(fi->userdata, cmsg);
+}
+
+static void
+ncci_disconnect_b3_ind(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_NCCI_N_5);
+	if (ncci->appl) { // FIXME
+		Send2Application(ncci, arg);
+	} else {
+		cmsg_free(arg);
+		mISDN_FsmChangeState(fi, ST_NCCI_N_0);
+		ncciDestr(ncci);
+	}
+}
+
+static void
+ncci_disconnect_b3_resp(struct FsmInst *fi, int event, void *arg)
+{
+	if (arg)
+		cmsg_free(arg);
+	mISDN_FsmChangeState(fi, ST_NCCI_N_0);
+	ncciDestr(fi->userdata);
+}
+
+static void
+ncci_facility_req(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	_cmsg	*cmsg = arg;
+	u_char	*p = cmsg->FacilityRequestParameter;
+	u16	func;
+	int	op;
+
+	if (!ncci->appl)
+		return;
+	capi_cmsg_answer(cmsg);
+	cmsg->Info = CAPI_NOERROR;
+	if (cmsg->FacilitySelector == 0) { // Handset
+		int err = ncciL4L3(ncci, PH_CONTROL | REQUEST, HW_POTS_ON, 0, NULL, NULL);
+		if (err)
+			cmsg->Info = CapiFacilityNotSupported;
+	} else if (cmsg->FacilitySelector != 1) { // not DTMF
+		cmsg->Info = CapiIllMessageParmCoding;
+	} else if (p && p[0]) {
+		func = CAPIMSG_U16(p, 1);
+		ncci_debug(fi, "%s: p %02x %02x %02x func(%x)",
+			__FUNCTION__, p[0], p[1], p[2], func);
+		switch (func) {
+			case 1:
+				op = DTMF_TONE_START;
+				ncciL4L3(ncci, PH_CONTROL | REQUEST, 0, sizeof(int), &op, NULL);
+				break;
+			case 2:
+				op = DTMF_TONE_STOP;
+				ncciL4L3(ncci, PH_CONTROL | REQUEST, 0, sizeof(int), &op, NULL);
+				break;
+			default:
+				cmsg->Info = CapiFacilityNotSupported;
+				break;
+		}
+	} else
+		cmsg->Info = CapiIllMessageParmCoding;
+		
+	Send2Application(ncci, cmsg);
+}
+
+static void
+ncci_manufacturer_req(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	_cmsg	*cmsg = arg;
+	int	err, op;
+	struct  _manu_conf_para {
+			u8	len;
+			u16	Info;
+			u16	vol;
+		} mcp = {2, CAPI_NOERROR,0};
+	struct  _manu_req_para {
+			u8	len;
+			u16	vol;
+		} __attribute__((packed)) *mrp;
+
+	if (!ncci->appl)
+		return;
+	mrp = (struct  _manu_req_para *)cmsg->ManuData;
+	capi_cmsg_answer(cmsg);
+	if (cmsg->Class == mISDN_MF_CLASS_HANDSET) { // Handset
+		switch(cmsg->Function) {
+			case mISDN_MF_HANDSET_ENABLE:
+				err = ncciL4L3(ncci, PH_CONTROL | REQUEST, HW_POTS_ON, 0, NULL, NULL);
+				if (err)
+					mcp.Info = CapiFacilityNotSupported;
+				break;
+			case mISDN_MF_HANDSET_DISABLE:
+				err = ncciL4L3(ncci, PH_CONTROL | REQUEST, HW_POTS_OFF, 0, NULL, NULL);
+				if (err)
+					mcp.Info = CapiFacilityNotSupported;
+				break;
+			case mISDN_MF_HANDSET_SETMICVOLUME:
+			case mISDN_MF_HANDSET_SETSPKVOLUME:
+				if (!mrp || mrp->len != 2) {
+					mcp.Info = CapiIllMessageParmCoding;
+					break;
+				}
+				op = (cmsg->Function == mISDN_MF_HANDSET_SETSPKVOLUME) ?
+					HW_POTS_SETSPKVOL : HW_POTS_SETMICVOL;
+				err = ncciL4L3(ncci, PH_CONTROL | REQUEST, op, 2, &mrp->vol, NULL);
+				if (err == -ENODEV)
+					mcp.Info = CapiFacilityNotSupported;
+				else if (err)
+					mcp.Info = CapiIllMessageParmCoding;
+				break;
+			/* not handled yet */
+			case mISDN_MF_HANDSET_GETMICVOLUME:
+			case mISDN_MF_HANDSET_GETSPKVOLUME:
+			default:
+				mcp.Info = CapiFacilityNotSupported;
+				break;
+		}
+	} else
+		mcp.Info = CapiIllMessageParmCoding;
+
+	cmsg->ManuData = (_cstruct)&mcp;
+	Send2Application(ncci, cmsg);
+}
+
+static void
+ncci_connect_b3_active_ind(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	int	i;
+
+	mISDN_FsmChangeState(fi, ST_NCCI_N_ACT);
+	for (i = 0; i < CAPI_MAXDATAWINDOW; i++) {
+		ncci->xmit_skb_handles[i].PktId = 0;
+		ncci->recv_skb_handles[i] = 0;
+	}
+	Send2Application(ncci, arg);
+}
+
+static void
+ncci_connect_b3_active_resp(struct FsmInst *fi, int event, void *arg)
+{
+	cmsg_free(arg);
+}
+
+static void
+ncci_n0_dl_establish_ind_conf(struct FsmInst *fi, int event, void *arg)
+{
+	_cmsg   *cmsg;
+	Ncci_t	*ncci = fi->userdata;
+
+	if (!ncci->appl)
+		return;
+	if (!(0xffff0000 & ncci->addr)) {
+		if (select_NCCIaddr(ncci)) {
+			int_error();
+			return;
+		}
+	} else {
+		int_error();
+		return;
+	}
+	CMSG_ALLOC(cmsg);
+	ncciCmsgHeader(ncci, cmsg, CAPI_CONNECT_B3, CAPI_IND);
+	if (mISDN_FsmEvent(&ncci->ncci_m, EV_NC_CONNECT_B3_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+ncci_dl_establish_conf(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	_cmsg	*cmsg;
+
+	if (!ncci->appl)
+		return;
+	CMSG_ALLOC(cmsg);
+	ncciCmsgHeader(ncci, cmsg, CAPI_CONNECT_B3_ACTIVE, CAPI_IND);
+	if (mISDN_FsmEvent(&ncci->ncci_m, EV_NC_CONNECT_B3_ACTIVE_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+ncci_dl_release_ind_conf(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	_cmsg	*cmsg;
+
+	CMSG_ALLOC(cmsg);
+	ncciCmsgHeader(ncci, cmsg, CAPI_DISCONNECT_B3, CAPI_IND);
+	if (mISDN_FsmEvent(&ncci->ncci_m, EV_NC_DISCONNECT_B3_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+ncci_linkdown(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	_cmsg	*cmsg;
+
+	CMSG_ALLOC(cmsg);
+	ncciCmsgHeader(ncci, cmsg, CAPI_DISCONNECT_B3, CAPI_IND);
+	if (mISDN_FsmEvent(&ncci->ncci_m, EV_NC_DISCONNECT_B3_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+ncci_dl_down_ind(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	_cmsg	*cmsg;
+
+	CMSG_ALLOC(cmsg);
+	ncciCmsgHeader(ncci, cmsg, CAPI_DISCONNECT_B3, CAPI_IND);
+	cmsg->Reason_B3 = CapiProtocolErrorLayer1;
+	if (mISDN_FsmEvent(&ncci->ncci_m, EV_NC_DISCONNECT_B3_IND, cmsg))
+		cmsg_free(cmsg);
+}
+
+static void
+ncci_appl_release(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_NCCI_N_0);
+	ncciDestr(fi->userdata);
+}
+
+static void
+ncci_appl_release_disc(struct FsmInst *fi, int event, void *arg)
+{
+	ncciL4L3(fi->userdata, DL_RELEASE | REQUEST, 0, 0, NULL, NULL);
+}
+
+static struct FsmNode fn_ncci_list[] =
+{
+  {ST_NCCI_N_0,		EV_AP_CONNECT_B3_REQ,		ncci_connect_b3_req},
+  {ST_NCCI_N_0,		EV_NC_CONNECT_B3_IND,		ncci_connect_b3_ind},
+  {ST_NCCI_N_0,		EV_DL_ESTABLISH_CONF,		ncci_n0_dl_establish_ind_conf},
+  {ST_NCCI_N_0,		EV_DL_ESTABLISH_IND,		ncci_n0_dl_establish_ind_conf},
+  {ST_NCCI_N_0,		EV_AP_RELEASE,			ncci_appl_release},
+
+  {ST_NCCI_N_0_1,	EV_NC_CONNECT_B3_CONF,		ncci_connect_b3_conf},
+  {ST_NCCI_N_0_1,	EV_AP_MANUFACTURER_REQ,		ncci_manufacturer_req},
+  {ST_NCCI_N_0_1,	EV_AP_RELEASE,			ncci_appl_release},
+
+  {ST_NCCI_N_1,		EV_AP_CONNECT_B3_RESP,		ncci_connect_b3_resp},
+  {ST_NCCI_N_1,		EV_AP_DISCONNECT_B3_REQ,	ncci_disconnect_b3_req},
+  {ST_NCCI_N_1,		EV_NC_DISCONNECT_B3_IND,	ncci_disconnect_b3_ind},
+  {ST_NCCI_N_1,		EV_AP_MANUFACTURER_REQ,		ncci_manufacturer_req},
+  {ST_NCCI_N_1,		EV_AP_RELEASE,			ncci_appl_release_disc},
+  {ST_NCCI_N_1,		EV_NC_LINKDOWN,			ncci_linkdown},
+
+  {ST_NCCI_N_2,		EV_NC_CONNECT_B3_ACTIVE_IND,	ncci_connect_b3_active_ind},
+  {ST_NCCI_N_2,		EV_AP_DISCONNECT_B3_REQ,	ncci_disconnect_b3_req},
+  {ST_NCCI_N_2,		EV_NC_DISCONNECT_B3_IND,	ncci_disconnect_b3_ind},
+  {ST_NCCI_N_2,		EV_DL_ESTABLISH_CONF,		ncci_dl_establish_conf},
+  {ST_NCCI_N_2,		EV_DL_RELEASE_IND,		ncci_dl_release_ind_conf},
+  {ST_NCCI_N_2,		EV_AP_MANUFACTURER_REQ,		ncci_manufacturer_req},
+  {ST_NCCI_N_2,		EV_AP_RELEASE,			ncci_appl_release_disc},
+  {ST_NCCI_N_2,		EV_NC_LINKDOWN,			ncci_linkdown},
+     
+#if 0
+  {ST_NCCI_N_3,		EV_NC_RESET_B3_IND,		ncci_reset_b3_ind},
+  {ST_NCCI_N_3,		EV_DL_DOWN_IND,			ncci_dl_down_ind},
+  {ST_NCCI_N_3,		EV_AP_DISCONNECT_B3_REQ,	ncci_disconnect_b3_req},
+  {ST_NCCI_N_3,		EV_NC_DISCONNECT_B3_IND,	ncci_disconnect_b3_ind},
+  {ST_NCCI_N_3,		EV_AP_RELEASE,			ncci_appl_release_disc},
+  {ST_NCCI_N_3,		EV_NC_LINKDOWN,			ncci_linkdown},
+#endif
+
+  {ST_NCCI_N_ACT,	EV_AP_CONNECT_B3_ACTIVE_RESP,	ncci_connect_b3_active_resp},
+  {ST_NCCI_N_ACT,	EV_AP_DISCONNECT_B3_REQ,	ncci_disconnect_b3_req},
+  {ST_NCCI_N_ACT,	EV_NC_DISCONNECT_B3_IND,	ncci_disconnect_b3_ind},
+  {ST_NCCI_N_ACT,	EV_DL_RELEASE_IND,		ncci_dl_release_ind_conf},
+  {ST_NCCI_N_ACT,	EV_DL_RELEASE_CONF,		ncci_dl_release_ind_conf},
+  {ST_NCCI_N_ACT,	EV_DL_DOWN_IND,			ncci_dl_down_ind},
+  {ST_NCCI_N_ACT,	EV_AP_FACILITY_REQ,		ncci_facility_req},
+  {ST_NCCI_N_ACT,	EV_AP_MANUFACTURER_REQ,		ncci_manufacturer_req},
+  {ST_NCCI_N_ACT,	EV_AP_RELEASE,			ncci_appl_release_disc},
+  {ST_NCCI_N_ACT,	EV_NC_LINKDOWN,			ncci_linkdown},
+#if 0
+  {ST_NCCI_N_ACT,	EV_AP_RESET_B3_REQ,		ncci_reset_b3_req},
+  {ST_NCCI_N_ACT,	EV_NC_RESET_B3_IND,		ncci_reset_b3_ind},
+  {ST_NCCI_N_ACT,	EV_NC_CONNECT_B3_T90_ACTIVE_IND,ncci_connect_b3_t90_active_ind},
+#endif
+
+  {ST_NCCI_N_4,		EV_NC_DISCONNECT_B3_CONF,	ncci_disconnect_b3_conf},
+  {ST_NCCI_N_4,		EV_NC_DISCONNECT_B3_IND,	ncci_disconnect_b3_ind},
+  {ST_NCCI_N_4,		EV_DL_RELEASE_CONF,		ncci_dl_release_ind_conf},
+  {ST_NCCI_N_4,		EV_DL_DOWN_IND,			ncci_dl_down_ind},
+  {ST_NCCI_N_4,		EV_AP_MANUFACTURER_REQ,		ncci_manufacturer_req},
+  {ST_NCCI_N_4,		EV_NC_LINKDOWN,			ncci_linkdown},
+
+  {ST_NCCI_N_5,		EV_AP_DISCONNECT_B3_RESP,	ncci_disconnect_b3_resp},
+  {ST_NCCI_N_5,		EV_AP_RELEASE,			ncci_appl_release},
+};
+const int FN_NCCI_COUNT = sizeof(fn_ncci_list)/sizeof(struct FsmNode);
+
+static void
+ncciD_connect_b3_req(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_NCCI_N_0_1);
+	if (SKB_l4l3(fi->userdata, arg))
+		dev_kfree_skb(arg);
+}
+
+static void
+ncciD_connect_b3_conf(struct FsmInst *fi, int event, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	__u16		info = CAPIMSG_U16(skb->data, 12);
+
+	if (info == 0)
+		mISDN_FsmChangeState(fi, ST_NCCI_N_2);
+	else
+		mISDN_FsmChangeState(fi, ST_NCCI_N_0);
+	SKB2Application(fi->userdata, skb);
+	if (info != 0)
+		ncciDestr(fi->userdata);
+}
+
+static void
+ncciD_connect_b3_ind(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_NCCI_N_1);
+	SKB2Application(fi->userdata, arg);
+}
+
+static void
+ncciD_connect_b3_resp(struct FsmInst *fi, int event, void *arg)
+{
+	struct sk_buff	*skb = arg;
+	__u16		rej = CAPIMSG_U16(skb->data, 4);
+
+	if (rej)
+		mISDN_FsmChangeState(fi, ST_NCCI_N_4);
+	else
+		mISDN_FsmChangeState(fi, ST_NCCI_N_2);
+	if (SKB_l4l3(fi->userdata, arg))
+		dev_kfree_skb(arg);
+}
+
+static void
+ncciD_connect_b3_active_ind(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_NCCI_N_ACT);
+	SKB2Application(fi->userdata, arg);
+}
+
+static void
+ncciD_connect_b3_active_resp(struct FsmInst *fi, int event, void *arg)
+{
+	if (SKB_l4l3(fi->userdata, arg))
+		dev_kfree_skb(arg);
+}
+
+static void
+ncciD_reset_b3_ind(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_NCCI_N_ACT);
+	SKB2Application(fi->userdata, arg);
+}
+
+static void
+ncciD_reset_b3_resp(struct FsmInst *fi, int event, void *arg)
+{
+	if (SKB_l4l3(fi->userdata, arg))
+		dev_kfree_skb(arg);
+}
+
+static void
+ncciD_reset_b3_conf(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_NCCI_N_3);
+	SKB2Application(fi->userdata, arg);
+}
+
+static void
+ncciD_reset_b3_req(struct FsmInst *fi, int event, void *arg)
+{
+	if (SKB_l4l3(fi->userdata, arg))
+		dev_kfree_skb(arg);
+}
+
+static void
+ncciD_disconnect_b3_req(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+
+	ncci->savedstate = fi->state;
+	mISDN_FsmChangeState(fi, ST_NCCI_N_4);
+	if (SKB_l4l3(fi->userdata, arg))
+		dev_kfree_skb(arg);
+}
+
+static void
+ncciD_disconnect_b3_conf(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	struct sk_buff	*skb = arg;
+	__u16		info = CAPIMSG_U16(skb->data, 12);
+
+	if (ncci->ncci_m.debug)
+		log_skbdata(skb);
+	if (test_bit(NCCI_STATE_APPLRELEASED, &ncci->state))
+		return;
+	if (info != 0)
+		mISDN_FsmChangeState(fi, ncci->savedstate);
+	SKB2Application(ncci, skb);
+}
+
+static void
+ncciD_disconnect_b3_ind(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	mISDN_FsmChangeState(fi, ST_NCCI_N_5);
+	if (test_bit(NCCI_STATE_APPLRELEASED, &ncci->state)) {
+		skb_pull(skb, CAPIMSG_BASELEN);
+		skb_trim(skb, 0);
+		skb_put(skb, 4);
+		mISDN_queuedown_newhead(&ncci->link->inst, 0, CAPI_DISCONNECT_B3_RESP, 0, skb);
+		ncciDestr(ncci);
+	} else
+		SKB2Application(ncci, arg);
+}
+
+static void
+ncciD_disconnect_b3_resp(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_NCCI_N_0);
+	if (SKB_l4l3(fi->userdata, arg))
+		dev_kfree_skb(arg);
+	ncciDestr(fi->userdata);
+}
+
+static void
+ncciD_linkdown(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	_cmsg	*cmsg;
+
+	CMSG_ALLOC(cmsg);
+	ncciCmsgHeader(ncci, cmsg, CAPI_DISCONNECT_B3, CAPI_IND);
+	mISDN_FsmChangeState(fi, ST_NCCI_N_5);
+	Send2Application(ncci, cmsg);
+}
+
+static void
+ncciD_appl_release_disc(struct FsmInst *fi, int event, void *arg)
+{
+	Ncci_t	*ncci = fi->userdata;
+	u_char	parm[5];
+
+	capimsg_setu32(parm, 0, ncci->addr);
+	parm[4] = 0;
+	mISDN_FsmChangeState(fi, ST_NCCI_N_4);
+	mISDN_queue_data(&ncci->link->inst, FLG_MSG_DOWN, CAPI_DISCONNECT_B3_REQ, 0, 5, parm, 0); 
+}
+
+static struct FsmNode fn_ncciD_list[] =
+{
+  {ST_NCCI_N_0,		EV_AP_CONNECT_B3_REQ,		ncciD_connect_b3_req},
+  {ST_NCCI_N_0,		EV_NC_CONNECT_B3_IND,		ncciD_connect_b3_ind},
+  {ST_NCCI_N_0,		EV_AP_RELEASE,			ncci_appl_release},
+
+  {ST_NCCI_N_0_1,	EV_NC_CONNECT_B3_CONF,		ncciD_connect_b3_conf},
+  {ST_NCCI_N_0_1,	EV_AP_RELEASE,			ncci_appl_release},
+
+  {ST_NCCI_N_1,		EV_AP_CONNECT_B3_RESP,		ncciD_connect_b3_resp},
+  {ST_NCCI_N_1,		EV_AP_DISCONNECT_B3_REQ,	ncciD_disconnect_b3_req},
+  {ST_NCCI_N_1,		EV_NC_DISCONNECT_B3_IND,	ncciD_disconnect_b3_ind},
+  {ST_NCCI_N_1,		EV_AP_RELEASE,			ncciD_appl_release_disc},
+  {ST_NCCI_N_1,		EV_NC_LINKDOWN,			ncciD_linkdown},
+
+  {ST_NCCI_N_2,		EV_NC_CONNECT_B3_ACTIVE_IND,	ncciD_connect_b3_active_ind},
+  {ST_NCCI_N_2,		EV_AP_DISCONNECT_B3_REQ,	ncciD_disconnect_b3_req},
+  {ST_NCCI_N_2,		EV_NC_DISCONNECT_B3_IND,	ncciD_disconnect_b3_ind},
+  {ST_NCCI_N_2,		EV_AP_RELEASE,			ncciD_appl_release_disc},
+  {ST_NCCI_N_2,		EV_NC_LINKDOWN,			ncciD_linkdown},
+     
+  {ST_NCCI_N_3,		EV_NC_RESET_B3_IND,		ncciD_reset_b3_ind},
+  {ST_NCCI_N_3,		EV_AP_DISCONNECT_B3_REQ,	ncciD_disconnect_b3_req},
+  {ST_NCCI_N_3,		EV_NC_DISCONNECT_B3_IND,	ncciD_disconnect_b3_ind},
+  {ST_NCCI_N_3,		EV_AP_RELEASE,			ncciD_appl_release_disc},
+  {ST_NCCI_N_3,		EV_NC_LINKDOWN,			ncciD_linkdown},
+
+  {ST_NCCI_N_ACT,	EV_AP_CONNECT_B3_ACTIVE_RESP,	ncciD_connect_b3_active_resp},
+  {ST_NCCI_N_ACT,	EV_AP_DISCONNECT_B3_REQ,	ncciD_disconnect_b3_req},
+  {ST_NCCI_N_ACT,	EV_NC_DISCONNECT_B3_IND,	ncciD_disconnect_b3_ind},
+  {ST_NCCI_N_ACT,	EV_AP_RELEASE,			ncciD_appl_release_disc},
+  {ST_NCCI_N_ACT,	EV_NC_LINKDOWN,			ncciD_linkdown},
+  {ST_NCCI_N_ACT,	EV_AP_RESET_B3_REQ,		ncciD_reset_b3_req},
+  {ST_NCCI_N_ACT,	EV_NC_RESET_B3_IND,		ncciD_reset_b3_ind},
+  {ST_NCCI_N_ACT,	EV_NC_RESET_B3_CONF,		ncciD_reset_b3_conf},
+  {ST_NCCI_N_ACT,	EV_AP_RESET_B3_RESP,		ncciD_reset_b3_resp},
+//{ST_NCCI_N_ACT,	EV_NC_CONNECT_B3_T90_ACTIVE_IND,ncciD_connect_b3_t90_active_ind},
+
+  {ST_NCCI_N_4,		EV_NC_DISCONNECT_B3_CONF,	ncciD_disconnect_b3_conf},
+  {ST_NCCI_N_4,		EV_NC_DISCONNECT_B3_IND,	ncciD_disconnect_b3_ind},
+  {ST_NCCI_N_4,		EV_NC_LINKDOWN,			ncciD_linkdown},
+
+  {ST_NCCI_N_5,		EV_AP_DISCONNECT_B3_RESP,	ncciD_disconnect_b3_resp},
+  {ST_NCCI_N_5,		EV_AP_RELEASE,			ncci_appl_release},
+};
+const int FN_NCCID_COUNT = sizeof(fn_ncciD_list)/sizeof(struct FsmNode);
+
+Ncci_t *
+ncciConstr(AppPlci_t *aplci)
+{
+	Ncci_t	*ncci = ncci_alloc();
+
+	if (!ncci)
+		return(NULL);
+
+	memset(ncci, 0, sizeof(Ncci_t));
+	ncci->ncci_m.state      = ST_NCCI_N_0;
+	ncci->ncci_m.debug      = aplci->plci->contr->debug & CAPI_DBG_NCCI_STATE;
+	ncci->ncci_m.userdata   = ncci;
+	ncci->ncci_m.printdebug = ncci_debug;
+	/* unused NCCI */
+	ncci->addr = aplci->addr;
+	ncci->AppPlci = aplci;
+	ncci->link = aplci->link;
+	ncci->contr = aplci->contr;
+	ncci->appl = aplci->appl;
+	ncci->window = aplci->appl->reg_params.datablkcnt;
+	if (aplci->Bprotocol.B2 != 0) /* X.75 has own flowctrl */
+		test_and_set_bit(NCCI_STATE_FCTRL, &ncci->state);
+	if (aplci->Bprotocol.B3 == 0) {
+		test_and_set_bit(NCCI_STATE_L3TRANS, &ncci->state);
+		ncci->ncci_m.fsm = &ncci_fsm;
+	} else
+		ncci->ncci_m.fsm = &ncciD_fsm;
+	skb_queue_head_init(&ncci->squeue);
+	if (ncci->window > CAPI_MAXDATAWINDOW) {
+		ncci->window = CAPI_MAXDATAWINDOW;
+	}
+	INIT_LIST_HEAD(&ncci->head);
+	list_add(&ncci->head, &aplci->Nccis);
+	if (ncci->ncci_m.debug)
+		printk(KERN_DEBUG "%s: ncci(%p) NCCI(%x) debug (%x/%x)\n",
+			__FUNCTION__, ncci, ncci->addr, aplci->plci->contr->debug, CAPI_DBG_NCCI_STATE); 
+	return(ncci);
+}
+
+void
+ncciDestr(Ncci_t *ncci)
+{
+	int	i;
+
+	capidebug(CAPI_DBG_NCCI, "ncciDestr NCCI %x", ncci->addr);
+
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	if (!test_bit(NCCI_STATE_APPLRELEASED, &ncci->state))
+		ncci->contr->ctrl->free_ncci(ncci->contr->ctrl, ncci->appl->ApplId, ncci->addr);
+#endif
+	/* cleanup data queues */
+	discard_queue(&ncci->squeue);
+	for (i = 0; i < CAPI_MAXDATAWINDOW; i++) {
+		if (ncci->xmit_skb_handles[i].PktId)
+			ncci->xmit_skb_handles[i].PktId = 0;
+	}
+	AppPlciDelNCCI(ncci);
+	ncci_free(ncci);
+}
+
+void
+ncciApplRelease(Ncci_t *ncci)
+{
+	test_and_set_bit(NCCI_STATE_APPLRELEASED, &ncci->state);
+	mISDN_FsmEvent(&ncci->ncci_m, EV_AP_RELEASE, NULL);
+}
+
+void
+ncciDelAppPlci(Ncci_t *ncci)
+{
+	printk(KERN_DEBUG "%s: ncci(%p) NCCI(%x)\n",
+		__FUNCTION__, ncci, ncci->addr); 
+	ncci->AppPlci = NULL;
+	/* maybe we should release the NCCI here */
+}
+
+void
+ncciReleaseLink(Ncci_t *ncci)
+{
+	/* this is normal shutdown on speech and other transparent protocols */
+	mISDN_FsmEvent(&ncci->ncci_m, EV_NC_LINKDOWN, NULL);
+}
+
+void
+ncciDataInd(Ncci_t *ncci, int pr, struct sk_buff *skb)
+{
+	struct sk_buff *nskb;
+	int i;
+
+	for (i = 0; i < ncci->window; i++) {
+		if (ncci->recv_skb_handles[i] == 0)
+			break;
+	}
+
+	if (i == ncci->window) {
+		// FIXME: trigger flow control if supported by L2 protocol
+		printk(KERN_DEBUG "%s: frame %d dropped\n", __FUNCTION__, skb->len);
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	if (skb_headroom(skb) < CAPI_B3_DATA_IND_HEADER_SIZE) {
+		capidebug(CAPI_DBG_NCCI_L3, "%s: only %d bytes headroom, need %d",
+			__FUNCTION__, skb_headroom(skb), CAPI_B3_DATA_IND_HEADER_SIZE);
+		nskb = skb_realloc_headroom(skb, CAPI_B3_DATA_IND_HEADER_SIZE);
+		dev_kfree_skb(skb);
+		if (!nskb) {
+			int_error();
+			return;
+		}
+      	} else { 
+		nskb = skb;
+	}
+	ncci->recv_skb_handles[i] = nskb;
+
+	skb_push(nskb, CAPI_B3_DATA_IND_HEADER_SIZE);
+	CAPIMSG_SETLEN(nskb->data, CAPI_B3_DATA_IND_HEADER_SIZE);
+	CAPIMSG_SETAPPID(nskb->data, ncci->appl->ApplId);
+	CAPIMSG_SETCOMMAND(nskb->data, CAPI_DATA_B3);
+	CAPIMSG_SETSUBCOMMAND(nskb->data, CAPI_IND);
+	CAPIMSG_SETMSGID(nskb->data, ncci->appl->MsgId++);
+	CAPIMSG_SETCONTROL(nskb->data, ncci->addr);
+	if (sizeof(nskb) == 4) {
+		capimsg_setu32(nskb->data, 12, (__u32)(((u_long)nskb->data + CAPI_B3_DATA_IND_HEADER_SIZE) & 0xffffffff));
+		*((__u64*)(nskb->data+22)) = cpu_to_le64(0);
+	} else {
+		capimsg_setu32(nskb->data, 12, 0);
+		*((__u64*)(nskb->data+22)) = cpu_to_le64((__u64)nskb->data + CAPI_B3_DATA_IND_HEADER_SIZE);
+	}
+	CAPIMSG_SETDATALEN(nskb->data, nskb->len - CAPI_B3_DATA_IND_HEADER_SIZE);
+	capimsg_setu16(nskb->data, 18, i);
+	// FIXME FLAGS
+	capimsg_setu16(nskb->data, 20, 0);
+#ifdef OLDCAPI_DRIVER_INTERFACE
+	ncci->contr->ctrl->handle_capimsg(ncci->contr->ctrl, ncci->appl->ApplId, nskb);
+#else
+	capi_ctr_handle_message(ncci->contr->ctrl, ncci->appl->ApplId, nskb);
+#endif
+}
+
+__u16
+ncciDataReq(Ncci_t *ncci, struct sk_buff *skb)
+{
+	int	i, err;
+	__u16	len, capierr = 0;
+	_cmsg	*cmsg;
+
+	len = CAPIMSG_LEN(skb->data);
+	if (len != 22 && len != 30) {
+		capierr = CapiIllMessageParmCoding;
+		int_error();
+		goto fail;
+	}
+	for (i = 0; i < CAPI_MAXDATAWINDOW; i++) {
+		/* try reserving a slot atomically (use an invalid Id) */
+		if (cmpxchg(&ncci->xmit_skb_handles[i].PktId, 0, MISDN_ID_DUMMY) == 0)
+			break;
+	}
+	if (i == CAPI_MAXDATAWINDOW) {
+		return(CAPI_SENDQUEUEFULL);
+	}
+	mISDN_HEAD_DINFO(skb) = ControllerNextId(ncci->contr);
+	ncci->xmit_skb_handles[i].PktId = mISDN_HEAD_DINFO(skb);
+	ncci->xmit_skb_handles[i].DataHandle = CAPIMSG_REQ_DATAHANDLE(skb->data);
+	ncci->xmit_skb_handles[i].MsgId = CAPIMSG_MSGID(skb->data);
+
+	/* the data begins behind the header, we don't use Data32/Data64 here */
+	skb_pull(skb, len);
+
+	if (test_bit(NCCI_STATE_FCTRL, &ncci->state)) {
+		if (test_and_set_bit(NCCI_STATE_BUSY, &ncci->state)) {
+			skb_queue_tail(&ncci->squeue, skb);
+			return(CAPI_NOERROR);
+		}
+		if (skb_queue_len(&ncci->squeue)) {
+			skb_queue_tail(&ncci->squeue, skb);
+			skb = skb_dequeue(&ncci->squeue);
+			i = -1;
+		}
+	}
+	err = ncciL4L3(ncci, DL_DATA | REQUEST, mISDN_HEAD_DINFO(skb), 0, NULL, skb);
+	if (!err)
+		return(CAPI_NOERROR);
+
+	int_error();
+	skb_push(skb, len);
+	capierr = CAPI_MSGBUSY;
+	if (i == -1) {
+		for (i = 0; i < CAPI_MAXDATAWINDOW; i++) {
+			if (ncci->xmit_skb_handles[i].PktId == mISDN_HEAD_DINFO(skb))
+				break;
+		}
+		if (i == CAPI_MAXDATAWINDOW)
+			int_error();
+		else
+			ncci->xmit_skb_handles[i].PktId = 0;
+	} else {
+		ncci->xmit_skb_handles[i].PktId = 0;
+		return(capierr);
+	}
+fail:
+	cmsg = cmsg_alloc();
+	if (!cmsg) {
+		int_error();
+		if (capierr != CAPI_MSGBUSY)
+			return(CAPI_MSGOSRESOURCEERR);
+		/* we can not do error handling on a skb from the queue here */	
+		dev_kfree_skb(skb);
+		return(CAPI_NOERROR);
+	}
+	capi_cmsg_header(cmsg, ncci->AppPlci->appl->ApplId, CAPI_DATA_B3, CAPI_CONF, 
+		CAPIMSG_MSGID(skb->data), ncci->addr);
+	/* illegal len (too short) ??? */
+	cmsg->DataHandle = CAPIMSG_REQ_DATAHANDLE(skb->data);
+	cmsg->Info = capierr;
+	Send2Application(ncci, cmsg);
+	dev_kfree_skb(skb);
+	return(CAPI_NOERROR);
+}
+
+int
+ncciDataConf(Ncci_t *ncci, int pr, struct sk_buff *skb)
+{
+	int	i;
+	_cmsg	*cmsg;
+
+	for (i = 0; i < CAPI_MAXDATAWINDOW; i++) {
+		if (ncci->xmit_skb_handles[i].PktId == mISDN_HEAD_DINFO(skb))
+			break;
+	}
+	if (i == CAPI_MAXDATAWINDOW) {
+		int_error();
+		printk(KERN_DEBUG "%s: dinfo(%x)\n", __FUNCTION__, mISDN_HEAD_DINFO(skb));
+		for (i = 0; i < CAPI_MAXDATAWINDOW; i++)
+			printk(KERN_DEBUG "%s: PktId[%d] %x\n", __FUNCTION__, i, ncci->xmit_skb_handles[i].PktId);
+		return(-EINVAL);
+	}
+	capidebug(CAPI_DBG_NCCI_L3, "%s: entry %d/%d handle (%x)",
+		__FUNCTION__, i, CAPI_MAXDATAWINDOW, ncci->xmit_skb_handles[i].DataHandle);
+
+	cmsg = cmsg_alloc();
+	if (!cmsg) {
+		int_error();
+		ncci->xmit_skb_handles[i].PktId = 0;
+		return(-ENOMEM);
+	}
+	dev_kfree_skb(skb);
+	capi_cmsg_header(cmsg, ncci->AppPlci->appl->ApplId, CAPI_DATA_B3, CAPI_CONF, 
+			 ncci->xmit_skb_handles[i].MsgId, ncci->addr);
+	cmsg->DataHandle = ncci->xmit_skb_handles[i].DataHandle;
+	cmsg->Info = 0;
+	ncci->xmit_skb_handles[i].PktId = 0;
+	Send2Application(ncci, cmsg);
+	if (test_bit(NCCI_STATE_FCTRL, &ncci->state)) {
+		if (skb_queue_len(&ncci->squeue)) {
+			skb = skb_dequeue(&ncci->squeue);
+			if (ncciL4L3(ncci, DL_DATA | REQUEST, mISDN_HEAD_DINFO(skb),
+				0, NULL, skb)) {
+				int_error();
+				dev_kfree_skb(skb);
+			}
+		} else {
+			test_and_clear_bit(NCCI_STATE_BUSY, &ncci->state);
+		}
+	}
+	return(0);
+}	
+	
+void
+ncciDataResp(Ncci_t *ncci, struct sk_buff *skb)
+{
+	// FIXME: incoming flow control doesn't work yet
+
+	int i;
+
+	i = CAPIMSG_RESP_DATAHANDLE(skb->data);
+	if (i < 0 || i > ncci->window) {
+		int_error();
+		return;
+	}
+	if (!ncci->recv_skb_handles[i]) {
+		int_error();
+		return;
+	}
+	ncci->recv_skb_handles[i] = 0;
+
+	dev_kfree_skb(skb);
+}
+
+int
+ncci_l4l3_direct(Ncci_t *ncci, struct sk_buff *skb) {
+	mISDN_head_t	*hh;
+	int		ret;
+
+	hh = mISDN_HEAD_P(skb);
+	if (ncci->ncci_m.debug)
+		log_skbdata(skb);
+	hh->prim = CAPIMSG_CMD(skb->data);
+	hh->dinfo = CAPIMSG_MSGID(skb->data);
+	skb_pull(skb, CAPIMSG_BASELEN);
+	if (ncci->ncci_m.debug)
+		log_skbdata(skb);
+	switch (hh->prim) {
+		case CAPI_DATA_B3_REQ:
+		case CAPI_DATA_B3_RESP:
+		case CAPI_FACILITY_REQ:
+		case CAPI_FACILITY_RESP:
+		case CAPI_MANUFACTURER_REQ:
+		case CAPI_MANUFACTURER_RESP:
+			return(SKB_l4l3(ncci, skb));
+		case CAPI_CONNECT_B3_REQ:
+			ret = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_CONNECT_B3_REQ, skb);
+			break;
+		case CAPI_CONNECT_B3_RESP:
+			ret = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_CONNECT_B3_RESP, skb);
+			break;
+		case CAPI_CONNECT_B3_ACTIVE_RESP:
+			ret = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_CONNECT_B3_ACTIVE_RESP, skb);
+			break;
+		case CAPI_DISCONNECT_B3_REQ:
+			ret = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_DISCONNECT_B3_REQ, skb);
+			break;
+		case CAPI_DISCONNECT_B3_RESP:
+			ret = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_DISCONNECT_B3_RESP, skb);
+			break;
+		case CAPI_RESET_B3_REQ:
+			ret = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_RESET_B3_REQ, skb);
+			break;
+		case CAPI_RESET_B3_RESP:
+			ret = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_RESET_B3_RESP, skb);
+			break;
+		default:
+			int_error();
+			ret = -1;
+	}
+	if (ret) {
+		int_error();
+		dev_kfree_skb(skb);
+	}
+	return(0);
+}
+
+void
+ncciGetCmsg(Ncci_t *ncci, _cmsg *cmsg)
+{
+	int	retval = 0;
+
+	if (!test_bit(NCCI_STATE_L3TRANS, &ncci->state)) {
+		int_error();
+		cmsg_free(cmsg);
+		return;
+	}
+	switch (CMSGCMD(cmsg)) {
+		case CAPI_CONNECT_B3_REQ:
+			retval = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_CONNECT_B3_REQ, cmsg);
+			break;
+		case CAPI_CONNECT_B3_RESP:
+			retval = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_CONNECT_B3_RESP, cmsg);
+			break;
+		case CAPI_CONNECT_B3_ACTIVE_RESP:
+			retval = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_CONNECT_B3_ACTIVE_RESP, cmsg);
+			break;
+		case CAPI_DISCONNECT_B3_REQ:
+			retval = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_DISCONNECT_B3_REQ, cmsg);
+			break;
+		case CAPI_DISCONNECT_B3_RESP:
+			retval = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_DISCONNECT_B3_RESP, cmsg);
+			break;
+		case CAPI_FACILITY_REQ:
+			retval = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_FACILITY_REQ, cmsg);
+			break;
+		case CAPI_MANUFACTURER_REQ:
+			retval = mISDN_FsmEvent(&ncci->ncci_m, EV_AP_MANUFACTURER_REQ, cmsg);
+			break;
+		default:
+			int_error();
+			retval = -1;
+	}
+	if (retval) { 
+		if (cmsg->Command == CAPI_REQ) {
+			capi_cmsg_answer(cmsg);
+			cmsg->Info = CapiMessageNotSupportedInCurrentState;
+			Send2Application(ncci, cmsg);
+		} else
+			cmsg_free(cmsg);
+	}
+}
+
+void
+ncciSendMessage(Ncci_t *ncci, struct sk_buff *skb)
+{
+	int	ret;
+	_cmsg	*cmsg;
+
+	if (!test_bit(NCCI_STATE_L3TRANS, &ncci->state)) {
+		ret = ncci_l4l3_direct(ncci, skb);
+		switch(ret) {
+			case 0:
+				break;
+			case -EINVAL:
+			case -ENXIO:
+				int_error();
+				break;	/* (CAPI_MSGBUSY) */
+			case -EXFULL:
+				int_error();
+				break;	/* (CAPI_SENDQUEUEFULL) */
+			default:
+				int_errtxt("ncci_l4l3_direct return(%d)", ret);
+				dev_kfree_skb(skb);
+				break;
+		}
+		return;
+	}
+	// we're not using the cmsg for DATA_B3 for performance reasons
+	switch (CAPIMSG_CMD(skb->data)) {
+		case CAPI_DATA_B3_REQ:
+			if (ncci->ncci_m.state == ST_NCCI_N_ACT) {
+				ret = ncciDataReq(ncci, skb);
+				if (ret)
+					int_error();
+			} else {
+				AnswerMessage2Application(ncci->appl, skb, 
+					CapiMessageNotSupportedInCurrentState);
+				dev_kfree_skb(skb);
+			}
+			return;
+		case CAPI_DATA_B3_RESP:
+			ncciDataResp(ncci, skb);
+			return;
+	}
+	cmsg = cmsg_alloc();
+	if (!cmsg) {
+		int_error();
+		return;
+	}
+	capi_message2cmsg(cmsg, skb->data);
+	ncciGetCmsg(ncci, cmsg);
+	dev_kfree_skb(skb);
+	return;
+}
+
+int
+ncci_l3l4_direct(Ncci_t *ncci, mISDN_head_t *hh, struct sk_buff *skb)
+{
+	__u16		msgnr;
+	int		event;
+
+	capidebug(CAPI_DBG_NCCI_L3, "%s: NCCI %x prim(%x) dinfo (%x) skb(%p) s(%x)",
+		__FUNCTION__, ncci->addr, hh->prim, hh->dinfo, skb, ncci->state);
+	if (ncci->ncci_m.debug)
+		log_skbdata(skb);
+	switch (hh->prim & 0xFF) {
+		case CAPI_IND:
+			msgnr = ncci->appl->MsgId++;
+			break;
+		case CAPI_CONF:
+			msgnr = hh->dinfo & 0xffff;
+			break;
+		default:
+			int_error();
+			return(-EINVAL);
+	}
+	if (skb_headroom(skb) < CAPIMSG_BASELEN) {
+		capidebug(CAPI_DBG_NCCI_L3, "%s: only %d bytes headroom, need %d",
+			__FUNCTION__, skb_headroom(skb), CAPIMSG_BASELEN);
+		int_error();
+		return(-ENOSPC);
+	}
+	skb_push(skb, CAPIMSG_BASELEN);
+	CAPIMSG_SETLEN(skb->data, (hh->prim == CAPI_DATA_B3_IND) ?
+		CAPI_B3_DATA_IND_HEADER_SIZE : skb->len);
+	CAPIMSG_SETAPPID(skb->data, ncci->appl->ApplId);
+	CAPIMSG_SETCOMMAND(skb->data, (hh->prim>>8) & 0xff);
+	CAPIMSG_SETSUBCOMMAND(skb->data, hh->prim & 0xff); 
+	CAPIMSG_SETMSGID(skb->data, msgnr);
+	switch (hh->prim) {
+		case CAPI_DATA_B3_IND:
+		case CAPI_DATA_B3_CONF:
+		case CAPI_FACILITY_IND:
+		case CAPI_FACILITY_CONF:
+		case CAPI_MANUFACTURER_IND:
+		case CAPI_MANUFACTURER_CONF:
+#ifdef OLDCAPI_DRIVER_INTERFACE
+			ncci->contr->ctrl->handle_capimsg(ncci->contr->ctrl, ncci->appl->ApplId, skb);
+#else
+			capi_ctr_handle_message(ncci->contr->ctrl, ncci->appl->ApplId, skb);
+#endif
+			return(0);
+		case CAPI_CONNECT_B3_IND:
+			event = EV_NC_CONNECT_B3_IND;
+			break;
+		case CAPI_CONNECT_B3_ACTIVE_IND:
+			event = EV_NC_CONNECT_B3_ACTIVE_IND;
+			break;
+		case CAPI_DISCONNECT_B3_IND:
+			event = EV_NC_DISCONNECT_B3_IND;
+			break;
+		case CAPI_RESET_B3_IND:
+			event = EV_NC_RESET_B3_IND;
+			break;
+		case CAPI_CONNECT_B3_CONF:
+			event = EV_NC_CONNECT_B3_CONF;
+			break;
+		case CAPI_DISCONNECT_B3_CONF:
+			event = EV_NC_DISCONNECT_B3_CONF;
+			break;
+		case CAPI_RESET_B3_CONF:
+			event = EV_NC_RESET_B3_CONF;
+			break;
+		default:
+			int_error();
+			return(-EINVAL);
+	}
+	if (mISDN_FsmEvent(&ncci->ncci_m, event, skb))
+		dev_kfree_skb(skb);
+	return(0);
+}
+
+int
+ncci_l3l4(Ncci_t *ncci, mISDN_head_t *hh, struct sk_buff *skb)
+{
+	capidebug(CAPI_DBG_NCCI_L3, "%s: NCCI %x prim(%x) dinfo (%x) skb(%p) s(%x)",
+		__FUNCTION__, ncci->addr, hh->prim, hh->dinfo, skb, ncci->state);
+	switch (hh->prim) {
+		// we're not using the Fsm for DL_DATA for performance reasons
+		case DL_DATA | INDICATION: 
+			if (ncci->ncci_m.state == ST_NCCI_N_ACT) {
+				ncciDataInd(ncci, hh->prim, skb);
+				return(0);
+			} 
+			break;
+		case DL_DATA | CONFIRM:
+			if (ncci->ncci_m.state == ST_NCCI_N_ACT) {
+				return(ncciDataConf(ncci, hh->prim, skb));
+			}
+			break;
+		case DL_ESTABLISH | INDICATION:
+			mISDN_FsmEvent(&ncci->ncci_m, EV_DL_ESTABLISH_IND, skb);
+			break;
+		case DL_ESTABLISH | CONFIRM:
+			mISDN_FsmEvent(&ncci->ncci_m, EV_DL_ESTABLISH_CONF, skb);
+			break;
+		case DL_RELEASE | INDICATION:
+			mISDN_FsmEvent(&ncci->ncci_m, EV_DL_RELEASE_IND, skb);
+			break;
+		case DL_RELEASE | CONFIRM:
+			mISDN_FsmEvent(&ncci->ncci_m, EV_DL_RELEASE_CONF, skb);
+			break;
+		case PH_CONTROL | INDICATION: /* e.g touch tones */
+			/* handled by AppPlci */
+			AppPlci_l3l4(ncci->AppPlci, hh->prim, skb->data);
+			break;
+		default:
+			capidebug(CAPI_DBG_WARN, "%s: unknown prim(%x) dinfo(%x) len(%d) skb(%p)",
+				__FUNCTION__, hh->prim, hh->dinfo, skb->len, skb);
+			int_error();
+			return(-EINVAL);
+	}
+	dev_kfree_skb(skb);
+	return(0);
+}
+
+static int
+ncciL4L3(Ncci_t *ncci, u_int prim, int dtyp, int len, void *arg, struct sk_buff *skb)
+{
+	capidebug(CAPI_DBG_NCCI_L3, "%s: NCCI %x prim(%x) dtyp(%x) len(%d) skb(%p)",
+		__FUNCTION__, ncci->addr, prim, dtyp, len, skb);
+	if (skb)
+		return(mISDN_queuedown_newhead(&ncci->link->inst, 0, prim, dtyp, skb));
+	else
+		return(mISDN_queue_data(&ncci->link->inst, FLG_MSG_DOWN, prim, dtyp, len, arg, 8));
+}
+
+void
+init_ncci(void)
+{
+	ncci_fsm.state_count = ST_NCCI_COUNT;
+	ncci_fsm.event_count = EV_NCCI_COUNT;
+	ncci_fsm.strEvent = str_ev_ncci;
+	ncci_fsm.strState = str_st_ncci;
+	mISDN_FsmNew(&ncci_fsm, fn_ncci_list, FN_NCCI_COUNT);
+
+	ncciD_fsm.state_count = ST_NCCI_COUNT;
+	ncciD_fsm.event_count = EV_NCCI_COUNT;
+	ncciD_fsm.strEvent = str_ev_ncci;
+	ncciD_fsm.strState = str_st_ncci;
+	mISDN_FsmNew(&ncciD_fsm, fn_ncciD_list, FN_NCCID_COUNT);
+}
+
+void
+free_ncci(void)
+{
+	mISDN_FsmFree(&ncci_fsm);
+	mISDN_FsmFree(&ncciD_fsm);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netdev.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netdev.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netdev.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,316 @@
+/*
+ * gateway between mISDN and Linux's netdev subsystem
+ *
+ * Copyright (C) 2005-2006 Christian Richter
+ *
+ * Authors: Christian Richter 
+ * 
+ * Thanks to Daniele Orlandi from the vISDN Developer Team
+ *
+ * This program is free software and may be modified and distributed
+ * under the terms and conditions of the GNU General Public License.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/kdev_t.h>
+#include <linux/netdevice.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/crc32.h>
+#include <linux/mISDNif.h>
+
+#include "core.h"
+#include "lapd.h"
+
+
+wait_queue_head_t waitq;
+struct sk_buff_head finishq;
+
+
+struct mISDN_netdev {
+	struct sk_buff_head workq;
+	struct list_head list;
+	struct net_device *netdev;
+	struct net_device_stats stats; 
+	mISDNstack_t *st;
+	int nt;
+	int addr;
+};
+
+LIST_HEAD(mISDN_netdev_list);
+	
+static int misdn_chan_frame_xmit(
+	struct net_device *netdev,
+	struct sk_buff *skb, int rx)
+{
+	struct mISDN_netdev *ndev=netdev->priv;
+	struct lapd_prim_hdr *prim_hdr;
+
+	netdev->last_rx = jiffies;
+
+	skb->protocol = htons(ETH_P_LAPD);
+	skb->dev = netdev;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->pkt_type = PACKET_HOST;
+
+	skb_push(skb, sizeof(struct lapd_prim_hdr));
+	prim_hdr = (struct lapd_prim_hdr *)skb->data;
+	prim_hdr->primitive_type = LAPD_PH_DATA_INDICATION;
+
+	if (rx)
+		ndev->stats.rx_packets++;
+	else
+		ndev->stats.rx_packets++;
+		
+	
+	return netif_rx(skb);
+}
+
+
+
+static struct net_device_stats *misdn_netdev_get_stats(
+	struct net_device *netdev)
+{
+		struct mISDN_netdev *ndev=netdev->priv;
+		return &ndev->stats;
+}
+
+static void misdn_netdev_set_multicast_list(
+	struct net_device *netdev)
+{
+}
+
+static int misdn_netdev_do_ioctl(
+	struct net_device *netdev,
+	struct ifreq *ifr, int cmd)
+{
+	return -EOPNOTSUPP;
+}
+
+static int misdn_netdev_change_mtu(
+	struct net_device *netdev,
+	int new_mtu)
+{
+	return 0;
+}
+
+static int lapd_mac_addr(struct net_device *dev, void *addr)
+{
+	return 0;
+}
+
+static void setup_lapd(struct net_device *netdev)
+{
+	netdev->change_mtu = NULL;
+	netdev->hard_header = NULL;
+	netdev->rebuild_header = NULL;
+	netdev->set_mac_address = lapd_mac_addr;
+	netdev->hard_header_cache = NULL;
+	netdev->header_cache_update= NULL;
+	//netdev->hard_header_parse = lapd_hard_header_parse;
+	netdev->hard_header_parse = NULL;
+
+	netdev->type = ARPHRD_LAPD;
+	netdev->hard_header_len = 0;
+	netdev->addr_len = 1;
+	netdev->tx_queue_len = 10;
+
+	memset(netdev->broadcast, 0, sizeof(netdev->broadcast));
+
+	netdev->flags = 0;
+}
+
+
+
+static int misdn_netdev_open(struct net_device *netdev)
+{
+	return 0;
+}
+
+static int misdn_netdev_stop(struct net_device *netdev)
+{
+	return 0;
+}
+
+
+static int mISDN_netdevd(void *data)
+{
+	struct sk_buff *skb;
+	struct mISDN_netdev *ndev;
+	
+	for(;;) {
+		wait_event_interruptible(waitq, 1);
+
+		if ((skb=skb_dequeue(&finishq))) {
+			kfree_skb(skb);
+			return 0;
+		}
+
+		list_for_each_entry(ndev, &mISDN_netdev_list, list) {
+			while ((skb=skb_dequeue(&ndev->workq))) {
+				misdn_chan_frame_xmit(ndev->netdev, skb, 1);
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+static int misdn_netdev_frame_xmit(
+	struct sk_buff *skb,
+	struct net_device *netdev)
+{
+	return 0;
+}
+
+
+/*************************/
+/** Interface Functions **/
+/*************************/
+
+void misdn_log_frame(mISDNstack_t* st, unsigned char *data, int len, int direction) 
+{
+	struct sk_buff *skb;
+	struct mISDN_netdev *ndev;
+	int i;
+
+	skb = alloc_skb(sizeof(struct lapd_prim_hdr)+len, GFP_KERNEL);
+	if (!skb) {
+		printk ("%s: no mem for skb\n", __FUNCTION__);
+		return;
+	}
+	
+	skb_reserve(skb, sizeof(struct lapd_prim_hdr));
+	skb_reserve(skb, 4);
+	memcpy(skb_put(skb, len), data, len);
+
+	list_for_each_entry(ndev, &mISDN_netdev_list, list) {
+		if (ndev->st==st) break;
+	}
+
+	// use syslog as long as kernel oops when using netdev
+	printk ("%s: st(%x): %s ", __FUNCTION__, st->id, (direction==FLG_MSG_UP)?"-->":"<--");
+	for (i=0; i<len; i++)
+		printk("0x%02x ", data[i]);
+	printk ("\n");
+	
+	kfree_skb(skb);
+
+	/*
+	if (ndev)
+		misdn_chan_frame_xmit(ndev->netdev, skb , 1);
+	else
+		printk(KERN_WARNING "No mISDN_netdev for stack:%x\n",st->id);
+	*/
+
+}
+
+
+
+
+int misdn_netdev_addstack(mISDNstack_t *st) 
+{
+	struct net_device *netdev;
+	struct mISDN_netdev *ndev;
+	int err;
+	char name[8];
+
+	sprintf(name, "mISDN%02x",
+	       ((((st->id >> 8) & 0xFF) + 
+	       ((st->id >> 12) & 0xFF)) 
+	       & 0xFF));
+	       
+	printk(KERN_NOTICE "allocating netdev(%s) for stack(%x)\n", name, st->id);
+
+	netdev = alloc_netdev(0, name, setup_lapd);
+	if(!netdev) {
+		printk(KERN_ERR "net_device alloc failed, abort.\n");
+		return -ENOMEM;
+	}
+	
+	ndev = kmalloc(sizeof(struct mISDN_netdev), GFP_KERNEL);
+	if(!ndev) {
+		printk(KERN_ERR "mISDN_netdevice alloc failed, abort.\n");
+		return -ENOMEM;
+	}
+
+	memset(&ndev->stats,0,sizeof(ndev->stats));
+
+	skb_queue_head_init(&ndev->workq);
+
+	ndev->netdev=netdev; 
+
+	netdev->priv = ndev;
+	netdev->open = misdn_netdev_open;
+	netdev->stop = misdn_netdev_stop;
+	netdev->hard_start_xmit = misdn_netdev_frame_xmit;
+	netdev->get_stats = misdn_netdev_get_stats;
+	netdev->set_multicast_list = misdn_netdev_set_multicast_list;
+	netdev->do_ioctl = misdn_netdev_do_ioctl;
+	netdev->change_mtu = misdn_netdev_change_mtu;
+	netdev->features = NETIF_F_NO_CSUM;
+	
+	switch (st->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK) {
+		case ISDN_PID_L0_TE_S0:
+		case ISDN_PID_L0_TE_E1:
+			printk(KERN_NOTICE " --> TE Mode\n");
+			memset(netdev->dev_addr, 0,  sizeof(netdev->dev_addr));
+			break;
+		case ISDN_PID_L0_NT_S0:
+		case ISDN_PID_L0_NT_E1:
+			printk(KERN_NOTICE " --> NT Mode\n");
+			memset(netdev->dev_addr, 1,  sizeof(netdev->dev_addr));
+			break;
+	}
+
+	SET_MODULE_OWNER(netdev);
+
+	netdev->irq = 0;
+	netdev->base_addr = 0;
+	
+	list_add(&ndev->list, &mISDN_netdev_list);
+
+	err = register_netdev(netdev);
+	
+	if (err < 0) {
+		printk(KERN_ERR "Cannot register net device %s, aborting.\n",
+		       netdev->name);
+	}
+	
+
+	return 0;
+}
+
+
+int misdn_netdev_init(void)
+{
+	int err=0;
+	
+	init_waitqueue_head(&waitq);
+	skb_queue_head_init(&finishq);
+
+
+	kernel_thread(mISDN_netdevd, NULL, 0);
+	
+	return err;
+}
+
+void misdn_netdev_exit(void)
+{
+	struct sk_buff *skb=alloc_skb(8,GFP_KERNEL);
+	struct mISDN_netdev *ndev;
+
+	skb_queue_tail(&finishq,skb);
+
+	list_for_each_entry(ndev, &mISDN_netdev_list, list) {
+		unregister_netdev(ndev->netdev);
+	}
+}
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netjet.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netjet.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netjet.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1843 @@
+/*
+ * NETJet mISDN driver
+ *
+ * Author Daniel Potts <daniel.potts at senaware.com>
+ * Copyright (C) 2005 Traverse Technologies P/L
+ *
+ * Based on HiSax NETJet driver by Karsten Keil
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include "core.h"
+#include "channel.h"
+#include "isac.h"
+#include "layer1.h"
+#include "debug.h"
+
+#include <linux/ppp_defs.h>
+
+#include "netjet.h"
+
+//#define DPRINT(...)
+//#define DTRACE(...)
+#define DTRACE printk
+#define DPRINT printk
+
+static const char *netjet_rev = "$Revision: 1.8 $";
+
+#define MAX_CARDS	4
+static int debug;
+static int netjet_cnt;
+static u_int protocol[MAX_CARDS];
+static int layermask[MAX_CARDS];
+
+#ifdef MODULE
+MODULE_AUTHOR("Daniel Potts");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#define MODULE_PARM_T	"1-4i"
+MODULE_PARM(protocol, MODULE_PARM_T);
+MODULE_PARM(layermask, MODULE_PARM_T);
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+#ifdef OLD_MODULE_PARAM_ARRAY
+static int num_protocol=0,num_layermask=0;
+module_param_array(protocol, uint, num_protocol, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, num_layermask, S_IRUGO | S_IWUSR);
+#else
+module_param_array(protocol, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, NULL, S_IRUGO | S_IWUSR);
+#endif
+#endif
+#endif
+
+#ifdef LOCAL_FCSTAB
+static __u16 fcstab[256] =
+{
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+#endif
+
+static mISDNobject_t netjet_mISDN;
+
+enum {
+	NETJET_S_TJ300,
+	NETJET_S_TJ320,
+};
+
+typedef struct {
+	long size;
+	u_int32_t *dmabuf;
+	dma_addr_t dmaaddr; 	// (system phys)
+} tiger_dmabuf_t;
+
+struct tiger_hw {
+	tiger_dmabuf_t send;
+	u_int32_t *s_irq;
+	u_int32_t *s_end;
+	u_int32_t *sendp;
+	tiger_dmabuf_t rec; 
+	int free;
+	u_char *rcvbuf; 
+	u_char *sendbuf;
+	u_char *sp;
+	int sendcnt;
+	u_int s_tot;
+	u_int r_bitcnt;
+	u_int r_tot;
+	u_int r_err;
+	u_int r_fcs;
+	u_char r_state;
+	u_char r_one;
+	u_char r_val;
+	u_char s_state;
+
+	u_char	*tx_buf;
+	u_char	*rx_buf;
+
+};
+
+
+typedef struct {
+	struct list_head	list;
+	struct pci_dev		*pdev;
+	u_int			subtype;
+	u_int			irq;
+	u_int			irqcnt;
+	u_long			base;
+	spinlock_t		lock;
+	isac_chip_t		isac;
+	struct tiger_hw		tiger[2]; // bch hdlc's
+	channel_t		dch;
+	channel_t		bch[2];
+	u_char			ctrlreg;
+
+	u_char			dmactrl;
+	u_char			auxd;
+
+	unsigned char last_is0;
+
+	unsigned char irqmask0;
+} netjet_t;
+
+
+/* Local Prototypes */
+static int tiger_l2l1B (mISDNinstance_t *inst, struct sk_buff *skb);
+static void nj_release_card(netjet_t *card);
+static void netjet_fill_dma(channel_t *bch);
+static void write_raw(channel_t *bch, u_int *buf, int cnt);
+static void write_tiger_bch(channel_t *bch, u_int *buf, int cnt);
+
+static void
+nj_disable_hwirq(netjet_t *card)
+{
+	outb (0, card->base + NETJET_IRQMASK0);
+	outb (0, card->base + NETJET_IRQMASK1);
+}
+
+
+static u_char
+nj_readISAC(void *cs, u_char offset)
+{
+	netjet_t *card = (netjet_t *)cs;
+	u_char ret;
+	
+	card->auxd &= 0xfc;
+	card->auxd |= (offset>>4) & 3;
+	outb (card->auxd, card->base + NETJET_AUXDATA);
+	ret = inb ((card->base | NETJET_ISAC_OFF) |
+		   ((offset & NETJET_HA_MASK) << NETJET_HA_OFFSET));
+	return (ret);
+}
+
+
+void
+nj_writeISAC(void *cs, u_char offset, u_char value)
+{
+	netjet_t *card = (netjet_t *)cs;
+
+	card->auxd &= 0xfc;
+	card->auxd |= (offset>>4) & 3;
+	outb (card->auxd, card->base + NETJET_AUXDATA);
+	outb (value, (card->base | NETJET_ISAC_OFF)  |
+		   ((offset & NETJET_HA_MASK) << NETJET_HA_OFFSET));
+}
+
+
+void
+nj_readISACfifo(void *cs, u_char *data, int size)
+{
+	netjet_t *card = (netjet_t *)cs;
+
+	card->auxd &= 0xfc;
+	outb (card->auxd, card->base + NETJET_AUXDATA);
+	insb((card->base | NETJET_ISAC_OFF), data, size);
+}
+
+
+void 
+nj_writeISACfifo(void *cs, u_char *data, int size)
+{
+	netjet_t *card = (netjet_t *)cs;
+
+	card->auxd &= 0xfc;
+	outb (card->auxd, card->base + NETJET_AUXDATA);
+	outsb((card->base | NETJET_ISAC_OFF), data, size);
+}
+
+
+void 
+fill_mem(channel_t *bch, u_int *pos, u_int cnt, int chan, u_char fill)
+{
+	u_int mask=0x000000ff, val = 0, *p=pos;
+	u_int i;
+	struct tiger_hw *tiger;
+
+	tiger = bch->hw;
+	
+	val |= fill;
+	if (chan) {
+		val  <<= 8;
+		mask <<= 8;
+	}
+	mask ^= 0xffffffff;
+	for (i=0; i<cnt; i++) {
+		*p   &= mask;
+		*p++ |= val;
+		if (p > tiger->s_end)
+			p = tiger->send.dmabuf;
+	}
+}
+
+
+int
+mode_tiger(channel_t *bch, int bc, int protocol)
+{
+	struct tiger_hw *tiger;
+	netjet_t *card;
+
+	tiger = bch->hw;
+	card = bch->inst.privat;
+
+//        u_char led;
+
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, 
+				 "Tiger bchan %d/%d protocol %x-->%x",
+				 bc, bch->channel, bch->state, protocol);
+	if ((protocol != -1) && (bc != bch->channel))
+		printk(KERN_WARNING "%s: netjet mismatch channel(%d/%d)\n", 
+		       __FUNCTION__, bch->channel, bc);
+
+	switch (protocol) {
+	case (-1): /* used for init */
+		bch->state = protocol; //james
+		bch->channel = bc;
+	case (ISDN_PID_NONE):
+		if (bch->state == ISDN_PID_NONE) {
+			break;
+		}
+		fill_mem(bch, tiger->send.dmabuf,
+			 NETJET_DMA_TXSIZE, bc, 0xff);
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst, 
+					 "Tiger stat rec %d/%d send %d",
+					 tiger->r_tot, tiger->r_err,
+					 tiger->s_tot); 
+		bch->state = ISDN_PID_NONE;
+		/* only stop dma and interrupts if both channels NULL */
+		if ((card->bch[0].state == ISDN_PID_NONE) &&
+		    (card->bch[1].state == ISDN_PID_NONE))
+		{
+			card->dmactrl = 0;
+			outb(card->dmactrl, card->base + NETJET_DMACTRL);
+			outb(0, card->base + NETJET_IRQMASK0);
+		}
+		test_and_clear_bit(FLG_HDLC, &bch->Flags);
+		test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
+#if 0 // led stuff
+		if (cs->typ == ISDN_CTYPE_NETJET_S)
+		{
+			// led off
+			led = bc & 0x01;
+			led = 0x01 << (6 + led); // convert to mask
+			led = ~led;
+			cs->hw.njet.auxd &= led;
+			byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+		}
+#endif
+		break;
+	case (ISDN_PID_L1_B_64TRANS):
+		/* fall through for transparancy (eg voice).. */
+		test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
+
+//	case (L1_MODE_HDLC_56K):
+	case (ISDN_PID_L1_B_64HDLC):
+		bch->state = protocol; //james
+		if (protocol == ISDN_PID_L1_B_64HDLC)
+			test_and_set_bit(FLG_HDLC, &bch->Flags);
+		fill_mem(bch, tiger->send.dmabuf,
+			 NETJET_DMA_TXSIZE, bc, 0xff);
+		tiger->r_state = HDLC_ZERO_SEARCH;
+		tiger->r_tot = 0;
+		tiger->r_bitcnt = 0;
+		tiger->r_one = 0;
+		tiger->r_err = 0;
+		tiger->s_tot = 0;
+		if (! card->dmactrl) {
+			fill_mem(bch, tiger->send.dmabuf,
+				 NETJET_DMA_TXSIZE, !bc, 0xff);
+			card->dmactrl = 1;
+			outb(card->dmactrl, card->base + NETJET_DMACTRL);
+			outb(0x0f, card->base + NETJET_IRQMASK0);
+			/* was 0x3f now 0x0f for TJ300 and TJ320 GE 13/07/00 */
+		}
+		tiger->sendp = tiger->send.dmabuf;
+		tiger->free = NETJET_DMA_TXSIZE;
+		test_and_set_bit(FLG_EMPTY, &bch->Flags);
+#if 0 // old led stuff
+		if (cs->typ == ISDN_CTYPE_NETJET_S)
+		{
+			// led on
+			led = bc & 0x01;
+			led = 0x01 << (6 + led); // convert to mask
+			cs->hw.njet.auxd |= led;
+			byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+		}
+#endif
+		break;
+	default:
+		mISDN_debugprint(&bch->inst, "nj prot not known %x", protocol);
+		return(-ENOPROTOOPT);
+	}
+
+	if (bch->debug & L1_DEB_HSCX)
+	 	mISDN_debugprint(&bch->inst, 
+				 "tiger: set %x %x %x  %x/%x  pulse=%d",
+				 inb(card->base + NETJET_DMACTRL),
+				 inb(card->base + NETJET_IRQMASK0),
+				 inb(card->base + NETJET_IRQSTAT0),
+				 inl(card->base + NETJET_DMA_READ_ADR),
+				 inl(card->base + NETJET_DMA_WRITE_ADR),
+				 inb(card->base + NETJET_PULSE_CNT));
+	return 0;
+}
+
+
+static void
+nj_reset (netjet_t *card)
+{
+	outb (0xff, card->base + NETJET_CTRL); /* Reset On */
+	mdelay(10);
+
+	/* now edge triggered for TJ320 GE 13/07/00 */
+	/* see comment in IRQ function */
+	if (card->subtype == NETJET_S_TJ320) /* TJ320 */
+		card->ctrlreg = 0x40;  /* Reset Off and status read clear */
+	else
+		card->ctrlreg = 0x00;  /* Reset Off and status read clear */
+	outb (card->ctrlreg, card->base + NETJET_CTRL);
+	mdelay(10);
+
+	/* configure AUX pins (all output except ISAC IRQ pin) */
+	card->auxd = 0;
+	card->dmactrl = 0;
+	outb (~NETJET_ISACIRQ, card->base + NETJET_AUXCTRL);
+	outb (NETJET_ISACIRQ,  card->base + NETJET_IRQMASK1);
+	outb (card->auxd, card->base + NETJET_AUXDATA);	
+}
+
+
+static int
+nj_manager (void *data, u_int prim, void *arg)
+{
+	mISDNinstance_t *inst = data;
+	netjet_t *card;
+	struct sk_buff *skb;
+	u_long		flags;
+	int channel = -1;
+
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim,arg,&netjet_mISDN)
+		printk(KERN_ERR "%s: no data prim %x arg %p\n",
+			__FUNCTION__, prim, arg);
+		return(-EINVAL);
+	}	
+
+	spin_lock_irqsave(&netjet_mISDN.lock, flags);
+	list_for_each_entry(card, &netjet_mISDN.ilist, list) {
+		if (&card->dch.inst == inst) {
+			channel = 2;
+			break;
+		}
+		if (&card->bch[0].inst == inst) {
+			channel = 0;
+			break;
+		}
+		if (&card->bch[1].inst == inst) {
+			channel = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&netjet_mISDN.lock, flags);
+	if (channel<0) {
+		printk(KERN_WARNING "%s: no channel data %p prim %x arg %p\n",
+			__FUNCTION__, data, prim, arg);
+		return(-EINVAL);
+	}
+
+	switch (prim) {
+	case MGR_REGLAYER | CONFIRM:
+		if (channel == 2)
+			mISDN_setpara(&card->dch, &inst->st->para);
+		else
+			mISDN_setpara(&card->bch[channel], &inst->st->para);
+		break;
+	case MGR_UNREGLAYER | REQUEST:
+	    	if ((skb = create_link_skb(PH_CONTROL | REQUEST,
+					   HW_DEACTIVATE, 0, NULL, 0))) {
+			if (channel == 2) {
+				if (mISDN_ISAC_l1hw(inst, skb))
+					dev_kfree_skb(skb);
+			} else {
+				if (tiger_l2l1B(inst, skb))
+					dev_kfree_skb(skb);
+			}
+		} else {
+			printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
+		}
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+		break;
+	case MGR_CLRSTPARA | INDICATION:
+		arg = NULL;
+	case MGR_ADDSTPARA | INDICATION:
+		if (channel == 2)
+			mISDN_setpara(&card->dch, arg);
+		else
+			mISDN_setpara(&card->bch[channel], arg);
+		break;
+	case MGR_RELEASE | INDICATION:
+		if (channel == 2) {
+			nj_release_card(card);
+		} else {
+			netjet_mISDN.refcnt--;
+		}
+		break;
+
+	case MGR_SETSTACK | INDICATION:
+		if ((channel!=2) && (inst->pid.global == 2)) {
+			if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
+				0, 0, NULL, 0))) {
+				if (tiger_l2l1B(inst, skb))
+					dev_kfree_skb(skb);
+			}
+			if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
+						 0, 0, NULL, 0);
+			else
+				mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
+						 0, 0, NULL, 0);
+		}
+		break;
+
+	PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+	PRIM_NOT_HANDLED(MGR_GLOBALOPT | REQUEST);
+	default:
+		printk(KERN_WARNING "%s: prim %x not handled\n",
+		       __FUNCTION__, prim);
+		return (-EINVAL);
+	}
+
+	return 0;
+}
+
+
+static int
+tiger_l2l1B(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*bch;
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	bch = container_of(inst, channel_t, inst);
+
+	if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		ret = channel_senddata(bch, hh->dinfo, skb);
+		if (ret > 0) { /* direct TX */
+			netjet_fill_dma(bch);
+			ret = 0;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		return(ret);
+	} 
+	if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_ESTABLISH  | REQUEST))) {
+		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
+			spin_lock_irqsave(inst->hwlock, flags);
+			ret = mode_tiger(bch, bch->channel, bch->inst.pid.protocol[1]);
+			spin_unlock_irqrestore(inst->hwlock, flags);
+			if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				test_and_set_bit(FLG_L2DATA, &bch->Flags);
+		}
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
+	} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_RELEASE | REQUEST)) ||
+		((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+			if (bch->next_skb == NULL)
+				printk(KERN_WARNING "%s: TX_NEXT set with no next_skb\n", __FUNCTION__);
+			else {
+				dev_kfree_skb(bch->next_skb);
+				bch->next_skb = NULL;
+			}
+		}
+		if (bch->tx_skb) {
+			dev_kfree_skb(bch->tx_skb);
+			bch->tx_skb = NULL;
+			bch->tx_idx = 0;
+		}
+		test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		mode_tiger(bch, bch->channel, 0);
+		test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+		test_and_clear_bit(FLG_L2DATA, &bch->Flags);
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		skb_trim(skb, 0);
+		if (hh->prim != (PH_CONTROL | REQUEST))
+			if (!mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, 0, skb))
+				return 0;
+	} else {
+		printk(KERN_WARNING "tiger_l2l1B unknown %x prim(%x)\n", (int)skb, hh->prim);
+		ret = -EINVAL;
+	}
+	if (!ret) {
+		dev_kfree_skb(skb);
+	}
+	return(ret);
+}
+
+
+void __init
+inittiger(netjet_t *card)
+{
+	struct tiger_hw *tiger0, *tiger1;
+
+	/* NOTE: I believe hisax tiger driver is wrong.
+	 *  It allocates 4 times too much memory (unsigned int) and does not
+	 *  use pci consistent, which won't work on all systems.
+	 */
+
+	tiger0 = &card->tiger[0];
+	tiger1 = &card->tiger[1];
+
+	/* XXX review buffer size */
+	tiger0->tx_buf = kmalloc(4 * NETJET_DMA_TXSIZE * sizeof (u_int32_t), GFP_ATOMIC);
+	tiger1->tx_buf = kmalloc(4 * NETJET_DMA_TXSIZE * sizeof (u_int32_t), GFP_ATOMIC);
+
+	tiger0->send.size = NETJET_DMA_TXSIZE * sizeof (u_int32_t);
+	tiger0->send.dmabuf = 
+		pci_alloc_consistent ((struct pci_dev *) card->pdev,
+				      tiger0->send.size,
+				      &tiger0->send.dmaaddr);
+	if (!tiger0->send.dmabuf) {
+		printk(KERN_WARNING "mISDN: No memory for tiger.send\n");
+		return;
+	}
+
+	/* 
+	 * NOTE: This code is seedy int ptr arithmetic.
+	 *       You have been warned.
+	 */
+
+	tiger0->s_irq = tiger0->send.dmabuf + NETJET_DMA_TXSIZE/2 - 1;
+	tiger0->s_end = tiger0->send.dmabuf + NETJET_DMA_TXSIZE - 1;
+	tiger1->send.dmabuf = tiger0->send.dmabuf;
+	tiger1->s_irq = tiger0->s_irq;
+	tiger1->s_end = tiger0->s_end;
+	
+	memset(tiger0->send.dmabuf, 0xff, NETJET_DMA_TXSIZE *sizeof(uint32_t));
+	mISDN_debugprint(&card->bch[0].inst, "tiger: send buf %p - %p", 
+			 tiger0->send.dmabuf,
+			 tiger0->send.dmabuf + NETJET_DMA_TXSIZE - 1);
+	outl(tiger0->send.dmaaddr, card->base + NETJET_DMA_READ_START);
+	outl(virt_to_bus(tiger0->s_irq), card->base + NETJET_DMA_READ_IRQ);
+	outl(virt_to_bus(tiger0->s_end), card->base + NETJET_DMA_READ_END);
+
+	tiger0->rec.size = NETJET_DMA_RXSIZE * sizeof (u_int32_t);
+	tiger0->rec.dmabuf = pci_alloc_consistent ((struct pci_dev *) 
+						   card->pdev,
+						   tiger0->rec.size,
+						   &tiger0->rec.dmaaddr);
+	if (!tiger0->rec.dmabuf) {
+		printk(KERN_WARNING "mISDN: No memory for tiger.rec\n");
+		return;
+	}
+
+	mISDN_debugprint(&card->bch[0].inst, "tiger: rec buf %p - %p", 
+			 tiger0->rec.dmabuf,
+			 tiger0->rec.dmabuf + NETJET_DMA_RXSIZE - 1);
+	tiger1->rec.dmabuf = tiger0->rec.dmabuf;
+	memset(tiger0->rec.dmabuf, 0xff, NETJET_DMA_RXSIZE *sizeof(u_int32_t));
+	outl(tiger0->rec.dmaaddr, card->base + NETJET_DMA_WRITE_START);
+	outl(virt_to_bus(tiger0->rec.dmabuf + NETJET_DMA_RXSIZE/2 - 1),
+	     card->base + NETJET_DMA_WRITE_IRQ);
+	outl(virt_to_bus(tiger0->rec.dmabuf + NETJET_DMA_RXSIZE - 1),
+	     card->base + NETJET_DMA_WRITE_END);
+	mISDN_debugprint(&card->bch[0].inst, "tiger: dmacfg  %x/%x  pulse=%d",
+			 inl(card->base + NETJET_DMA_WRITE_ADR),
+			 inl(card->base + NETJET_DMA_READ_ADR),
+			 inb(card->base + NETJET_PULSE_CNT));
+	card->last_is0 = 0;
+}
+
+
+static 
+void printframe(mISDNinstance_t *cs, u_char *buf, int count, char *s) 
+{
+	char tmp[128];
+	char *t = tmp;
+	int i=count,j;
+	u_char *p = buf;
+
+	t += sprintf(t, "tiger %s(%4d)", s, count);
+	while (i>0) {
+		if (i>16)
+			j=16;
+		else
+			j=i;
+
+		mISDN_QuickHex(t, p, j);
+		mISDN_debugprint(cs, tmp);
+		p += j;
+		i -= j;
+		t = tmp;
+		t += sprintf(t, "tiger %s      ", s);
+	}
+}
+
+
+// macro for 64k
+#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
+			bitcnt++;\
+			s_val >>= 1;\
+			if (val & 1) {\
+				s_one++;\
+				s_val |= 0x80;\
+			} else {\
+				s_one = 0;\
+				s_val &= 0x7f;\
+			}\
+			if (bitcnt==8) {\
+				tiger->tx_buf[s_cnt++] = s_val;\
+				bitcnt = 0;\
+			}\
+			if (s_one == 5) {\
+				s_val >>= 1;\
+				s_val &= 0x7f;\
+				bitcnt++;\
+				s_one = 0;\
+			}\
+			if (bitcnt==8) {\
+				tiger->tx_buf[s_cnt++] = s_val;\
+				bitcnt = 0;\
+			}\
+			val >>= 1;\
+		}
+
+
+static int 
+make_raw_data_transparent(channel_t *bch, struct sk_buff *skb) 
+{
+	// this make_raw is for transparent (Voice)
+	u_int i,s_cnt=0;
+	u_char val;
+	struct tiger_hw *tiger;
+	
+	tiger = bch->hw;
+	
+	if (!skb) {
+		mISDN_debugprint(&bch->inst, "tiger make_raw_trans: NULL skb");
+		return(1);
+	}
+
+	for (i=0; i<skb->len; i++) {
+		val = skb->data[i]; 		// input
+		tiger->tx_buf[s_cnt++] = val;	// output
+	}
+	tiger->sendcnt = s_cnt;
+	tiger->sp = tiger->tx_buf;
+	return(0);
+}
+
+
+static int 
+make_raw_data(channel_t *bch, struct sk_buff *skb) 
+{
+	// this make_raw is for 64k
+	u_int i,s_cnt=0;
+	u_char j;
+	u_char val;
+	u_char s_one = 0;
+	u_char s_val = 0;
+	u_char bitcnt = 0;
+	u_int fcs;
+
+	struct tiger_hw *tiger;
+
+	tiger = bch->hw;
+
+	if (!skb) {
+		mISDN_debugprint(&bch->inst, "tiger make_raw: NULL skb");
+		return(1);
+	}
+
+	tiger->tx_buf[s_cnt++] = HDLC_FLAG_VALUE;
+	fcs = PPP_INITFCS;
+	for (i=0; i<skb->len; i++) {
+		val = skb->data[i];
+		fcs = PPP_FCS (fcs, val);
+		MAKE_RAW_BYTE;
+	}
+	fcs ^= 0xffff;
+	val = fcs & 0xff;
+	MAKE_RAW_BYTE;
+	val = (fcs>>8) & 0xff;
+	MAKE_RAW_BYTE;
+	val = HDLC_FLAG_VALUE;
+	for (j=0; j<8; j++) { 
+		bitcnt++;
+		s_val >>= 1;
+		if (val & 1)
+			s_val |= 0x80;
+		else
+			s_val &= 0x7f;
+		if (bitcnt==8) {
+			tiger->tx_buf[s_cnt++] = s_val;
+			bitcnt = 0;
+		}
+		val >>= 1;
+	}
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst,"tiger make_raw: in %ld out %d.%d",
+				 skb->len, s_cnt, bitcnt);
+	if (bitcnt) {
+		while (8>bitcnt++) {
+			s_val >>= 1;
+			s_val |= 0x80;
+		}
+		tiger->tx_buf[s_cnt++] = s_val;
+		tiger->tx_buf[s_cnt++] = 0xff;	// NJ<->NJ thoughput bug fix
+	}
+	tiger->sendcnt = s_cnt;
+	tiger->sp = tiger->tx_buf;
+	return(0);
+}
+
+
+// macro for 56k
+#define MAKE_RAW_BYTE_56K for (j=0; j<8; j++) { \
+			bitcnt++;\
+			s_val >>= 1;\
+			if (val & 1) {\
+				s_one++;\
+				s_val |= 0x80;\
+			} else {\
+				s_one = 0;\
+				s_val &= 0x7f;\
+			}\
+			if (bitcnt==7) {\
+				s_val >>= 1;\
+				s_val |= 0x80;\
+				tiger->tx_buf[s_cnt++] = s_val;\
+				bitcnt = 0;\
+			}\
+			if (s_one == 5) {\
+				s_val >>= 1;\
+				s_val &= 0x7f;\
+				bitcnt++;\
+				s_one = 0;\
+			}\
+			if (bitcnt==7) {\
+				s_val >>= 1;\
+				s_val |= 0x80;\
+				tiger->tx_buf[s_cnt++] = s_val;\
+				bitcnt = 0;\
+			}\
+			val >>= 1;\
+		}
+
+
+static int 
+make_raw_data_56k(channel_t *bch, struct sk_buff *skb)
+{
+	// this make_raw is for 56k
+	u_int i,s_cnt=0;
+	u_char j;
+	u_char val;
+	u_char s_one = 0;
+	u_char s_val = 0;
+	u_char bitcnt = 0;
+	u_int fcs;
+
+	struct tiger_hw *tiger;
+
+	tiger = bch->hw;
+
+	if (!skb) {
+		mISDN_debugprint(&bch->inst, "tiger make_raw_56k: NULL skb");
+		return(1);
+	}
+
+	val = HDLC_FLAG_VALUE;
+	for (j=0; j<8; j++) { 
+		bitcnt++;
+		s_val >>= 1;
+		if (val & 1)
+			s_val |= 0x80;
+		else
+			s_val &= 0x7f;
+		if (bitcnt==7) {
+			s_val >>= 1;
+			s_val |= 0x80;
+			tiger->tx_buf[s_cnt++] = s_val;
+			bitcnt = 0;
+		}
+		val >>= 1;
+	};
+	fcs = PPP_INITFCS;
+	for (i=0; i<skb->len; i++) {
+		val = skb->data[i];
+		fcs = PPP_FCS (fcs, val);
+		MAKE_RAW_BYTE_56K;
+	}
+	fcs ^= 0xffff;
+	val = fcs & 0xff;
+	MAKE_RAW_BYTE_56K;
+	val = (fcs>>8) & 0xff;
+	MAKE_RAW_BYTE_56K;
+	val = HDLC_FLAG_VALUE;
+	for (j=0; j<8; j++) { 
+		bitcnt++;
+		s_val >>= 1;
+		if (val & 1)
+			s_val |= 0x80;
+		else
+			s_val &= 0x7f;
+		if (bitcnt==7) {
+			s_val >>= 1;
+			s_val |= 0x80;
+			tiger->tx_buf[s_cnt++] = s_val;
+			bitcnt = 0;
+		}
+		val >>= 1;
+	}
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst,
+				 "tiger make_raw_56k: in %ld out %d.%d",
+				 skb->len, s_cnt, bitcnt);
+	if (bitcnt) {
+		while (8>bitcnt++) {
+			s_val >>= 1;
+			s_val |= 0x80;
+		}
+		tiger->tx_buf[s_cnt++] = s_val;
+		tiger->tx_buf[s_cnt++] = 0xff;	// NJ<->NJ thoughput bug fix
+	}
+	tiger->sendcnt = s_cnt;
+	tiger->sp = tiger->tx_buf;
+	return(0);
+}
+
+
+static void 
+netjet_fill_dma(channel_t *bch)
+{
+	u_int *p, *sp;
+	int cnt;
+	struct tiger_hw *tiger;
+	netjet_t *card;
+	struct sk_buff *skb;
+
+	tiger = bch->hw;
+	card = bch->inst.privat;
+	skb = bch->tx_skb;
+
+	if (!skb) {
+		printk(KERN_WARNING "%s: called with no skb\n", __FUNCTION__);
+		return;
+	}
+
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst,"tiger fill_dma1: c%d %4x", 
+				 bch->channel, bch->Flags);
+
+	if (test_bit(FLG_HDLC, &bch->Flags)) {		// it's 64k
+		if (make_raw_data(bch, skb))
+			return;		
+	} else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+		if (make_raw_data_transparent(bch, skb))
+			return;
+	} else { 						// it's 56k
+		if (make_raw_data_56k(bch, skb))
+			return;		
+	}
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst,"tiger fill_dma2: c%d %4x", 
+				 bch->channel, bch->Flags);
+
+	if (test_and_clear_bit(FLG_NOFRAME, &bch->Flags)) {
+		write_raw(bch, tiger->sendp, tiger->free);
+	} else if (test_and_clear_bit(FLG_HALF, &bch->Flags)) {
+		/* urky, don't we know this already? */
+		p = bus_to_virt(inl(card->base + NETJET_DMA_READ_ADR));
+		sp = tiger->sendp;
+		if (p == tiger->s_end)
+			p = tiger->send.dmabuf -1;
+		if (sp == tiger->s_end)
+			sp = tiger->send.dmabuf -1;
+		cnt = p - sp;
+		if (cnt <0) {
+			write_raw(bch, tiger->sendp, tiger->free);
+		} else {
+			p++;
+			cnt++;
+			if (p > tiger->s_end)
+				p = tiger->send.dmabuf;
+			p++;
+			cnt++;
+			if (p > tiger->s_end)
+				p = tiger->send.dmabuf;
+			write_raw(bch, p, tiger->free - cnt);
+		}
+	} else if (test_and_clear_bit(FLG_EMPTY, &bch->Flags)) {
+		p = bus_to_virt(inl(card->base + NETJET_DMA_READ_ADR));
+		cnt = tiger->s_end - p;
+		if (cnt < 2) {
+			p = tiger->send.dmabuf + 1;
+			cnt = NETJET_DMA_TXSIZE/2 - 2;
+		} else {
+			p++;
+			p++;
+			if (cnt <= (NETJET_DMA_TXSIZE/2))
+				cnt += NETJET_DMA_TXSIZE/2;
+			cnt--;
+			cnt--;
+		}
+		write_raw(bch, p, cnt);
+	}
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst,"tiger fill_dma3: c%d %4x", 
+				 bch->channel, bch->Flags);
+}
+
+
+static void 
+write_raw (channel_t *bch, u_int *buf, int cnt) 
+{
+	u_int mask, val, *p=buf;
+	u_int i, s_cnt;
+	struct tiger_hw *tiger;
+
+	tiger = bch->hw;
+        
+        if (cnt <= 0) {
+        	return;
+	}
+	if (test_bit(FLG_TX_BUSY, &bch->Flags)) {
+		if (tiger->sendcnt > cnt) {
+			s_cnt = cnt;
+			tiger->sendcnt -= cnt;
+		} else {
+			s_cnt = tiger->sendcnt;
+			tiger->sendcnt = 0;
+		}
+		if (bch->channel)
+			mask = 0xffff00ff;
+		else
+			mask = 0xffffff00;
+		for (i=0; i<s_cnt; i++) {
+			val = bch->channel ? ((tiger->sp[i] <<8) & 0xff00) :
+				(tiger->sp[i]);
+			*p   &= mask;
+			*p++ |= val;
+			if (p > tiger->s_end)
+				p = tiger->send.dmabuf;
+		}
+		tiger->s_tot += s_cnt;
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst,
+					 "tiger write_raw: c%d %p-%p %d/%d %d N/A", 
+					 bch->channel, buf, p, s_cnt, cnt,
+					 tiger->sendcnt/*, bcs->cs->hw.njet.irqstat0*/);
+		if (bch->debug & L1_DEB_HSCX_FIFO)
+			printframe(&bch->inst, tiger->sp, s_cnt, "snd");
+		tiger->sp += s_cnt;
+		tiger->sendp = p;
+
+		/* Test to see if we can send more */
+		if (tiger->sendcnt == 0) {
+
+			/* XXX old block, all needed? */
+			tiger->free = cnt - s_cnt;
+			if (tiger->free > (NETJET_DMA_TXSIZE/2))
+				test_and_set_bit(FLG_HALF, &bch->Flags);
+			else {
+				test_and_clear_bit(FLG_HALF, &bch->Flags);
+				test_and_set_bit(FLG_NOFRAME, &bch->Flags);
+			}
+			/* end old block */
+
+			if (bch->tx_skb) {
+				dev_kfree_skb(bch->tx_skb);
+				bch->tx_skb = NULL;
+				test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+			}
+#if 0
+			if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+				bch->tx_skb = bch->next_skb;
+				bch->tx_idx = 0;
+				bch->next_skb = NULL;
+				if (bch->tx_skb) {
+					mISDN_head_t *hh = mISDN_HEAD_P(bch->tx_skb);
+					queue_ch_frame(bch, CONFIRM, hh->dinfo, NULL);
+					netjet_fill_dma(bch);
+				} else {
+					//bch->tx_len = 0;
+					printk(KERN_WARNING "hdlc tx irq TX_NEXT without skb\n");
+					test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+				}
+			} else {
+				bch->tx_skb = NULL;
+				mask ^= 0xffffffff;
+				if (s_cnt < cnt) {
+					for (i=s_cnt; i<cnt;i++) {
+						*p++ |= mask;
+						if (p>tiger->s_end)
+							p = tiger->send.dmabuf;
+					}
+					if (bch->debug & L1_DEB_HSCX)
+						mISDN_debugprint(&bch->inst, "tiger write_raw: fill rest %d",
+								 cnt - s_cnt);
+				}
+				test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+			}
+#endif
+		}
+	} else if (test_and_clear_bit(FLG_NOFRAME, &bch->Flags)) {
+		test_and_set_bit(FLG_HALF, &bch->Flags);
+		fill_mem(bch, buf, cnt, bch->channel, 0xff);
+		tiger->free += cnt;
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst,
+					 "tiger write_raw: fill half");
+	} else if (test_and_clear_bit(FLG_HALF, &bch->Flags)) {
+		test_and_set_bit(FLG_EMPTY, &bch->Flags);
+		fill_mem(bch, buf, cnt, bch->channel, 0xff);
+		if (bch->debug & L1_DEB_HSCX)
+			mISDN_debugprint(&bch->inst,
+					 "tiger write_raw: fill full");
+	}
+}
+
+
+static void 
+got_frame(channel_t *bch, int count) 
+{
+	struct sk_buff *skb;
+		
+	if (bch->rx_skb == NULL)
+		return;
+
+	if (bch->rx_skb->len < MISDN_COPY_SIZE) {
+		skb = alloc_stack_skb(bch->rx_skb->len, bch->up_headerlen);
+		if (skb) {
+			memcpy(skb_put(skb, bch->rx_skb->len),
+			       bch->rx_skb->data, bch->rx_skb->len);
+			skb_trim(bch->rx_skb, 0);
+		} else {
+			skb = bch->rx_skb;
+			bch->rx_skb = NULL;
+		}
+	} else {
+		skb = bch->rx_skb;
+		bch->rx_skb = NULL;
+	}
+
+	if (bch->debug & L1_DEB_RECEIVE_FRAME)
+		printframe(&bch->inst, skb->data, skb->len, "got_frame");
+
+	queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, skb);
+}
+
+
+static void 
+read_raw_transparent(channel_t *bch, u_int *buf, int cnt)
+{
+	struct tiger_hw *tiger;
+	int i;
+	u_char val;
+	u_int  *pend;
+	u_int *p = buf;
+	
+	u_char *skb_ptr;
+
+	tiger = bch->hw;
+	pend = tiger->rec.dmabuf + NETJET_DMA_RXSIZE -1;
+
+	if (!bch->rx_skb) {
+		if (!(bch->rx_skb = alloc_stack_skb(bch->maxlen, bch->up_headerlen))) {
+			printk(KERN_WARNING "mISDN: B receive out of memory\n");
+			return;
+		}
+	}
+	if ((bch->rx_skb->len + cnt) > bch->maxlen) {
+		if (bch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&bch->inst, "read_raw_transparent overrun %d",
+				bch->rx_skb->len + cnt);
+		return;
+	}
+
+	skb_ptr = skb_put(bch->rx_skb, cnt);
+
+	for (i=0;i<cnt;i++) {
+		val = bch->channel ? ((*p>>8) & 0xff) : (*p & 0xff);
+		p++;
+		if (p > pend)
+			p = tiger->rec.dmabuf;
+		skb_ptr[i] = val;
+	}
+        got_frame(bch, cnt);
+}
+
+
+static void 
+read_raw(channel_t *bch, u_int *buf, int cnt)
+{
+	int i;
+	u_char j;
+	u_char val;
+	struct tiger_hw *tiger;
+	u_int  *pend;
+
+	u_char state;
+	u_char r_one;
+	u_char r_val;
+	u_int bitcnt;
+
+	int bits;
+	u_char mask;
+
+	u_int *p = buf;
+
+	u_char *skb_ptr;
+
+	if (!bch->rx_skb) {
+		if (!(bch->rx_skb = alloc_stack_skb(bch->maxlen, bch->up_headerlen))) {
+			printk(KERN_WARNING "mISDN: B receive out of memory\n");
+			return;
+		}
+	}
+
+	skb_ptr = skb_put (bch->rx_skb, 0);
+
+	tiger = bch->hw;
+	pend = tiger->rec.dmabuf + NETJET_DMA_RXSIZE - 1;
+	state = tiger->r_state;
+	r_one = tiger->r_one;
+	r_val = tiger->r_val;
+	bitcnt = tiger->r_bitcnt;
+
+        if (test_bit(FLG_HDLC, &bch->Flags)) {
+		mask = 0xff;
+		bits = 8;
+	}
+	else { // it's 56K
+		mask = 0x7f;
+		bits = 7;
+	};
+	for (i=0;i<cnt;i++) {
+		val = bch->channel ? ((*p>>8) & 0xff) : (*p & 0xff);
+		p++;
+		if (p > pend)
+			p = tiger->rec.dmabuf;
+		if ((val & mask) == mask) {
+			state = HDLC_ZERO_SEARCH;
+			tiger->r_tot++;
+			bitcnt = 0;
+			r_one = 0;
+			continue;
+		}
+		for (j=0;j<bits;j++) {
+			if (state == HDLC_ZERO_SEARCH) {
+				if (val & 1) {
+					r_one++;
+				} else {
+					r_one = 0;
+					state = HDLC_FLAG_SEARCH;
+					if (bch->debug & L1_DEB_HSCX)
+						mISDN_debugprint(&bch->inst,"tiger read_raw: zBit(%d,%d,%d) %x",
+								 tiger->r_tot,i,j,val);
+				}
+			} else if (state == HDLC_FLAG_SEARCH) { 
+				if (val & 1) {
+					r_one++;
+					if (r_one>6) {
+						state = HDLC_ZERO_SEARCH;
+					}
+				} else {
+					if (r_one==6) {
+						bitcnt = 0;
+						r_val = 0;
+						state = HDLC_FLAG_FOUND;
+						if (bch->debug & L1_DEB_HSCX)
+							mISDN_debugprint(&bch->inst,"tiger read_raw: flag(%d,%d,%d) %x",
+									 tiger->r_tot,i,j,val);
+					}
+					r_one=0;
+				}
+			} else if (state ==  HDLC_FLAG_FOUND) {
+				if (val & 1) {
+					r_one++;
+					if (r_one>6) {
+						state=HDLC_ZERO_SEARCH;
+					} else {
+						r_val >>= 1;
+						r_val |= 0x80;
+						bitcnt++;
+					}
+				} else {
+					if (r_one==6) {
+						bitcnt=0;
+						r_val=0;
+						r_one=0;
+						val >>= 1;
+						continue;
+					} else if (r_one!=5) {
+						r_val >>= 1;
+						r_val &= 0x7f;
+						bitcnt++;
+					}
+					r_one=0;	
+				}
+				if ((state != HDLC_ZERO_SEARCH) &&
+					!(bitcnt & 7)) {
+					state=HDLC_FRAME_FOUND;
+					tiger->r_fcs = PPP_INITFCS;
+					skb_ptr[0] = r_val;
+					tiger->r_fcs = PPP_FCS (tiger->r_fcs, r_val);
+					if (bch->debug & L1_DEB_HSCX)
+						mISDN_debugprint(&bch->inst,"tiger read_raw: byte1(%d,%d,%d) rval %x val %x i (N/A)",
+								 tiger->r_tot,i,j,r_val,val
+								 /*,bcs->cs->hw.njet.irqstat0*/);
+				}
+			} else if (state ==  HDLC_FRAME_FOUND) {
+				if (val & 1) {
+					r_one++;
+					if (r_one>6) {
+						state=HDLC_ZERO_SEARCH;
+						bitcnt=0;
+					} else {
+						r_val >>= 1;
+						r_val |= 0x80;
+						bitcnt++;
+					}
+				} else {
+					if (r_one==6) {
+						r_val=0; 
+						r_one=0;
+						bitcnt++;
+						if (bitcnt & 7) {
+							mISDN_debugprint(&bch->inst, "tiger: frame not byte aligned");
+							state=HDLC_FLAG_SEARCH;
+							tiger->r_err++;
+#ifdef ERROR_STATISTIC
+							bcs->err_inv++;
+#endif
+						} else {
+							if (bch->debug & L1_DEB_HSCX)
+								mISDN_debugprint(&bch->inst,"tiger frame end(%d,%d): fcs(%x) i (N/A)",
+										 i,j,tiger->r_fcs/*, bcs->cs->hw.njet.irqstat0*/);
+							if (tiger->r_fcs == PPP_GOODFCS) {
+								skb_put (bch->rx_skb, (bitcnt>>3)-3);
+								got_frame(bch, (bitcnt>>3)-3);
+								if (!bch->rx_skb) {
+									if (!(bch->rx_skb = alloc_stack_skb(bch->maxlen, bch->up_headerlen))) {
+										printk(KERN_WARNING "mISDN: B receive out of memory\n");
+										return;
+									}
+								}
+								skb_ptr = skb_put (bch->rx_skb, 0);
+							} else {
+								if (bch->debug) {
+									mISDN_debugprint(&bch->inst, "tiger FCS error");
+									tiger->r_err++;
+								}
+#ifdef ERROR_STATISTIC
+							bcs->err_crc++;
+#endif
+							}
+							state=HDLC_FLAG_FOUND;
+						}
+						bitcnt=0;
+					} else if (r_one==5) {
+						val >>= 1;
+						r_one=0;
+						continue;
+					} else {
+						r_val >>= 1;
+						r_val &= 0x7f;
+						bitcnt++;
+					}
+					r_one=0;	
+				}
+				if ((state == HDLC_FRAME_FOUND) &&
+					!(bitcnt & 7)) {
+					if ((bitcnt>>3) >= bch->maxlen) {
+						mISDN_debugprint(&bch->inst, "tiger: frame too big");
+						r_val=0; 
+						state=HDLC_FLAG_SEARCH;
+						tiger->r_err++;
+#ifdef ERROR_STATISTIC
+						bcs->err_inv++;
+#endif
+					} else {
+						skb_ptr[(bitcnt>>3)-1] = r_val;
+						tiger->r_fcs = 
+							PPP_FCS (tiger->r_fcs, r_val);
+					}
+				}
+			}
+			val >>= 1;
+		}
+		tiger->r_tot++;
+	}
+	tiger->r_state = state;
+	tiger->r_one = r_one;
+	tiger->r_val = r_val;
+	tiger->r_bitcnt = bitcnt;
+}
+
+/* read_tiger()
+ *  Read tiger state and process it
+ *  - assumes lock held
+ */
+static void
+read_tiger (netjet_t *card, uint8_t irq_stat)
+{
+	u_int *p;
+	int cnt = NETJET_DMA_RXSIZE/2;
+	channel_t *bch;
+	
+	if ((irq_stat & card->last_is0) & NETJET_IRQM0_READ_MASK) {
+		printk ("netjet: tiger warn read double dma %x/%x",
+			irq_stat, card->last_is0);
+		return;
+	} else {
+		card->last_is0 &= ~NETJET_IRQM0_READ_MASK;
+		card->last_is0 |= (irq_stat & NETJET_IRQM0_READ_MASK);
+	}	
+	if (irq_stat & NETJET_IRQM0_READ_1) {
+		p = card->tiger[0].rec.dmabuf + NETJET_DMA_RXSIZE - 1;
+	} else {
+		p = card->tiger[0].rec.dmabuf + cnt - 1;
+	}
+
+	/* Note: Unhandled 56K */
+
+	bch = &card->bch[0];
+	if (test_bit(FLG_HDLC, &bch->Flags)) {
+		read_raw(bch, p, cnt);
+	}
+	if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+		read_raw_transparent(bch, p, cnt);
+	}
+
+	bch = &card->bch[1];
+	if (test_bit(FLG_HDLC, &bch->Flags)) {
+		read_raw(bch, p, cnt);
+	}
+	if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+		read_raw_transparent(bch, p, cnt);
+	}
+}
+
+
+/* write_tiger()
+ *  Update tiger state
+ *  - assumes lock held
+ */
+void
+write_tiger (netjet_t *card, uint8_t irq_stat)
+{
+	u_int *p, cnt = NETJET_DMA_TXSIZE/2;
+
+	if ((irq_stat & card->last_is0) & NETJET_IRQM0_WRITE_MASK) {
+		DPRINT ("netjet: tiger warn write double dma %x/%x",
+			irq_stat, card->last_is0);
+		DPRINT(KERN_WARNING "%s: done A\n", __FUNCTION__);
+		return;
+	} else {
+		card->last_is0 &= ~NETJET_IRQM0_WRITE_MASK;
+		card->last_is0 |= (irq_stat & NETJET_IRQM0_WRITE_MASK);
+	}	
+	if (irq_stat & NETJET_IRQM0_WRITE_1)
+		p = card->tiger[0].send.dmabuf + NETJET_DMA_TXSIZE - 1;
+	else
+		p = card->tiger[0].send.dmabuf + cnt - 1;
+
+	write_tiger_bch(&card->bch[0], p, cnt);
+	write_tiger_bch(&card->bch[1], p, cnt);
+
+}
+
+static void
+write_tiger_bch(channel_t *bch, u_int *buf, int cnt) {
+	mISDN_head_t *hh;
+
+	if (!test_bit(FLG_TRANSPARENT, &bch->Flags)
+	    && !test_bit(FLG_HDLC, &bch->Flags)) {
+		if (test_bit(FLG_TX_BUSY, &bch->Flags))
+			printk(KERN_WARNING "%s: (busy)\n", __FUNCTION__);
+		if (test_bit(FLG_TX_NEXT, &bch->Flags))
+			printk(KERN_WARNING "%s: (next)\n", __FUNCTION__);
+		return;
+	}
+
+	write_raw(bch, buf, cnt);
+
+	if (!test_bit(FLG_TX_BUSY, &bch->Flags) && test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+		bch->tx_skb = bch->next_skb;
+		bch->tx_idx = 0;
+		bch->next_skb = NULL;
+		if (bch->tx_skb) {
+			test_and_set_bit(FLG_TX_BUSY, &bch->Flags);
+			hh = mISDN_HEAD_P(bch->tx_skb);
+			queue_ch_frame(bch, CONFIRM, hh->dinfo, NULL);
+			netjet_fill_dma(bch);
+		} else {
+			//bch->tx_len = 0;
+			printk(KERN_WARNING "hdlc tx irq TX_NEXT without skb\n");
+			test_and_set_bit(FLG_TX_BUSY, &bch->Flags);
+		}
+	}
+}
+
+static irqreturn_t
+nj_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	netjet_t *card = dev_id;
+	u_int8_t val, s1val, s0val;
+
+	spin_lock(&card->lock);
+
+	s0val = inb (card->base | NETJET_IRQSTAT0);
+	s1val = inb (card->base | NETJET_IRQSTAT1);
+	if ( ((s1val & NETJET_ISACIRQ) != 0) && (s0val == 0)) {
+		/* no interrupts for us */
+		/* shared IRQ */
+		spin_unlock(&card->lock);
+		return IRQ_NONE;
+	}
+
+	card->irqcnt++;
+
+	if (!(s1val & NETJET_ISACIRQ)) {
+		val = nj_readISAC(card, ISAC_ISTA);
+		if (val) {
+			mISDN_isac_interrupt(&card->dch, val);
+			nj_writeISAC(card, ISAC_MASK, 0xFF);
+			nj_writeISAC(card, ISAC_MASK, 0x0);
+		}
+	}
+
+	if (s0val) {
+		/* write to clear */
+		outb (s0val, card->base | NETJET_IRQSTAT0);
+	}
+
+	/* set bits in sval to indicate which page is free */
+	if (inl(card->base | NETJET_DMA_WRITE_ADR) <
+	    inl(card->base | NETJET_DMA_WRITE_IRQ)) {
+		/* the 2nd write page is free */
+		s0val = 0x08;
+	} else	{
+		/* the 1st write page is free */
+		s0val = 0x04;	
+	}
+	if (inl(card->base | NETJET_DMA_READ_ADR) <
+	    inl(card->base | NETJET_DMA_READ_IRQ)) {
+		/* the 2nd read page is free */
+		s0val |= 0x02;
+	} else {
+		/* the 1st read page is free */
+		s0val |= 0x01;	
+	}
+
+	/* test if we have a DMA interrupt */
+	if (s0val != card->last_is0) {
+		if ((s0val & NETJET_IRQM0_READ_MASK) !=
+		    (card->last_is0 & NETJET_IRQM0_READ_MASK)) {
+			/* got a read dma int */
+
+			read_tiger (card, s0val);
+		}
+		if ((s0val & NETJET_IRQM0_WRITE_MASK) !=
+		    (card->last_is0 & NETJET_IRQM0_WRITE_MASK)) {
+			/* got a write dma int */
+			write_tiger (card, s0val);
+		}
+	}
+
+	spin_unlock(&card->lock);
+
+	return IRQ_HANDLED;
+}
+
+
+static int 
+nj_init_card (netjet_t *card)
+{
+	u_long		flags;
+	int ret;
+
+	spin_lock_irqsave(&card->lock, flags);
+	nj_disable_hwirq(card);
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	if (request_irq(card->irq, nj_interrupt, SA_SHIRQ, "NETjet", card)) {
+		printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
+		       card->irq);
+		return (-EIO);
+	}
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	nj_reset (card);
+	mISDN_clear_isac (&card->dch);
+
+	if ((ret=mISDN_isac_init (&card->dch))) {
+		printk(KERN_WARNING "mISDN: mISDN_isac_init failed with %d\n", ret);
+		/* XXX return or retry ? */
+		spin_unlock_irqrestore(&card->lock, flags);
+		return (-EIO);
+	}
+
+	inittiger (card);
+
+	mode_tiger(&card->bch[0], 0, -1);
+	mode_tiger(&card->bch[1], 1, -1);
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	return 0;
+}
+
+
+static void
+nj_release_card(netjet_t *card)
+{
+	u_long		flags;
+
+	nj_disable_hwirq(card);
+	spin_lock_irqsave(&card->lock, flags);
+ 	mode_tiger(&card->bch[0], 0, ISDN_PID_NONE);
+ 	mode_tiger(&card->bch[1], 1, ISDN_PID_NONE);
+	mISDN_isac_free(&card->dch);
+	spin_unlock_irqrestore(&card->lock, flags);
+	free_irq(card->irq, card);
+	spin_lock_irqsave(&card->lock, flags);
+	release_region(card->base, 256);
+	mISDN_freechannel(&card->bch[1]);
+	mISDN_freechannel(&card->bch[0]);
+	mISDN_freechannel(&card->dch);
+	spin_unlock_irqrestore(&card->lock, flags);
+	mISDN_ctrl(&card->dch.inst, MGR_UNREGLAYER | REQUEST, NULL);
+	spin_lock_irqsave(&netjet_mISDN.lock, flags);
+	list_del(&card->list);
+	spin_unlock_irqrestore(&netjet_mISDN.lock, flags);
+
+	pci_disable_device(card->pdev);
+	pci_set_drvdata(card->pdev, NULL);
+	kfree(card);
+}
+
+
+static int
+setup_netjet (netjet_t *card)
+{
+	u_int bytecnt;
+
+	bytecnt = 256; // NOTE: we use this size in release_card
+
+	if (!request_region(card->base, bytecnt, "netjet-s isdn")) {
+		printk(KERN_WARNING
+		       "mISDN: NETjet config port %#lx-%#lx already in use\n",
+		       card->base,
+		       card->base + bytecnt -1);
+		return (-EIO);
+	}
+
+	/* Register D-Channel (ISAC) callbacks */
+
+	card->dch.read_reg = &nj_readISAC;
+	card->dch.write_reg = &nj_writeISAC;
+	card->dch.read_fifo = &nj_readISACfifo;
+	card->dch.write_fifo = &nj_writeISACfifo;
+	card->dch.type = ISAC_TYPE_ISAC;
+
+	card->dch.hw = &card->isac;
+
+	return 0;
+}
+
+
+static int __devinit
+setup_instance (netjet_t *card)
+{
+	int		i, err;
+	mISDN_pid_t	pid;
+	u_long		flags;
+	
+	DPRINT(KERN_WARNING "NETJet setup_instance: protocol is %x layermask is %x\n",
+	       protocol[0], layermask[0]);
+
+	spin_lock_irqsave(&netjet_mISDN.lock, flags);
+	list_add_tail(&card->list, &netjet_mISDN.ilist);
+	spin_unlock_irqrestore(&netjet_mISDN.lock, flags);
+	card->dch.debug = debug;
+	spin_lock_init(&card->lock);
+	card->dch.inst.hwlock = &card->lock;
+	card->dch.inst.class_dev.dev = &card->pdev->dev;
+	card->dch.inst.pid.layermask = ISDN_LAYER(0);
+	card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
+	mISDN_init_instance(&card->dch.inst, &netjet_mISDN, card, mISDN_ISAC_l1hw);
+	sprintf(card->dch.inst.name, "NETJet%d", netjet_cnt+1);
+	mISDN_set_dchannel_pid(&pid, protocol[netjet_cnt], layermask[netjet_cnt]);
+	mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
+	for (i=0; i<2; i++) {
+		card->bch[i].channel = i;
+		mISDN_init_instance(&card->bch[i].inst, &netjet_mISDN, card, tiger_l2l1B);
+		card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
+		card->bch[i].inst.hwlock = &card->lock;
+		card->bch[i].inst.class_dev.dev = &card->pdev->dev;
+		card->bch[i].debug = debug;
+		sprintf(card->bch[i].inst.name, "%s B%d", card->dch.inst.name, i+1);
+		mISDN_initchannel(&card->bch[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM);
+		card->bch[i].hw = &card->tiger[i];
+	}
+	printk(KERN_DEBUG "NETJet card %p dch %p bch1 %p bch2 %p\n",
+		card, &card->dch, &card->bch[0], &card->bch[1]);
+	err = setup_netjet(card);
+	if (err) {
+		mISDN_freechannel(&card->dch);
+		mISDN_freechannel(&card->bch[1]);
+		mISDN_freechannel(&card->bch[0]);
+		spin_lock_irqsave(&netjet_mISDN.lock, flags);
+		list_del(&card->list);
+		spin_unlock_irqrestore(&netjet_mISDN.lock, flags);
+		kfree(card);
+		return(err);
+	}
+	netjet_cnt++;
+	err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &card->dch.inst);
+
+	if (err) {
+		nj_release_card(card);
+		return(err);
+	}
+	for (i=0; i<2; i++) {
+		err = mISDN_ctrl(card->dch.inst.st, MGR_NEWSTACK | REQUEST, &card->bch[i].inst);
+		if (err) {
+			printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
+			mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+			return(err);
+		}
+	}
+	err = mISDN_ctrl(card->dch.inst.st, MGR_SETSTACK | REQUEST, &pid);
+	if (err) {
+		printk(KERN_ERR  "MGR_SETSTACK REQUEST dch err(%d)\n", err);
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return(err);
+	}
+	err = nj_init_card(card);
+	if (err) {
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return(err);
+	}
+	mISDN_ctrl(card->dch.inst.st, MGR_CTRLREADY | INDICATION, NULL);
+	printk(KERN_INFO "NETJet %d cards installed\n", netjet_cnt);
+	return(0);
+}
+
+
+static int __devinit 
+nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int err = -ENOMEM;
+	int cfg;
+	netjet_t *card;
+
+	if (pdev->subsystem_vendor == PCI_VENDOR_ID_INTEL && pdev->subsystem_device == 0x0003) 
+		return -ENODEV;
+
+	if (!(card = kmalloc(sizeof(netjet_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "No kmem for netjet\n");
+		return(err);
+	}
+	memset(card, 0, sizeof(netjet_t));
+
+	card->pdev = pdev;
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		kfree(card);
+		return(err);
+	}
+
+	printk(KERN_INFO "nj_probe(mISDN): found adapter %s at %s\n",
+	       (char *) ent->driver_data, pci_name(pdev));
+
+	pci_set_master (pdev);
+
+	/* the TJ300 and TJ320 must be detected, the IRQ handling is different
+	 * unfortunately the chips use the same device ID, but the TJ320 has
+	 * the bit20 in status PCI cfg register set
+	 */
+	pci_read_config_dword(pdev, 0x04, &cfg);
+	if (cfg & 0x00100000)
+		card->subtype = NETJET_S_TJ320;
+	else
+		card->subtype = NETJET_S_TJ300;
+
+	card->base = pci_resource_start(pdev, 0);
+	card->irq = pdev->irq;
+	pci_set_drvdata(pdev, card);
+	err = setup_instance(card);
+	if (err)
+		pci_set_drvdata(pdev, NULL);
+
+	return (err);
+}
+
+
+static void __devexit nj_remove(struct pci_dev *pdev)
+{
+	netjet_t *card = pci_get_drvdata(pdev);
+	
+	if (card)
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+	else
+		printk(KERN_WARNING "%s drvdata already removed\n", __FUNCTION__);
+}
+
+static struct pci_device_id nj_pci_ids[] __devinitdata = {
+	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) "NETJet S" },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, nj_pci_ids);
+
+static struct pci_driver nj_pci_driver = {
+	name: "netjet",
+	probe: nj_probe,
+	remove: __devexit_p(nj_remove),
+	id_table: nj_pci_ids,
+};
+
+
+static int __init nj_init (void)
+{
+	int err;
+
+	printk(KERN_INFO "Traverse Tech. NETjet-S driver, revision %s\n", mISDN_getrev(netjet_rev));
+
+#ifdef MODULE
+	netjet_mISDN.owner = THIS_MODULE;
+#endif
+	spin_lock_init(&netjet_mISDN.lock);
+	INIT_LIST_HEAD(&netjet_mISDN.ilist);
+	netjet_mISDN.name = "NETjet-S";
+	netjet_mISDN.own_ctrl = nj_manager;
+	netjet_mISDN.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0;
+	netjet_mISDN.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS |
+					   ISDN_PID_L1_B_64HDLC;
+	netjet_mISDN.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS;
+
+	if ((err = mISDN_register (&netjet_mISDN))) {
+		printk(KERN_ERR "Can't register NETJet PCI error(%d)\n", err);
+		return err;
+	}
+
+	err = pci_register_driver (&nj_pci_driver);
+	if (err < 0)
+		return err;
+	
+	mISDN_module_register(THIS_MODULE);
+
+	return 0;
+}
+
+
+static void __exit nj_cleanup (void)
+{
+	int err;
+	netjet_t *card, *next;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if ((err = mISDN_unregister (&netjet_mISDN))) {
+		printk(KERN_ERR "Can't unregister NETJet PCI error(%d)\n", err);
+	}
+
+	list_for_each_entry_safe(card, next, &netjet_mISDN.ilist, list) {
+		printk(KERN_ERR "NetJet PCI card struct not empty refs %d\n",
+		       netjet_mISDN.refcnt);
+		nj_release_card(card);
+	}
+
+	pci_unregister_driver (&nj_pci_driver);
+
+}
+
+module_init (nj_init);
+module_exit (nj_cleanup);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netjet.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netjet.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/netjet.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,64 @@
+/* 
+ *
+ * NETjet common header file
+ *
+ * Author       Karsten Keil
+ * Copyright    by Karsten Keil      <keil at isdn4linux.de>
+ *              by Matt Henderson and Daniel Potts,
+ *                 Traverse Technologies P/L www.traverse.com.au
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Ported to mISDN from HiSax by Daniel Potts
+ *  
+ */
+
+#define NETJET_CTRL		0x00
+#define NETJET_DMACTRL		0x01
+#define NETJET_AUXCTRL		0x02
+#define NETJET_AUXDATA		0x03
+#define NETJET_IRQMASK0 	0x04
+#define NETJET_IRQMASK1 	0x05
+#define NETJET_IRQSTAT0 	0x06
+#define NETJET_IRQSTAT1 	0x07
+#define NETJET_DMA_READ_START	0x08
+#define NETJET_DMA_READ_IRQ	0x0c
+#define NETJET_DMA_READ_END	0x10
+#define NETJET_DMA_READ_ADR	0x14
+#define NETJET_DMA_WRITE_START	0x18
+#define NETJET_DMA_WRITE_IRQ	0x1c
+#define NETJET_DMA_WRITE_END	0x20
+#define NETJET_DMA_WRITE_ADR	0x24
+#define NETJET_PULSE_CNT	0x28
+
+#define NETJET_ISAC_OFF		0xc0
+#define NETJET_ISACIRQ		0x10
+#define NETJET_IRQM0_READ_MASK	0x0c
+#define NETJET_IRQM0_READ_1	0x04
+#define NETJET_IRQM0_READ_2	0x08
+#define NETJET_IRQM0_WRITE_MASK	0x03
+#define NETJET_IRQM0_WRITE_1	0x01
+#define NETJET_IRQM0_WRITE_2	0x02
+
+#define NETJET_HA_OFFSET	2
+#define NETJET_HA_BITS		4
+#define NETJET_HA_MASK		0xf // mask from offset
+
+#define NETJET_DMA_TXSIZE 	512 // dma buf size in 32-bit words
+#define NETJET_DMA_RXSIZE 	128 // dma buf size in 32-bit words
+
+#define HDLC_ZERO_SEARCH 	0
+#define HDLC_FLAG_SEARCH 	1
+#define HDLC_FLAG_FOUND  	2
+#define HDLC_FRAME_FOUND 	3
+#define HDLC_NULL 		4
+#define HDLC_PART 		5
+#define HDLC_FULL 		6
+
+#define HDLC_FLAG_VALUE		0x7e
+
+#define FLG_NOFRAME		26
+#define FLG_HALF		27
+#define FLG_EMPTY		28
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/plci.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/plci.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/plci.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,157 @@
+/* $Id: plci.c,v 1.12 2006/03/06 12:52:07 keil Exp $
+ *
+ */
+
+#include "m_capi.h"
+#include "dss1.h"
+#include "helper.h"
+#include "debug.h"
+
+#define plciDebug(plci, lev, fmt, args...) \
+        capidebug(lev, fmt, ## args)
+
+
+void plciInit(Controller_t *contr)
+{
+	Plci_t	*plci = contr->plcis;
+	int	i;
+
+	for (i = 0; i < contr->maxplci; i++) {
+		memset(plci, 0, sizeof(Plci_t));
+		plci->addr = ((i + 1) << 8) | contr->addr;
+		plci->l3id = MISDN_ID_NONE;
+		INIT_LIST_HEAD(&plci->AppPlcis);
+		plci->contr = contr;
+		if (contr->debug & CAPI_DBG_PLCI)
+			printk(KERN_DEBUG "%s: %p PLCI(%x) l3id(%x)\n",
+				__FUNCTION__, plci, plci->addr, plci->l3id);
+		plci++;
+	}
+}
+
+void plciHandleSetupInd(Plci_t *plci, int pr, Q931_info_t *qi)
+{
+	__u16			CIPValue;
+	Application_t		*appl;
+	AppPlci_t		*aplci;
+	struct list_head	*item, *next;
+
+	if (!qi || !plci->contr) {
+		int_error();
+		return;
+	}
+	CIPValue = q931CIPValue(qi);
+	list_for_each_safe(item, next, &plci->contr->Applications) {
+		appl = (Application_t *)item;
+		if (test_bit(APPL_STATE_RELEASE, &appl->state))
+			continue;
+		if (listenHandle(appl, CIPValue)) {
+			aplci = ApplicationNewAppPlci(appl, plci);
+			if (!aplci) {
+				int_error();
+				break;
+			}
+			AppPlci_l3l4(aplci, pr, qi);
+		}
+	}
+	if (plci->nAppl == 0) {
+		struct sk_buff *skb = mISDN_alloc_l3msg(10, MT_RELEASE_COMPLETE);
+		u_char cause[4] = {IE_CAUSE,2,0x80,0xd8}; /* incompatible destination */
+
+		if (skb) {
+			mISDN_AddvarIE(skb,cause);
+			plciL4L3(plci, CC_RELEASE_COMPLETE | REQUEST, skb);
+		}
+		ControllerReleasePlci(plci);
+	}
+}
+
+int plci_l3l4(Plci_t *plci, int pr, struct sk_buff *skb)
+{
+	AppPlci_t		*aplci;
+	Q931_info_t		*qi;
+	struct list_head	*item, *next;
+
+	if (skb->len)
+		qi = (Q931_info_t *)skb->data;
+	else
+		qi = NULL;
+	switch (pr) {
+		case CC_SETUP | INDICATION:
+			plciHandleSetupInd(plci, pr, qi);
+			break;
+		/*
+		// no extra treatment for CC_RELEASE_CR | INDICATION ! 
+		case CC_RELEASE_CR | INDICATION:
+			break;
+		*/
+		default:
+			list_for_each_safe(item, next, &plci->AppPlcis) {
+				aplci = (AppPlci_t *)item;
+				AppPlci_l3l4(aplci, pr, qi);
+			}
+			break;
+	}
+	dev_kfree_skb(skb);
+	return(0);
+}
+
+AppPlci_t *
+getAppPlci4Id(Plci_t *plci, __u16 appId) {
+	struct list_head	*item;
+	AppPlci_t		*aplci;
+
+	list_for_each(item, &plci->AppPlcis) {
+		aplci = (AppPlci_t *)item;
+		if (appId == aplci->appl->ApplId)
+			return(aplci);
+	}
+	return(NULL);
+}
+
+void plciAttachAppPlci(Plci_t *plci, AppPlci_t *aplci)
+{
+	AppPlci_t	*test = getAppPlci4Id(plci, aplci->appl->ApplId);
+
+	if (test) {
+		int_error();
+		return;
+	}
+	list_add(&aplci->head, &plci->AppPlcis);
+	plci->nAppl++;
+}
+
+void
+plciDetachAppPlci(Plci_t *plci, AppPlci_t *aplci)
+{
+	aplci->plci = NULL;
+	list_del_init(&aplci->head);
+	plci->nAppl--;
+	if (!plci->nAppl)
+		ControllerReleasePlci(plci);
+}
+
+void plciNewCrReq(Plci_t *plci)
+{
+	plciL4L3(plci, CC_NEW_CR | REQUEST, NULL);
+}
+
+int
+plciL4L3(Plci_t *plci, __u32 prim, struct sk_buff *skb)
+{
+#define	MY_RESERVE	8
+	int	err;
+
+	if (!skb) {
+		if (!(skb = alloc_skb(MY_RESERVE, GFP_ATOMIC))) {
+			printk(KERN_WARNING "%s: no skb size %d\n",
+				__FUNCTION__, MY_RESERVE);
+			return(-ENOMEM);
+		} else
+			skb_reserve(skb, MY_RESERVE);
+	}
+	err = ControllerL4L3(plci->contr, prim, plci->l3id, skb);
+	if (err)
+		dev_kfree_skb(skb);
+	return(err);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sedl_fax.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sedl_fax.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sedl_fax.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,975 @@
+/* $Id: sedl_fax.c,v 1.30 2007/02/13 10:43:45 crich Exp $
+ *
+ * sedl_fax.c  low level stuff for Sedlbauer Speedfax + cards
+ *
+ * Copyright  (C) 2000,2001 Karsten Keil (kkeil at suse.de)
+ *
+ * Author     Karsten Keil (kkeil at suse.de)
+ *
+ *
+ * Thanks to  Sedlbauer AG for informations
+ *            Marcus Niemann
+ *            Edgar Toernig
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+/* Supported cards:
+ * Card:	Chip:		Configuration:	Comment:
+ * ---------------------------------------------------------------------
+ * Speed Fax+	ISAC_ISAR	ISAPNP		Full analog support
+ * Speed Fax+ 	ISAC_ISAR	PCI PNP		Full analog support
+ *
+ * Important:
+ * For the sedlbauer speed fax+ to work properly you have to download 
+ * the firmware onto the card.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/semaphore.h>
+#ifdef NEW_ISAPNP
+#include <linux/pnp.h>
+#else
+#include <linux/isapnp.h>
+#endif
+#include "core.h"
+#include "channel.h"
+#include "isac.h"
+#include "isar.h"
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+
+extern const char *CardType[];
+
+const char *Sedlfax_revision = "$Revision: 1.30 $";
+
+const char *Sedlbauer_Types[] =
+	{"None", "speed fax+", "speed fax+ pyramid", "speed fax+ pci"};
+
+#ifndef PCI_VENDOR_ID_TIGERJET
+#define PCI_VENDOR_ID_TIGERJET		0xe159
+#endif
+#ifndef PCI_DEVICE_ID_TIGERJET_100
+#define PCI_DEVICE_ID_TIGERJET_100	0x0002
+#endif
+#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID	0x51
+#define PCI_SUBVENDOR_SPEEDFAX_PCI	0x54
+#define PCI_SUB_ID_SEDLBAUER		0x01
+ 
+#define SEDL_SPEEDFAX_ISA	1
+#define SEDL_SPEEDFAX_PYRAMID	2
+#define SEDL_SPEEDFAX_PCI	3
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define SEDL_ISA_ISAC	4
+#define SEDL_ISA_ISAR	6
+#define SEDL_ISA_ADR	8
+#define SEDL_ISA_RESET_ON	10
+#define SEDL_ISA_RESET_OFF	12
+
+#define SEDL_PCI_ADR	0xc8
+#define SEDL_PCI_ISAC	0xd0
+#define SEDL_PCI_ISAR	0xe0
+
+/* TIGER 100 Registers */
+
+#define TIGER_RESET_ADDR	0x00
+#define TIGER_EXTERN_RESET_ON	0x01
+#define TIGER_EXTERN_RESET_OFF	0x00
+#define TIGER_AUX_CTRL		0x02
+#define TIGER_AUX_DATA		0x03
+#define TIGER_AUX_IRQMASK	0x05
+#define TIGER_AUX_STATUS	0x07
+
+/* Tiger AUX BITs */
+#define SEDL_AUX_IOMASK		0xdd	/* 1 and 5 are inputs */
+#define SEDL_ISAR_RESET_BIT_OFF 0x00
+#define SEDL_ISAR_RESET_BIT_ON	0x01
+#define SEDL_TIGER_IRQ_BIT	0x02
+#define SEDL_ISAR_PCI_LED1_BIT	0x08
+#define SEDL_ISAR_PCI_LED2_BIT	0x10
+
+#define SEDL_PCI_RESET_ON	(SEDL_ISAR_RESET_BIT_ON)
+#define SEDL_PCI_RESET_OFF	(SEDL_ISAR_PCI_LED1_BIT | SEDL_ISAR_PCI_LED2_BIT)
+
+
+#define SEDL_RESET      0x3	/* same as DOS driver */
+
+/* data struct */
+
+typedef struct _sedl_fax {
+	struct list_head	list;
+	union {
+#if defined(CONFIG_PNP)
+#ifdef NEW_ISAPNP
+		struct pnp_dev		*pnp;
+#else
+		struct pci_dev		*pnp;
+#endif
+#endif
+		struct pci_dev		*pci;
+	}			dev;
+	u_int			subtyp;
+	u_int			irq;
+	u_int			irqcnt;
+	u_int			cfg;
+	u_int			addr;
+	u_int			isac;
+	u_int			isar;
+	spinlock_t		lock;
+	isar_reg_t		ir;
+	isac_chip_t		isac_hw;
+	isar_hw_t		isar_hw[2];
+	channel_t		dch;
+	channel_t		bch[2];
+} sedl_fax;
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+	byteout(ale, off);
+	return (bytein(adr));
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+	byteout(ale, off);
+	insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+	byteout(ale, off);
+	byteout(adr, data);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+	byteout(ale, off);
+	outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(void *p, u_char offset)
+{
+	return (readreg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isac, offset));
+}
+
+static void
+WriteISAC(void *p, u_char offset, u_char value)
+{
+	writereg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isac, offset, value);
+}
+
+static void
+ReadISACfifo(void *p, u_char * data, int size)
+{
+	readfifo(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(void *p, u_char * data, int size)
+{
+	writefifo(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isac, 0, data, size);
+}
+
+/* ISAR access routines
+ * mode = 0 access with IRQ on
+ * mode = 1 access with IRQ off
+ * mode = 2 access with IRQ off and using last offset
+ */
+  
+static u_char
+ReadISAR(void *p, u_char offset)
+{	
+	return (readreg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, offset));
+}
+
+static void
+WriteISAR(void *p, u_char offset, u_char value)
+{
+	writereg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, offset, value);
+}
+
+static void
+ReadISARfifo(void *p, u_char * data, int size)
+{
+	readfifo(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, ISAR_MBOX, data, size);
+}
+
+static void
+WriteISARfifo(void *p, u_char * data, int size)
+{
+	writefifo(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, ISAR_MBOX, data, size);
+}
+
+inline void
+do_sedl_interrupt(sedl_fax *sf)
+{
+	u_char val;
+	int cnt = 8;
+
+	val = readreg(sf->addr, sf->isar, ISAR_IRQBIT);
+      Start_ISAR:
+	if (val & ISAR_IRQSTA)
+		isar_int_main(&sf->bch[0]);
+	val = readreg(sf->addr, sf->isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val)
+		mISDN_isac_interrupt(&sf->dch, val);
+	val = readreg(sf->addr, sf->isar, ISAR_IRQBIT);
+	if ((val & ISAR_IRQSTA) && cnt) {
+		cnt--;
+		if (sf->dch.debug & L1_DEB_HSCX)
+			printk(KERN_DEBUG "ISAR IntStat after IntRoutine cpu%d\n",
+				smp_processor_id());
+		goto Start_ISAR;
+	}
+	val = readreg(sf->addr, sf->isac, ISAC_ISTA);
+	if (val && cnt) {
+		cnt--;
+		if (sf->dch.debug & L1_DEB_ISAC)
+			printk(KERN_DEBUG "ISAC IntStat after IntRoutine cpu%d\n",
+				smp_processor_id());
+		goto Start_ISAC;
+	}
+	if (!cnt)
+		if (sf->dch.debug & L1_DEB_ISAC)
+			printk(KERN_DEBUG "Sedlbauer IRQ LOOP\n");
+	writereg(sf->addr, sf->isar, ISAR_IRQBIT, 0);
+	writereg(sf->addr, sf->isac, ISAC_MASK, 0xFF);
+	writereg(sf->addr, sf->isac, ISAC_MASK, 0x0);
+	writereg(sf->addr, sf->isar, ISAR_IRQBIT, ISAR_IRQMSK);
+}
+
+static irqreturn_t
+speedfax_isa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	sedl_fax	*sf = dev_id;
+	
+	spin_lock(&sf->lock);
+	sf->irqcnt++;
+	do_sedl_interrupt(sf);
+	spin_unlock(&sf->lock);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+speedfax_pci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	sedl_fax	*sf = dev_id;
+	u_char		val;
+
+	spin_lock(&sf->lock);
+	val = bytein(sf->cfg + TIGER_AUX_STATUS);
+	if (val & SEDL_TIGER_IRQ_BIT) { /* for us or shared ? */
+		spin_unlock(&sf->lock);
+		return IRQ_NONE; /* shared */
+	}
+	sf->irqcnt++;
+	do_sedl_interrupt(sf);
+	spin_unlock(&sf->lock);
+	return IRQ_HANDLED;
+}
+
+static void
+enable_hwirq(sedl_fax *sf)
+{
+	WriteISAC(sf, ISAC_MASK, 0);
+	WriteISAR(sf, ISAR_IRQBIT, ISAR_IRQMSK);
+	if (sf->subtyp != SEDL_SPEEDFAX_ISA)
+		byteout(sf->cfg + TIGER_AUX_IRQMASK, SEDL_TIGER_IRQ_BIT);
+}
+
+static void
+disable_hwirq(sedl_fax *sf)
+{
+	WriteISAC(sf, ISAC_MASK, 0xFF);
+	WriteISAR(sf, ISAR_IRQBIT, 0);
+	if (sf->subtyp != SEDL_SPEEDFAX_ISA)
+		byteout(sf->cfg + TIGER_AUX_IRQMASK, 0);
+}
+
+void
+release_sedlbauer(sedl_fax *sf)
+{
+	int bytecnt = 256;
+
+	if (sf->subtyp == SEDL_SPEEDFAX_ISA)
+		bytecnt = 16;
+	if (sf->cfg)
+		release_region(sf->cfg, bytecnt);
+}
+
+static void
+reset_speedfax(sedl_fax *sf)
+{
+
+	printk(KERN_INFO "Sedlbauer: resetting card\n");
+
+	if (sf->subtyp == SEDL_SPEEDFAX_ISA) {
+		byteout(sf->cfg + SEDL_ISA_RESET_ON, SEDL_RESET);
+		mdelay(1);
+		byteout(sf->cfg + SEDL_ISA_RESET_OFF, 0);
+		mdelay(1);
+	} else {
+		byteout(sf->cfg + TIGER_RESET_ADDR, TIGER_EXTERN_RESET_ON);
+		byteout(sf->cfg + TIGER_AUX_DATA, SEDL_PCI_RESET_ON);
+		mdelay(1);
+		byteout(sf->cfg + TIGER_RESET_ADDR, TIGER_EXTERN_RESET_OFF);
+		byteout(sf->cfg + TIGER_AUX_DATA, SEDL_PCI_RESET_OFF);
+		mdelay(1);
+	}
+}
+
+static int init_card(sedl_fax *sf)
+{
+	int	cnt = 3;
+	u_long	flags;
+	u_int	shared = SA_SHIRQ;
+	void	*irq_func = speedfax_pci_interrupt;
+
+	if (sf->subtyp == SEDL_SPEEDFAX_ISA) {
+		irq_func = speedfax_isa_interrupt;
+		shared = 0;
+	}
+	if (request_irq(sf->irq, irq_func, shared, "speedfax", sf)) {
+		printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
+			sf->irq);
+		return(-EIO);
+	}
+	spin_lock_irqsave(&sf->lock, flags);
+	while (cnt) {
+		int	ret;
+
+		mISDN_clear_isac(&sf->dch);
+		if ((ret=mISDN_isac_init(&sf->dch))) {
+			printk(KERN_WARNING "mISDN: mISDN_isac_init failed with %d\n", ret);
+			break;
+		}
+		init_isar(&sf->bch[0]);
+		init_isar(&sf->bch[1]);
+		enable_hwirq(sf);
+		/* RESET Receiver and Transmitter */
+		WriteISAC(sf, ISAC_CMDR, 0x41);
+		spin_unlock_irqrestore(&sf->lock, flags);
+		current->state = TASK_UNINTERRUPTIBLE;
+		/* Timeout 10ms */
+		schedule_timeout((10*HZ)/1000);
+		printk(KERN_INFO "%s: IRQ %d count %d\n",
+			sf->dch.inst.name, sf->irq, sf->irqcnt);
+		if (!sf->irqcnt) {
+			printk(KERN_WARNING
+			       "Sedlbauer speedfax: IRQ(%d) getting no interrupts during init %d\n",
+			       sf->irq, 4 - cnt);
+			if (cnt == 1) {
+				return (-EIO);
+			} else {
+				spin_lock_irqsave(&sf->lock, flags);
+				reset_speedfax(sf);
+				cnt--;
+			}
+		} else {
+			return(0);
+		}
+	}
+	spin_unlock_irqrestore(&sf->lock, flags);
+	return(-EIO);
+}
+
+
+#define MAX_CARDS	4
+static int sedl_cnt;
+static mISDNobject_t	speedfax;
+static uint debug;
+static uint protocol[MAX_CARDS];
+static uint layermask[MAX_CARDS];
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#define MODULE_PARM_T   "1-4i"
+MODULE_PARM(protocol, MODULE_PARM_T);
+MODULE_PARM(layermask, MODULE_PARM_T);
+#else
+module_param (debug, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC (debug, "sedlfax debug mask");
+static uint protocol_num;
+static uint layermask_num;
+#ifdef OLD_MODULE_PARAM_ARRAY
+module_param_array(protocol, uint, protocol_num, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, layermask_num, S_IRUGO | S_IWUSR);
+#else
+module_param_array(protocol, uint, &protocol_num, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, &layermask_num, S_IRUGO | S_IWUSR);
+#endif
+MODULE_PARM_DESC (protocol, "sedlfax protcol (DSS1 := 2)");
+MODULE_PARM_DESC(layermask, "sedlfax layer mask");
+#endif
+#endif
+static char SpeedfaxName[] = "Speedfax";
+
+int
+setup_speedfax(sedl_fax *sf)
+{
+	int	bytecnt, ver;
+	u_long	flags;
+
+	bytecnt = (sf->subtyp == SEDL_SPEEDFAX_ISA) ? 16 : 256;
+	if (!request_region(sf->cfg, bytecnt, (sf->subtyp == SEDL_SPEEDFAX_ISA) ? "sedl PnP" : "sedl PCI")) {
+		printk(KERN_WARNING
+		       "mISDN: %s config port %x-%x already in use\n",
+		       "Speedfax +",
+		       sf->cfg,
+		       sf->cfg + bytecnt - 1);
+		return(-EIO);
+	}
+	sf->dch.read_reg = &ReadISAC;
+	sf->dch.write_reg = &WriteISAC;
+	sf->dch.read_fifo = &ReadISACfifo;
+	sf->dch.write_fifo = &WriteISACfifo;
+	sf->dch.hw = &sf->isac_hw;
+	if (sf->subtyp != SEDL_SPEEDFAX_ISA) {
+		sf->addr = sf->cfg + SEDL_PCI_ADR;
+		sf->isac = sf->cfg + SEDL_PCI_ISAC;
+		sf->isar = sf->cfg + SEDL_PCI_ISAR;
+		byteout(sf->cfg + TIGER_RESET_ADDR, 0xff);
+		mdelay(1);
+		byteout(sf->cfg + TIGER_RESET_ADDR, 0x00);
+		mdelay(1);
+		byteout(sf->cfg + TIGER_AUX_CTRL, SEDL_AUX_IOMASK);
+		byteout(sf->cfg + TIGER_AUX_IRQMASK, 0);
+		byteout(sf->cfg + TIGER_AUX_DATA, SEDL_PCI_RESET_ON);
+		mdelay(1);
+		byteout(sf->cfg + TIGER_AUX_DATA, SEDL_PCI_RESET_OFF);
+		mdelay(1);
+	} else {
+		sf->addr = sf->cfg + SEDL_ISA_ADR;
+		sf->isac = sf->cfg + SEDL_ISA_ISAC;
+		sf->isar = sf->cfg + SEDL_ISA_ISAR;
+	}
+	sf->isar_hw[0].reg = &sf->ir;
+	sf->isar_hw[1].reg = &sf->ir;
+	sf->bch[0].hw = &sf->isar_hw[0];
+	sf->bch[1].hw = &sf->isar_hw[1];
+	sf->bch[0].read_reg = &ReadISAR;
+	sf->bch[0].write_reg = &WriteISAR;
+	sf->bch[0].read_fifo = &ReadISARfifo;
+	sf->bch[0].write_fifo = &WriteISARfifo;
+	sf->bch[1].read_reg = &ReadISAR;
+	sf->bch[1].write_reg = &WriteISAR;
+	sf->bch[1].read_fifo = &ReadISARfifo;
+	sf->bch[1].write_fifo = &WriteISARfifo;
+	spin_lock_irqsave(&sf->lock, flags);
+	disable_hwirq(sf);
+	ver = ISARVersion(&sf->bch[0], "Sedlbauer:");
+	spin_unlock_irqrestore(&sf->lock, flags);
+	if (ver < 0) {
+		printk(KERN_WARNING
+			"Sedlbauer: wrong ISAR version (ret = %d)\n", ver);
+		release_sedlbauer(sf);
+		return (-EIO);
+	}
+	return (0);
+}
+
+static void
+release_card(sedl_fax *card) {
+	u_long	flags;
+
+	spin_lock_irqsave(&card->lock, flags);	
+	disable_hwirq(card);
+	spin_unlock_irqrestore(&card->lock, flags);
+	free_irq(card->irq, card);
+	spin_lock_irqsave(&card->lock, flags);
+	free_isar(&card->bch[1]);
+	free_isar(&card->bch[0]);
+	mISDN_isac_free(&card->dch);
+	release_sedlbauer(card);
+	mISDN_freechannel(&card->bch[1]);
+	mISDN_freechannel(&card->bch[0]);
+	mISDN_freechannel(&card->dch);
+	spin_unlock_irqrestore(&card->lock, flags);
+	mISDN_ctrl(&card->dch.inst, MGR_UNREGLAYER | REQUEST, NULL);
+	spin_lock_irqsave(&speedfax.lock, flags);
+	list_del(&card->list);
+	spin_unlock_irqrestore(&speedfax.lock, flags);
+	if (card->subtyp == SEDL_SPEEDFAX_ISA) {
+#if defined(CONFIG_PNP)
+		pnp_disable_dev(card->dev.pnp);
+		pnp_set_drvdata(card->dev.pnp, NULL);
+#endif
+	} else {
+		pci_disable_device(card->dev.pci);
+		pci_set_drvdata(card->dev.pci, NULL);
+	}
+	kfree(card);
+	sedl_cnt--;
+}
+
+static int
+speedfax_manager(void *data, u_int prim, void *arg) {
+	sedl_fax	*card;
+	mISDNinstance_t	*inst=data;
+	int		channel = -1;
+	struct sk_buff	*skb;
+	u_long		flags;
+
+	if (debug & MISDN_DEBUG_MANAGER)
+		printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n",
+			__FUNCTION__, data, prim, arg);
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim,arg,&speedfax)
+		printk(KERN_ERR "speedfax_manager no data prim %x arg %p\n",
+			prim, arg);
+		return(-EINVAL);
+	}
+	spin_lock_irqsave(&speedfax.lock, flags);
+	list_for_each_entry(card, &speedfax.ilist, list) {
+		if (&card->dch.inst == inst) {
+			channel = 2;
+			break;
+		}
+		if (&card->bch[0].inst == inst) {
+			channel = 0;
+			break;
+		}
+		if (&card->bch[1].inst == inst) {
+			channel = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&speedfax.lock, flags);
+	if (channel<0) {
+		printk(KERN_ERR "speedfax_manager no channel data %p prim %x arg %p\n",
+			data, prim, arg);
+		return(-EINVAL);
+	}
+	if (debug & MISDN_DEBUG_MANAGER)
+		printk(KERN_DEBUG "%s: channel %d\n", __FUNCTION__, channel);
+	switch(prim) {
+	    case MGR_REGLAYER | CONFIRM:
+		if (channel == 2)
+			mISDN_setpara(&card->dch, &inst->st->para);
+		else
+			mISDN_setpara(&card->bch[channel], &inst->st->para);
+		break;
+	    case MGR_UNREGLAYER | REQUEST:
+		if ((skb = create_link_skb(PH_CONTROL | REQUEST,
+			HW_DEACTIVATE, 0, NULL, 0))) {
+			if (channel == 2) {
+				if (mISDN_ISAC_l1hw(inst, skb))
+					dev_kfree_skb(skb);
+			} else {
+				if (isar_down(inst, skb))
+					dev_kfree_skb(skb);
+			}
+		} else
+			printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+		break;
+	    case MGR_CLRSTPARA | INDICATION:
+		arg = NULL;
+	    case MGR_ADDSTPARA | INDICATION:
+		if (channel == 2)
+			mISDN_setpara(&card->dch, arg);
+		else
+			mISDN_setpara(&card->bch[channel], arg);
+		break;
+	    case MGR_RELEASE | INDICATION:
+		if (channel == 2) {
+			release_card(card);
+		} else {
+			speedfax.refcnt--;
+		}
+		break;
+#ifdef OBSOLETE
+	    case MGR_CONNECT | REQUEST:
+		return(mISDN_ConnectIF(inst, arg));
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+		if (channel==2)
+			return(mISDN_SetIF(inst, arg, prim, mISDN_ISAC_l1hw, NULL, &card->dch));
+		else
+			return(mISDN_SetIF(inst, arg, prim, isar_down, NULL, &card->bch[channel]));
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		return(mISDN_DisConnectIF(inst, arg));
+#endif
+	    case MGR_LOADFIRM | REQUEST:
+	    	{
+			struct firm {
+				int	len;
+				void	*data;
+			} *firm = arg;
+			
+			if (!arg)
+				return(-EINVAL);
+			return(isar_load_firmware(&card->bch[0], firm->data, firm->len));
+		}
+	    case MGR_LOADFIRM | CONFIRM:
+		mISDN_ctrl(card->dch.inst.st, MGR_CTRLREADY | INDICATION, NULL);
+		break;
+	    case MGR_SETSTACK | INDICATION:
+		if ((channel!=2) && (inst->pid.global == 2)) {
+//			inst->down.fdata = &card->bch[channel];
+			if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
+				0, 0, NULL, 0))) {
+				if (isar_down(inst, skb))
+					dev_kfree_skb(skb);
+			}
+			if ((inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS) ||
+				(inst->pid.protocol[2] == ISDN_PID_L2_B_TRANSDTMF))
+				mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
+					0, 0, NULL, 0);
+			else
+				mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
+					0, 0, NULL, 0);
+		}
+		break;
+	    PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+	    PRIM_NOT_HANDLED(MGR_GLOBALOPT | REQUEST);
+	    default:
+		printk(KERN_WARNING "speedfax_manager prim %x not handled\n", prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+static int __devinit setup_instance(sedl_fax *card)
+{
+	int		i, err;
+	mISDN_pid_t	pid;
+	struct device	*dev;
+	u_long		flags;
+	
+	if (sedl_cnt >= MAX_CARDS) {
+		kfree(card);
+		return(-EINVAL);
+	}
+	if (card->subtyp == SEDL_SPEEDFAX_ISA) {
+#if defined(CONFIG_PNP)
+		dev = &card->dev.pnp->dev;
+#else
+		dev = NULL;
+#endif
+	} else {
+		dev = &card->dev.pci->dev;
+	}
+	spin_lock_irqsave(&speedfax.lock, flags);
+	list_add_tail(&card->list, &speedfax.ilist);
+	spin_unlock_irqrestore(&speedfax.lock, flags);
+	card->dch.debug = debug;
+	spin_lock_init(&card->lock);
+	card->dch.inst.hwlock = &card->lock;
+	card->dch.inst.pid.layermask = ISDN_LAYER(0);
+	card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
+	card->dch.inst.class_dev.dev = dev;
+	mISDN_init_instance(&card->dch.inst, &speedfax, card, mISDN_ISAC_l1hw);
+	sprintf(card->dch.inst.name, "SpeedFax%d", sedl_cnt+1);
+	mISDN_set_dchannel_pid(&pid, protocol[sedl_cnt], layermask[sedl_cnt]);
+	mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
+	for (i=0; i<2; i++) {
+		card->bch[i].channel = i;
+		mISDN_init_instance(&card->bch[i].inst, &speedfax, card, isar_down);
+		card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
+		card->bch[i].inst.hwlock = &card->lock;
+		card->bch[i].debug = debug;
+		card->bch[i].inst.class_dev.dev = dev;
+		sprintf(card->bch[i].inst.name, "%s B%d", card->dch.inst.name, i+1);
+		mISDN_initchannel(&card->bch[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM);
+	}
+	printk(KERN_DEBUG "sfax card %p dch %p bch1 %p bch2 %p\n",
+		card, &card->dch, &card->bch[0], &card->bch[1]);
+	err = setup_speedfax(card);
+	if (err) {
+		mISDN_freechannel(&card->dch);
+		mISDN_freechannel(&card->bch[1]);
+		mISDN_freechannel(&card->bch[0]);
+		spin_lock_irqsave(&speedfax.lock, flags);
+		list_del(&card->list);
+		spin_unlock_irqrestore(&speedfax.lock, flags);
+		kfree(card);
+		return(err);
+	}
+	sedl_cnt++;
+	err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &card->dch.inst);
+	if (err) {
+		release_card(card);
+		return(err);
+	}
+	mISDN_ctrl(card->dch.inst.st, MGR_STOPSTACK | REQUEST, NULL);
+	for (i=0; i<2; i++) {
+		err = mISDN_ctrl(card->dch.inst.st, MGR_NEWSTACK | REQUEST, &card->bch[i].inst);
+		if (err) {
+			printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
+			mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+			return(err);
+		}
+	}
+	err = mISDN_ctrl(card->dch.inst.st, MGR_SETSTACK | REQUEST, &pid);
+	if (err) {
+		printk(KERN_ERR  "MGR_SETSTACK REQUEST dch err(%d)\n", err);
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return(err);
+	}
+	err = init_card(card);
+	if (err) {
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return(err);
+	}
+	mISDN_ctrl(card->dch.inst.st, MGR_STARTSTACK | REQUEST, NULL);
+	printk(KERN_INFO "SpeedFax %d cards installed\n", sedl_cnt);
+	return(0);
+}
+
+static int __devinit sedlpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int		err = -ENOMEM;
+	sedl_fax	*card;
+
+	if (!(card = kmalloc(sizeof(sedl_fax), GFP_ATOMIC))) {
+		printk(KERN_ERR "No kmem for Speedfax + PCI\n");
+		return(err);
+	}
+	memset(card, 0, sizeof(sedl_fax));
+	card->dev.pci = pdev;
+	if (PCI_SUBVENDOR_SPEEDFAX_PYRAMID == pdev->subsystem_vendor)
+		card->subtyp = SEDL_SPEEDFAX_PYRAMID;
+	else
+		card->subtyp = SEDL_SPEEDFAX_PCI;
+	err = pci_enable_device(pdev);
+	if (err) {
+		kfree(card);
+		return(err);
+	}
+
+	printk(KERN_INFO "mISDN: sedlpci found adapter %s at %s\n",
+	       (char *) ent->driver_data, pci_name(pdev));
+
+	card->cfg = pci_resource_start(pdev, 0);
+	card->irq = pdev->irq;
+	pci_set_drvdata(pdev, card);
+	err = setup_instance(card);
+	if (err)
+		pci_set_drvdata(pdev, NULL);
+	return(err);
+}
+
+#if defined(CONFIG_PNP)
+#ifdef NEW_ISAPNP
+static int __devinit sedlpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
+#else
+static int __devinit sedlpnp_probe(struct pci_dev *pdev, const struct isapnp_device_id *dev_id)
+#endif
+{
+	int		err;
+	sedl_fax	*card;
+
+	if (!pdev)
+		return(-ENODEV);
+
+	if (!(card = kmalloc(sizeof(sedl_fax), GFP_ATOMIC))) {
+		printk(KERN_ERR "No kmem for Speedfax + PnP\n");
+		return(-ENOMEM);
+	}
+	memset(card, 0, sizeof(sedl_fax));
+	card->subtyp = SEDL_SPEEDFAX_ISA;
+	card->dev.pnp = pdev;
+	pnp_disable_dev(pdev);
+	err = pnp_activate_dev(pdev);
+	if (err<0) {
+		printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__,
+			(char *)dev_id->driver_data, err);
+		kfree(card);
+		return(err);
+	}
+	card->cfg = pnp_port_start(pdev, 0);
+	card->irq = pnp_irq(pdev, 0);
+
+	printk(KERN_INFO "mISDN: sedlpnp_probe found adapter %s at IO %#x irq %d\n",
+	       (char *)dev_id->driver_data, card->addr, card->irq);
+
+	pnp_set_drvdata(pdev, card);
+	err = setup_instance(card);
+	if (err)
+		pnp_set_drvdata(pdev, NULL);
+	return(err);
+}
+#endif /* CONFIG_PNP */
+
+static void __devexit sedl_remove_pci(struct pci_dev *pdev)
+{
+	sedl_fax	*card = pci_get_drvdata(pdev);
+
+	if (card)
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+	else
+		printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__);
+}
+
+#if defined(CONFIG_PNP)
+#ifdef NEW_ISAPNP
+static void __devexit sedl_remove_pnp(struct pnp_dev *pdev)
+#else
+static void __devexit sedl_remove_pnp(struct pci_dev *pdev)
+#endif
+{
+	sedl_fax	*card = pnp_get_drvdata(pdev);
+
+	if (card)
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+	else
+		printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__);
+}
+#endif
+
+static struct pci_device_id sedlpci_ids[] __devinitdata = {
+	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER,
+	  0, 0, (unsigned long) "Pyramid Speedfax + PCI" },
+	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER,
+	  0, 0, (unsigned long) "Sedlbauer Speedfax + PCI" },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, sedlpci_ids);
+
+static struct pci_driver sedlpci_driver = {
+	name:     "speedfax pci",
+	probe:    sedlpci_probe,
+	remove:   __devexit_p(sedl_remove_pci),
+	id_table: sedlpci_ids,
+};
+
+#if defined(CONFIG_PNP)
+#ifdef NEW_ISAPNP
+static struct pnp_device_id sedlpnp_ids[] __devinitdata = {
+	{ 
+		.id		= "SAG0002",
+		.driver_data	= (unsigned long) "Speedfax + PnP",
+	},
+};
+
+static struct pnp_driver sedlpnp_driver = {
+#else
+static struct isapnp_device_id sedlpnp_ids[] __devinitdata = {
+	{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
+	  ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02), 
+	  (unsigned long) "Speedfax + PnP" },
+	{ }
+};
+MODULE_DEVICE_TABLE(isapnp, sedlpnp_ids);
+
+static struct isapnp_driver sedlpnp_driver = {
+#endif
+	name:     "speedfax pnp",
+	probe:    sedlpnp_probe,
+	remove:   __devexit_p(sedl_remove_pnp),
+	id_table: sedlpnp_ids,
+};
+#endif /* CONFIG_PNP */
+
+static int __init Speedfax_init(void)
+{
+	int	err;
+#ifdef OLD_PCI_REGISTER_DRIVER
+	int	pci_nr_found;
+#endif
+
+#ifdef MODULE
+	speedfax.owner = THIS_MODULE;
+#endif
+	spin_lock_init(&speedfax.lock);
+	INIT_LIST_HEAD(&speedfax.ilist);
+	speedfax.name = SpeedfaxName;
+	speedfax.own_ctrl = speedfax_manager;
+	speedfax.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0;
+	speedfax.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS |
+				      ISDN_PID_L1_B_64HDLC |
+				      ISDN_PID_L1_B_T30FAX |
+				      ISDN_PID_L1_B_MODEM_ASYNC;
+	speedfax.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS |
+				      ISDN_PID_L2_B_T30;
+
+	if ((err = mISDN_register(&speedfax))) {
+		printk(KERN_ERR "Can't register Speedfax error(%d)\n", err);
+		return(err);
+	}
+	err = pci_register_driver(&sedlpci_driver);
+	if (err < 0)
+		goto out;
+#ifdef OLD_PCI_REGISTER_DRIVER
+	pci_nr_found = err;
+#endif
+#if defined(CONFIG_PNP)
+	err = pnp_register_driver(&sedlpnp_driver);
+	if (err < 0)
+		goto out_unregister_pci;
+#endif
+#ifdef OLD_PCI_REGISTER_DRIVER
+#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
+	if (pci_nr_found + err == 0) {
+		err = -ENODEV;
+		goto out_unregister_isapnp;
+	}
+#endif
+#endif
+
+	mISDN_module_register(THIS_MODULE);
+
+	return 0;
+
+#ifdef OLD_PCI_REGISTER_DRIVER
+#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
+ out_unregister_isapnp:
+#if defined(CONFIG_PNP)
+	pnp_unregister_driver(&sedlpnp_driver);
+#endif
+#endif
+#endif
+#if defined(CONFIG_PNP)
+ out_unregister_pci:
+#endif
+	pci_unregister_driver(&sedlpci_driver);
+ out:
+ 	return err;
+}
+
+static void __exit Speedfax_cleanup(void)
+{
+	int		err;
+	sedl_fax	*card, *next;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if ((err = mISDN_unregister(&speedfax))) {
+		printk(KERN_ERR "Can't unregister Speedfax PCI error(%d)\n", err);
+	}
+	list_for_each_entry_safe(card, next, &speedfax.ilist, list) {
+		printk(KERN_ERR "Speedfax PCI card struct not empty refs %d\n",
+			speedfax.refcnt);
+		release_card(card);
+	}
+#if defined(CONFIG_PNP)
+	pnp_unregister_driver(&sedlpnp_driver);
+#endif
+	pci_unregister_driver(&sedlpci_driver);
+}
+
+module_init(Speedfax_init);
+module_exit(Speedfax_cleanup);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/socket.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/socket.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/socket.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,173 @@
+/*
+
+ * socket handling, transfer, receive-process for Voice over IP
+ *
+ * Author	Andreas Eversberg (jolly at eversberg.eu)
+ *
+ * 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.
+ *
+ */
+
+
+#include <linux/vmalloc.h>
+#include <linux/in.h>
+#include <net/sock.h>
+
+#include "debug.h"
+#include "socket.h"
+#include <linux/isdn_compat.h>
+
+
+/* socket thread */
+static int
+mISDN_socket_thread(void *data)
+{
+	mISDN_socket_t *ms = (mISDN_socket_t *)data;
+
+	/* make daemon */
+	daemonize("mISDN-socket");
+	allow_signal(SIGTERM);
+
+	/* read loop */
+	while(!signal_lending(current)) {
+		ms->iov.iov_base = ms->rcvbuf;
+		ms->iov_len = sizeof(ms->rcvbuf);
+		ms->oldfs = get_fs();
+		set_fs(KERNEL_DS);
+		ms->rcvlen = sock_recvmsg(ms->socket, &ms->msg, sizeof(ms->rcvbuf), 0);
+		set_fs(oldfs);
+		if (ms->rcvlen>0) {
+			ms->func(ms, ms->pri);
+		}
+	}
+
+	/* show that we terminate */
+	ms->thread_pid = 0;
+
+	/* if we got killed, signal completion */
+	if (ms->thread_complete)
+		complete(&ms->thread_complete);
+
+	return(0);
+}
+
+/*
+ * Adds a new socket with receive process.
+ * func will be the pointer to the receive process.
+ * -> The packet information is included in the mISDN_socket_t.
+ * pri will be the private data when calling receive process.
+ * local/remote ip/port will be the tupple for sending an receiving udp data.
+ * -> local-ip must be 0 if any local ip is accepted.
+ */
+mISDN_socket_t
+*mISDN_add_socket(sock_func_t *func, void *pri, u32 local_ip, u32 remote_ip, u16 local_port, u16 remote_port)
+{
+	mISDN_socket_t *ms;
+	
+	/* alloc memory structure */
+	if (!(sm = vmalloc(sizeof(mISDN_sock_t)))) {
+		printk(KERN_ERR "%s: No memory for mISDN_sock_t.\n", __FUNCTION__);
+		return(NULL);
+	}
+	memset(ms, 0, sizeof(mISDN_sock_t));
+	ms->func = func;
+	ms->pri = pri;
+
+	/* create socket */
+	if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &ms->socket)) {
+		printk(KERN_ERR "%s: Failed to create socket.\n", __FUNCTION__);
+		mISDN_free_socket(ms);
+		return(NULL);
+	}
+
+	/* bind socket */	
+	ms->server.sin_family = AF_INET;
+	ms->server.sin_addr.s_addr = (local_ip)?local_ip:INADDR_ANY;
+	ms->server.sin_port = htons((unsigned short)local_port);
+	if (ms->socket->ops->bind(ms->socket, (struct sockaddr *)ms->server, sizeof(ms->server))) {
+		printk(KERN_ERR "%s: Failed to bind socket.\n", __FUNCTION__);
+		mISDN_free_socket(ms);
+		return(NULL);
+	}
+
+	/* check sk */
+	if (ms->socket->sk == NULL) {
+		printk(KERN_ERR "%s: socket->sk == NULL\n", __FUNCTION__);
+		return(NULL);
+	}
+	
+	/* build message */
+	ms->msg.msg_name = &ms->client;
+	ms->msg.msg_namelen = sizeof(ms->client);
+	ms->msg.msg_control = NULL;
+	ms->msg.msg_controllen = 0;
+	ms->msg.msg_iov = &ms->iov;
+	ms->msg.msg_iovlen = 1;
+
+	/* create receive process */
+	if ((ms->thread_pid = kernel_thread(mISDN_socket_thread, ms, CLONE_KERNEL)) < 0) {
+		printk(KERN_ERR "%s: Failed to create receive process.\n", __FUNCTION__);
+		mISDN_free_socket(ms);
+		return(NULL);
+	}
+}
+
+
+/*
+ * free given socket with all resources
+ */
+void
+mISDN_free_socket(mISDN_sock_t *ms)
+{
+	if (!ms)
+		return;
+
+	/* kill thread */
+	if (ms->thread_pid) {
+		DECLARE_COMPLETION(thread_complete);
+		ms->thread_complete = &thread_complete;
+		kill_proc(ms->thread_pid, SIGTERM, 0);
+		wait_for_completion(&thread_complete);
+	}
+
+	/* release socket */
+	if (ms->socket)
+		sock_release(ms->socket);
+
+	/* free memory structure */
+	vfree(sm);
+}
+
+
+/*
+ * transfer a frame via given socket
+ */
+int
+mISDN_send_socket(mISDN_sock_t *ms, u8 *buf, int len)
+{
+
+	/* send packet */
+	ms->send_iov.iov_base = ms->sndbuf;
+	ms->send_iov_len = sizeof(ms->sndbuf);
+	ms->send_oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	ms->rcvlen = sock_recvmsg(ms->socket, &ms->msg, sizeof(ms->rcvbuf), 0);
+	set_fs(oldfs);
+	if (ms->rcvlen>0) {
+		ms->func(ms, ms->pri);
+	}
+}
+
+

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/socket.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/socket.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/socket.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,39 @@
+/*
+
+ * socket handling, transfer, receive-process for Voice over IP
+ *
+ * Author	Andreas Eversberg (jolly at eversberg.eu)
+ *
+ * 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.
+ *
+ */
+
+struct _mISDN_socket_t;
+typedef void (sock_func_t)(_mISDN_socket_t *ms, void *pri);
+
+typedef struct _mISDN_socket_t {
+	sock_func_t *func;
+	void *pri;
+	int thread_pid;
+	struct completion *thread_complete;
+	struct socket *socket;
+	struct sockaddr_in server, client;
+	struct sockaddr *address;
+	struct msghdr msg;
+	struct iovec iov;
+	mm_segment_t oldfs;
+	u8 rcvbuf[1500]; 
+	int rcvlen;
+} mISDN_socket_t;

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/stack.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/stack.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/stack.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1344 @@
+/* $Id: stack.c,v 1.21 2006/10/09 12:51:33 crich Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include "core.h"
+
+static LIST_HEAD(mISDN_stacklist);
+static rwlock_t	stacklist_lock = RW_LOCK_UNLOCKED;
+static LIST_HEAD(mISDN_instlist);
+static rwlock_t	instlist_lock = RW_LOCK_UNLOCKED;
+
+int
+get_stack_cnt(void)
+{
+	int cnt = 0;
+	mISDNstack_t *st;
+
+	read_lock(&stacklist_lock);
+	list_for_each_entry(st, &mISDN_stacklist, list)
+		cnt++;
+	read_unlock(&stacklist_lock);
+	return(cnt);
+}
+
+void
+get_stack_info(struct sk_buff *skb)
+{
+	mISDN_head_t	*hp;
+	mISDNstack_t	*cst, *st;
+	stack_info_t	*si;
+	int		i;
+
+	hp = mISDN_HEAD_P(skb);
+	if (hp->addr == 0) {
+		hp->dinfo = get_stack_cnt();
+		hp->len = 0;
+		return;
+	} else if (hp->addr <= 127 && hp->addr <= get_stack_cnt()) {
+		/* stack nr */
+		i = 1;
+		read_lock(&stacklist_lock);
+		list_for_each_entry(st, &mISDN_stacklist, list) {
+			if (i == hp->addr)
+				break;
+			i++;
+		}
+		read_unlock(&stacklist_lock);
+	} else
+		st = get_stack4id(hp->addr);
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s: addr(%08x) st(%p) id(%08x)\n", __FUNCTION__, hp->addr, st,
+			st ? st->id : 0);
+	if (!st) {
+		hp->len = -ENODEV;
+		return;
+	} else {
+		si = (stack_info_t *)skb->data;
+		memset(si, 0, sizeof(stack_info_t));
+		si->id = st->id;
+		si->extentions = st->extentions;
+		if (st->mgr)
+			si->mgr = st->mgr->id;
+		else
+			si->mgr = 0;
+		memcpy(&si->pid, &st->pid, sizeof(mISDN_pid_t));
+		memcpy(&si->para, &st->para, sizeof(mISDN_stPara_t));
+		if (st->clone)
+			si->clone = st->clone->id;
+		else
+			si->clone = 0;
+		if (st->master)
+			si->master = st->master->id;
+		else
+			si->master = 0;
+		si->instcnt = 0;
+		for (i = 0; i <= MAX_LAYER_NR; i++) {
+			if (st->i_array[i]) {
+				si->inst[si->instcnt] = st->i_array[i]->id;
+				si->instcnt++;
+			}
+		}
+		si->childcnt = 0;
+		list_for_each_entry(cst, &st->childlist, list) {
+			si->child[si->childcnt] = cst->id;
+			si->childcnt++;
+		}
+		hp->len = sizeof(stack_info_t);
+		if (si->childcnt>2)
+			hp->len += (si->childcnt-2)*sizeof(int);
+	}
+	skb_put(skb, hp->len);
+}
+
+static int
+get_free_stackid(mISDNstack_t *mst, int flag)
+{
+	u_int		id = 0, found;
+	mISDNstack_t	*st;
+
+	if (!mst) {
+		while(id < STACK_ID_MAX) {
+			found = 0;
+			id += STACK_ID_INC;
+			read_lock(&stacklist_lock);
+			list_for_each_entry(st, &mISDN_stacklist, list) {
+				if (st->id == id) {
+					found++;
+					break;
+				}
+			}
+			read_unlock(&stacklist_lock);
+			if (!found)
+				return(id);
+		}
+	} else if (flag & FLG_CLONE_STACK) {
+		id = mst->id | FLG_CLONE_STACK;
+		while(id < CLONE_ID_MAX) {
+			found = 0;
+			id += CLONE_ID_INC;
+			st = mst->clone;
+			while (st) {
+				if (st->id == id) {
+					found++;
+					break;
+				}
+				st = st->clone;
+			}
+			if (!found)
+				return(id);
+		}
+	} else if (flag & FLG_CHILD_STACK) {
+		id = mst->id | FLG_CHILD_STACK;
+		while(id < CHILD_ID_MAX) {
+			id += CHILD_ID_INC;
+			found = 0;
+			list_for_each_entry(st, &mst->childlist, list) {
+				if (st->id == id) {
+					found++;
+					break;
+				}
+			}
+			if (!found)
+				return(id);
+		}
+	}
+	return(0);
+}
+
+mISDNstack_t *
+get_stack4id(u_int id)
+{
+	mISDNstack_t *cst, *st;
+
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "get_stack4id(%x)\n", id);
+	if (!id) /* 0 isn't a valid id */
+		return(NULL);
+	read_lock(&stacklist_lock);
+	list_for_each_entry(st, &mISDN_stacklist, list) {
+		if (id == st->id) {
+			read_unlock(&stacklist_lock);
+			return(st);
+		}
+		if ((id & FLG_CHILD_STACK) && ((id & MASTER_ID_MASK) == st->id)) {
+			list_for_each_entry(cst, &st->childlist, list) {
+				if (cst->id == id) {
+					read_unlock(&stacklist_lock);
+					return(cst);
+				}
+			}
+		}
+		if ((id & FLG_CLONE_STACK) && ((id & MASTER_ID_MASK) == st->id)) {
+			cst = st->clone;
+			while (cst) {
+				if (cst->id == id) {
+					read_unlock(&stacklist_lock);
+					return(cst);
+				}
+				cst = cst->clone;
+			}
+		}
+	}
+	read_unlock(&stacklist_lock);
+	return(NULL);
+}
+
+mISDNinstance_t *
+getlayer4lay(mISDNstack_t *st, int layermask)
+{
+	int	i;
+
+	if (!st) {
+		int_error();
+		return(NULL);
+	}
+	for (i = 0; i <= MAX_LAYER_NR; i++) {
+		if (st->i_array[i] && (st->i_array[i]->pid.layermask & layermask))
+			return(st->i_array[i]);
+	}
+	return(NULL);
+}
+
+static mISDNinstance_t *
+get_nextlayer(mISDNstack_t *st, u_int addr)
+{
+	mISDNinstance_t	*inst=NULL;
+	int		layer = addr & LAYER_ID_MASK;
+
+	if (!(addr & FLG_MSG_TARGET)) {
+		switch(addr & MSG_DIR_MASK) {
+			case FLG_MSG_DOWN:
+				if (addr & FLG_MSG_CLONED) {
+					/* OK */
+				} else
+					layer -= LAYER_ID_INC;
+				break;
+			case FLG_MSG_UP:
+				if (addr & FLG_MSG_CLONED) {
+					/* OK */
+				} else
+					layer += LAYER_ID_INC;
+				break;
+			case MSG_TO_OWNER:
+				break;
+			default: /* broadcast */
+				int_errtxt("st(%08x) addr(%08x) wrong address", st->id, addr);
+				return(NULL);
+		}
+	}
+	if ((layer < 0) || (layer > MAX_LAYER_NR)) {
+		int_errtxt("st(%08x) addr(%08x) layer %d out of range", st->id, addr, layer);
+		return(NULL);
+	}
+	inst = st->i_array[layer];
+	if (core_debug & DEBUG_QUEUE_FUNC)
+		printk(KERN_DEBUG "%s: st(%08x) addr(%08x) -> inst(%08x)\n",
+			__FUNCTION__, st->id, addr, inst ? inst->id : 0);
+	return(inst);
+}
+
+mISDNinstance_t *
+get_instance(mISDNstack_t *st, int layer_nr, int protocol)
+{
+	mISDNinstance_t	*inst=NULL;
+	int		i;
+
+	if (!st) {
+		int_error();
+		return(NULL);
+	}
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "get_instance st(%08x) lnr(%d) prot(%x)\n",
+			st->id, layer_nr, protocol);
+	if ((layer_nr < 0) || (layer_nr > MAX_LAYER_NR)) {
+		int_errtxt("lnr %d", layer_nr);
+		return(NULL);
+	}
+	list_for_each_entry(inst, &st->prereg, list) {
+		if (core_debug & DEBUG_CORE_FUNC)
+			printk(KERN_DEBUG "get_instance prereg(%p, %x) lm %x/%x prot %x/%x\n",
+				inst, inst->id, inst->pid.layermask, ISDN_LAYER(layer_nr),
+				inst->pid.protocol[layer_nr], protocol);
+		if ((inst->pid.layermask & ISDN_LAYER(layer_nr)) &&
+			(inst->pid.protocol[layer_nr] == protocol)) {
+			i = register_layer(st, inst);
+			if (i) {
+				int_errtxt("error(%d) register preregistered inst(%08x) on st(%08x)", i, inst->id, st->id);
+				return(NULL);
+			}
+			return(inst);
+		}
+	}
+	for (i = 0; i <= MAX_LAYER_NR; i++) {
+		if ((inst = st->i_array[i])) {
+			if (core_debug & DEBUG_CORE_FUNC)
+				printk(KERN_DEBUG "get_instance inst%d(%p, %x) lm %x/%x prot %x/%x\n",
+					i,inst, inst->id, inst->pid.layermask, ISDN_LAYER(layer_nr),
+					inst->pid.protocol[layer_nr], protocol);
+			if ((inst->pid.layermask & ISDN_LAYER(layer_nr)) &&
+				(inst->pid.protocol[layer_nr] == protocol))
+				return(inst);
+		}
+	}
+	return(NULL);
+}
+
+mISDNinstance_t *
+get_instance4id(u_int id)
+{
+	mISDNinstance_t *inst;
+
+	read_lock(&instlist_lock);
+	list_for_each_entry(inst, &mISDN_instlist, list)
+		if (inst->id == id) {
+			read_unlock(&instlist_lock);
+			return(inst);
+		}
+	read_unlock(&instlist_lock);
+	return(NULL);
+}
+
+#ifdef OBSOLETE
+int
+get_layermask(mISDNlayer_t *layer)
+{
+	int mask = 0;
+
+	if (layer->inst)
+		mask |= layer->inst->pid.layermask;
+	return(mask);
+}
+
+int
+insertlayer(mISDNstack_t *st, mISDNlayer_t *layer, int layermask)
+{
+	mISDNlayer_t *item;
+
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s(%p, %p, %x)\n",
+			__FUNCTION__, st, layer, layermask);
+	if (!st || !layer) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (list_empty(&st->layerlist)) {
+		list_add(&layer->list, &st->layerlist);
+	} else {
+		list_for_each_entry(item, &st->layerlist, list) {
+			if (layermask < get_layermask(item)) {
+				list_add_tail(&layer->list, &item->list);
+				return(0);
+			}
+		}
+		list_add_tail(&layer->list, &st->layerlist);
+	}
+	return(0);
+}
+#endif
+
+inline void
+_queue_message(mISDNstack_t *st, struct sk_buff *skb)
+{
+	skb_queue_tail(&st->msgq, skb);
+	if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) {
+		test_and_set_bit(mISDN_STACK_WORK, &st->status);
+		wake_up_interruptible(&st->workq);
+	}
+}
+
+int
+mISDN_queue_message(mISDNinstance_t *inst, u_int aflag, struct sk_buff *skb)
+{
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	mISDNstack_t	*st = inst->st;
+	u_int		id;
+
+	if (core_debug & DEBUG_QUEUE_FUNC)
+		printk(KERN_DEBUG "%s(%08x, %x, prim(%x))\n", __FUNCTION__,
+			inst->id, aflag, hh->prim);
+	if (aflag & FLG_MSG_TARGET) {
+		id = aflag;
+	} else {
+		id = (inst->id & INST_ID_MASK) | aflag;
+	}
+	if ((aflag & MSG_DIR_MASK) == FLG_MSG_DOWN) {
+		if (inst->parent) {
+			inst = inst->parent;
+			st = inst->st;
+			id = (inst->id & INST_ID_MASK) | FLG_MSG_TARGET | FLG_MSG_CLONED | FLG_MSG_DOWN;
+		}
+	}
+	if (!st)
+		return(-EINVAL);
+	if (st->id == 0 || test_bit(mISDN_STACK_ABORT, &st->status))
+		return(-EBUSY);
+	if (inst->id == 0) { /* instance is not initialised */
+		if (!(aflag & FLG_MSG_TARGET)) {
+			id &= INST_ID_MASK;
+			id |= (st->id & INST_ID_MASK) | aflag | FLG_INSTANCE;
+		}
+	}
+	if (test_bit(mISDN_STACK_KILLED, &st->status))
+		return(-EBUSY);
+	if ((st->id & STACK_ID_MASK) != (id & STACK_ID_MASK)) {
+		int_errtxt("stack id not match st(%08x) id(%08x) inst(%08x) aflag(%08x) prim(%x)",
+			st->id, id, inst->id, aflag, hh->prim);
+	}
+	hh->addr = id;
+	_queue_message(st, skb);
+	return(0);
+}
+
+static void
+do_broadcast(mISDNstack_t *st, struct sk_buff *skb)
+{
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	mISDNinstance_t	*inst = NULL;
+	struct sk_buff	*c_skb = NULL;
+	int i, err;
+
+	for(i=0; i<=MAX_LAYER_NR; i++) {
+		if (i == (hh->addr & LAYER_ID_MASK))
+			continue; // skip own layer
+		inst = st->i_array[i];
+		if (!inst)
+			continue;  // maybe we have a gap
+		if (!c_skb)
+			c_skb = skb_copy(skb, GFP_KERNEL);  // we need a new private copy
+		if (!c_skb)
+			break;  // stop here when copy not possible
+
+		if (core_debug & DEBUG_MSG_THREAD_INFO)
+			printk(KERN_DEBUG "%s: inst(%08x) msg call addr(%08x) prim(%x)\n",
+				__FUNCTION__, inst->id, hh->addr, hh->prim);
+
+		if (inst->function) {
+			err = inst->function(inst, c_skb);
+			if (!err)
+				c_skb = NULL; /* function consumed the skb */
+			if (core_debug & DEBUG_MSG_THREAD_INFO)
+				printk(KERN_DEBUG "%s: inst(%08x) msg call return %d\n",
+					__FUNCTION__, inst->id, err);
+
+		} else {
+			if (core_debug & DEBUG_MSG_THREAD_ERR)
+				printk(KERN_DEBUG "%s: instance(%08x) no function\n",
+					__FUNCTION__, inst->id);
+		}
+	}
+	if (c_skb)
+		dev_kfree_skb(c_skb);
+	dev_kfree_skb(skb);
+}
+
+static void
+release_layers(mISDNstack_t *st, u_int prim)
+{
+	int	i;
+
+	for (i = 0; i <= MAX_LAYER_NR; i++) {
+		if (st->i_array[i]) {
+			if (core_debug & DEBUG_CORE_FUNC)
+				printk(KERN_DEBUG  "%s: st(%p) inst%d(%p):%x %s lm(%x)\n",
+					__FUNCTION__, st, i, st->i_array[i], st->i_array[i]->id,
+					st->i_array[i]->name, st->i_array[i]->pid.layermask);
+			st->i_array[i]->obj->own_ctrl(st->i_array[i], prim, NULL);
+		}
+	}
+}
+
+static void
+do_clear_stack(mISDNstack_t *st) {
+
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s: st(%08x)\n", __FUNCTION__, st->id);
+	kfree(st->pid.pbuf);
+	memset(&st->pid, 0, sizeof(mISDN_pid_t));
+	memset(&st->para, 0, sizeof(mISDN_stPara_t));
+	release_layers(st, MGR_UNREGLAYER | REQUEST);
+}
+
+static int
+mISDNStackd(void *data)
+{
+	mISDNstack_t	*st = data;
+	int		err = 0;
+
+#ifdef CONFIG_SMP
+	lock_kernel();
+#endif
+	MAKEDAEMON("mISDNStackd");
+	sigfillset(&current->blocked);
+	st->thread = current;
+#ifdef CONFIG_SMP
+	unlock_kernel();
+#endif
+	if ( core_debug & DEBUG_THREADS)
+		printk(KERN_DEBUG "mISDNStackd started for id(%08x)\n", st->id);
+
+	for (;;) {
+		struct sk_buff	*skb, *c_skb;
+		mISDN_head_t	*hh;
+		
+		if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) {
+			test_and_clear_bit(mISDN_STACK_WORK, &st->status);
+			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
+		} else
+			test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
+		while (test_bit(mISDN_STACK_WORK, &st->status)) {
+			mISDNinstance_t	*inst;
+
+			skb = skb_dequeue(&st->msgq);
+			if (!skb) {
+				test_and_clear_bit(mISDN_STACK_WORK, &st->status);
+				/* test if a race happens */
+				if (!(skb = skb_dequeue(&st->msgq)))
+					continue;
+				test_and_set_bit(mISDN_STACK_WORK, &st->status);
+			}
+#ifdef MISDN_MSG_STATS
+			st->msg_cnt++;
+#endif
+			hh = mISDN_HEAD_P(skb);
+			if (hh->prim == (MGR_CLEARSTACK | REQUEST)) {
+				mISDN_headext_t	*hhe = (mISDN_headext_t *)hh;
+
+				if (test_and_set_bit(mISDN_STACK_CLEARING, &st->status)) {
+					int_errtxt("double clearing");
+				}
+				if (hhe->data[0]) {
+					if (st->notify) {
+						int_errtxt("notify already set");
+						up(st->notify);
+					}
+					st->notify = hhe->data[0];
+				}
+				dev_kfree_skb(skb);
+				continue;
+			}
+			if ((hh->addr & MSG_DIR_MASK) == MSG_BROADCAST) {
+				do_broadcast(st, skb);
+				continue;
+			}
+			inst = get_nextlayer(st, hh->addr);
+			if (!inst) {
+				if (core_debug & DEBUG_MSG_THREAD_ERR)
+					printk(KERN_DEBUG "%s: st(%08x) no instance for addr(%08x) prim(%x) dinfo(%x)\n",
+						__FUNCTION__, st->id, hh->addr, hh->prim, hh->dinfo);
+				dev_kfree_skb(skb);
+				continue;
+			}
+			if (inst->clone && ((hh->addr & MSG_DIR_MASK) == FLG_MSG_UP)) {
+				u_int	id = (inst->clone->id & INST_ID_MASK) | FLG_MSG_TARGET | FLG_MSG_CLONED | FLG_MSG_UP;
+
+#ifdef MISDN_MSG_STATS
+				st->clone_cnt++;
+#endif
+				c_skb = skb_copy(skb, GFP_KERNEL);
+				if (c_skb) {
+					if (core_debug & DEBUG_MSG_THREAD_INFO)
+						printk(KERN_DEBUG "%s: inst(%08x) msg clone msg to(%08x) caddr(%08x) prim(%x)\n",
+							__FUNCTION__, inst->id, inst->clone->id, id, hh->prim);
+					err = mISDN_queue_message(inst->clone, id, c_skb);
+					if (err) {
+						if (core_debug & DEBUG_MSG_THREAD_ERR)
+							printk(KERN_DEBUG "%s: clone instance(%08x) cannot queue msg(%08x) err(%d)\n",
+								__FUNCTION__, inst->clone->id, id, err);
+						dev_kfree_skb(c_skb);
+					}
+				} else {
+					printk(KERN_WARNING "%s OOM on msg cloning inst(%08x) caddr(%08x) prim(%x) len(%d)\n",
+						__FUNCTION__, inst->id, id, hh->prim, skb->len);
+				}
+			}
+			if (core_debug & DEBUG_MSG_THREAD_INFO)
+				printk(KERN_DEBUG "%s: inst(%08x) msg call addr(%08x) prim(%x)\n",
+					__FUNCTION__, inst->id, hh->addr, hh->prim);
+			if (!inst->function) {
+				if (core_debug & DEBUG_MSG_THREAD_ERR)
+					printk(KERN_DEBUG "%s: instance(%08x) no function\n",
+						__FUNCTION__, inst->id);
+				dev_kfree_skb(skb);
+				continue;
+			}
+			err = inst->function(inst, skb);
+			if (err) {
+				if (core_debug & DEBUG_MSG_THREAD_ERR)
+					printk(KERN_DEBUG "%s: instance(%08x)->function return(%d)\n",
+						__FUNCTION__, inst->id, err);
+				dev_kfree_skb(skb);
+				continue;
+			}
+			if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) {
+				test_and_clear_bit(mISDN_STACK_WORK, &st->status);
+				test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
+				break;
+			}
+		}
+		if (test_bit(mISDN_STACK_CLEARING, &st->status)) {
+			test_and_set_bit(mISDN_STACK_STOPPED, &st->status);
+			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
+			do_clear_stack(st);
+			test_and_clear_bit(mISDN_STACK_CLEARING, &st->status);
+			test_and_set_bit(mISDN_STACK_RESTART, &st->status);
+		}
+		if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) {
+			test_and_clear_bit(mISDN_STACK_STOPPED, &st->status);
+			test_and_set_bit(mISDN_STACK_RUNNING, &st->status);
+			if (!skb_queue_empty(&st->msgq))
+				test_and_set_bit(mISDN_STACK_WORK, &st->status);
+		}
+		if (test_bit(mISDN_STACK_ABORT, &st->status))
+			break;
+		if (st->notify != NULL) {
+			up(st->notify);
+			st->notify = NULL;
+		}
+#ifdef MISDN_MSG_STATS
+		st->sleep_cnt++;
+#endif
+		test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
+		wait_event_interruptible(st->workq, (st->status & mISDN_STACK_ACTION_MASK));
+		if (core_debug & DEBUG_MSG_THREAD_INFO)
+			printk(KERN_DEBUG "%s: %08x wake status %08lx\n", __FUNCTION__, st->id, st->status);
+		test_and_set_bit(mISDN_STACK_ACTIVE, &st->status);
+
+		test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status);
+
+		if (test_bit(mISDN_STACK_STOPPED, &st->status)) {
+			test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
+#ifdef MISDN_MSG_STATS
+			st->stopped_cnt++;
+#endif
+		}
+	}
+#ifdef MISDN_MSG_STATS
+	printk(KERN_DEBUG "mISDNStackd daemon for id(%08x) proceed %d msg %d clone %d sleep %d stopped\n",
+		st->id, st->msg_cnt, st->clone_cnt, st->sleep_cnt, st->stopped_cnt);
+	printk(KERN_DEBUG "mISDNStackd daemon for id(%08x) utime(%ld) stime(%ld)\n", st->id, st->thread->utime, st->thread->stime);
+	printk(KERN_DEBUG "mISDNStackd daemon for id(%08x) nvcsw(%ld) nivcsw(%ld)\n", st->id, st->thread->nvcsw, st->thread->nivcsw);
+	printk(KERN_DEBUG "mISDNStackd daemon for id(%08x) killed now\n", st->id);
+#endif
+	test_and_set_bit(mISDN_STACK_KILLED, &st->status);
+	test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
+	test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status);
+	test_and_clear_bit(mISDN_STACK_ABORT, &st->status);
+	discard_queue(&st->msgq);
+	st->thread = NULL;
+	if (st->notify != NULL) {
+		up(st->notify);
+		st->notify = NULL;
+	}
+	return(0);
+}
+
+int
+mISDN_start_stack_thread(mISDNstack_t *st)
+{
+	int	err = 0;
+
+	if (st->thread == NULL && test_bit(mISDN_STACK_KILLED, &st->status)) {
+		test_and_clear_bit(mISDN_STACK_KILLED, &st->status);
+		kernel_thread(mISDNStackd, (void *)st, 0);
+	} else
+		err = -EBUSY;
+	return(err);
+}
+
+mISDNstack_t *
+new_stack(mISDNstack_t *master, mISDNinstance_t *inst)
+{
+	mISDNstack_t	*newst;
+	int		err;
+	u_long		flags;
+
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "create %s stack inst(%p)\n",
+			master ? "child" : "master", inst);
+	if (!(newst = kmalloc(sizeof(mISDNstack_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc mISDN_stack failed\n");
+		return(NULL);
+	}
+	memset(newst, 0, sizeof(mISDNstack_t));
+	INIT_LIST_HEAD(&newst->list);
+	INIT_LIST_HEAD(&newst->childlist);
+	INIT_LIST_HEAD(&newst->prereg);
+	init_waitqueue_head(&newst->workq);
+	skb_queue_head_init(&newst->msgq);
+	if (!master) {
+		if (inst && inst->st) {
+			master = inst->st;
+			while(master->clone)
+				master = master->clone;
+			newst->id = get_free_stackid(inst->st, FLG_CLONE_STACK);
+			newst->master = master;
+			master->clone = newst;
+			master = NULL;
+		} else {
+			newst->id = get_free_stackid(NULL, 0);
+		}
+	} else {
+		newst->id = get_free_stackid(master, FLG_CHILD_STACK);
+	}
+	newst->mgr = inst;
+	if (master) {
+		list_add_tail(&newst->list, &master->childlist);
+		newst->parent = master;
+	} else if (!(newst->id & FLG_CLONE_STACK)) {
+		write_lock_irqsave(&stacklist_lock, flags);
+		list_add_tail(&newst->list, &mISDN_stacklist);
+		write_unlock_irqrestore(&stacklist_lock, flags);
+	}
+	if (inst) {
+		inst->st = newst;
+	}
+	err = mISDN_register_sysfs_stack(newst);
+	if (err) {
+		// FIXME error handling
+		printk(KERN_ERR "Stack id %x not registered in sysfs\n", newst->id);
+	}
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "Stack id %x added\n", newst->id);
+	kernel_thread(mISDNStackd, (void *)newst, 0);
+	return(newst);
+}
+
+int
+mISDN_start_stop(mISDNstack_t *st, int start)
+{
+	int	ret;
+
+	if (start) {
+		ret = test_and_clear_bit(mISDN_STACK_STOPPED, &st->status);
+		test_and_set_bit(mISDN_STACK_WAKEUP, &st->status);
+		if (!skb_queue_empty(&st->msgq))
+			test_and_set_bit(mISDN_STACK_WORK, &st->status);
+		wake_up_interruptible(&st->workq);
+	} else
+		ret = test_and_set_bit(mISDN_STACK_STOPPED, &st->status);
+	return(ret);
+}
+
+int
+do_for_all_layers(void *data, u_int prim, void *arg)
+{
+	mISDNstack_t	*st = data;
+	int		i;
+
+	if (!st) {
+		int_error();
+		return(-EINVAL);
+	}
+	for (i = 0; i <= MAX_LAYER_NR; i++) {
+		if (st->i_array[i]) {
+			if (core_debug & DEBUG_CORE_FUNC)
+				printk(KERN_DEBUG  "%s: st(%p) inst%d(%p):%x %s prim(%x) arg(%p)\n",
+					__FUNCTION__, st, i, st->i_array[i], st->i_array[i]->id,
+					st->i_array[i]->name, prim, arg);
+			st->i_array[i]->obj->own_ctrl(st->i_array[i], prim, arg);
+		}
+	}
+	return(0);
+}
+
+int
+change_stack_para(mISDNstack_t *st, u_int prim, mISDN_stPara_t *stpara)
+{
+	int	changed = 0;
+	if (!st) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (prim == (MGR_ADDSTPARA | REQUEST)) {
+		if (!stpara) {
+			int_error();
+			return(-EINVAL);
+		}
+		prim = MGR_ADDSTPARA | INDICATION;
+		if (stpara->maxdatalen > 0 && stpara->maxdatalen < st->para.maxdatalen) {
+			changed++;
+			st->para.maxdatalen = stpara->maxdatalen;
+		}
+		if (stpara->up_headerlen > st->para.up_headerlen) {
+			changed++;
+			st->para.up_headerlen = stpara->up_headerlen;
+		}
+		if (stpara->down_headerlen > st->para.down_headerlen) {
+			changed++;
+			st->para.down_headerlen = stpara->down_headerlen;
+		}
+		if (!changed)
+			return(0);
+		stpara = &st->para;
+	} else if (prim == (MGR_CLRSTPARA | REQUEST)) {
+		prim = MGR_CLRSTPARA | INDICATION;
+		memset(&st->para, 0, sizeof(mISDN_stPara_t));
+		stpara = NULL;
+	}
+	return(do_for_all_layers(st, prim, stpara));
+}
+
+static int
+delete_stack(mISDNstack_t *st)
+{
+	DECLARE_MUTEX_LOCKED(sem);
+	u_long	flags;
+
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s: st(%p:%08x)\n", __FUNCTION__, st, st->id);
+	mISDN_unregister_sysfs_st(st);
+	if (st->parent)
+		st->parent = NULL;
+	if (!list_empty(&st->prereg)) {
+		mISDNinstance_t	*inst, *ni;
+
+		int_errtxt("st(%08x)->prereg not empty\n", st->id);
+		list_for_each_entry_safe(inst, ni, &st->prereg, list) {
+			int_errtxt("inst(%p:%08x) preregistered", inst, inst->id);
+			list_del(&inst->list);
+		}
+	}
+	if (st->thread) {
+		if (st->thread != current) {
+			if (st->notify) {
+				int_error();
+				up(st->notify);
+			}
+			st->notify = &sem;
+		}
+		test_and_set_bit(mISDN_STACK_ABORT, &st->status);
+		mISDN_start_stop(st, 1);
+		if (st->thread != current) /* we cannot wait for us */
+			down(&sem);
+	}
+	release_layers(st, MGR_RELEASE | INDICATION);
+	// FIXME dirty
+	test_and_set_bit(mISDN_STACK_DELETED, &st->status);
+	write_lock_irqsave(&stacklist_lock, flags);
+	list_del(&st->list);
+	write_unlock_irqrestore(&stacklist_lock, flags);
+	kfree(st);
+	return(0);
+}
+
+int
+release_stack(mISDNstack_t *st) {
+	int err;
+	mISDNstack_t *cst, *nst;
+
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s: st(%p)\n", __FUNCTION__, st);
+
+	// FIXME dirty
+	if (test_bit(mISDN_STACK_DELETED, &st->status)) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	list_for_each_entry_safe(cst, nst, &st->childlist, list) {
+		if ((err = delete_stack(cst))) {
+			return(err);
+		}
+	}
+	if (st->clone) {
+		st->clone->master = st->master;
+	}
+	if (st->master) {
+		st->master->clone = st->clone;
+	} else if (st->clone) { /* no master left -> delete clone too */
+		delete_stack(st->clone);
+		st->clone = NULL;
+	}
+	if ((err = delete_stack(st)))
+		return(err);
+
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s: mISDN_stacklist(%p<-%p->%p)\n", __FUNCTION__,
+			mISDN_stacklist.prev, &mISDN_stacklist, mISDN_stacklist.next);
+	return(0);
+}
+
+void
+cleanup_object(mISDNobject_t *obj)
+{
+	mISDNstack_t	*st, *nst;
+	mISDNinstance_t	*inst;
+	int		i;
+
+	read_lock(&stacklist_lock);
+	list_for_each_entry_safe(st, nst, &mISDN_stacklist, list) {
+		for (i = 0; i < MAX_LAYER_NR; i++) {
+			inst = st->i_array[i];
+			if (inst && inst->obj == obj) {
+				read_unlock(&stacklist_lock);
+				inst->obj->own_ctrl(st, MGR_RELEASE | INDICATION, inst);
+				read_lock(&stacklist_lock);
+			}
+		}
+	}
+	read_unlock(&stacklist_lock);
+}
+
+void
+check_stacklist(void)
+{
+	mISDNstack_t	*st, *nst;
+
+	read_lock(&stacklist_lock);
+	if (!list_empty(&mISDN_stacklist)) {
+		printk(KERN_WARNING "mISDNcore mISDN_stacklist not empty\n");
+		list_for_each_entry_safe(st, nst, &mISDN_stacklist, list) {
+			printk(KERN_WARNING "mISDNcore st %x still in list\n", st->id);
+			if (list_empty(&st->list)) {
+				printk(KERN_WARNING "mISDNcore st == next\n");
+				break;
+			}
+		}
+	}
+	read_unlock(&stacklist_lock);
+}
+
+void
+release_stacks(mISDNobject_t *obj)
+{
+	mISDNstack_t	*st, *tmp;
+	int		rel, i;
+
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s: obj(%p) %s\n", __FUNCTION__, obj, obj->name);
+	read_lock(&stacklist_lock);
+	list_for_each_entry_safe(st, tmp, &mISDN_stacklist, list) {
+		rel = 0;
+		if (core_debug & DEBUG_CORE_FUNC)
+			printk(KERN_DEBUG "%s: st(%p)\n", __FUNCTION__, st);
+		for (i = 0; i <= MAX_LAYER_NR; i++) {
+			if (!st->i_array[i])
+				continue;
+			if (core_debug & DEBUG_CORE_FUNC)
+				printk(KERN_DEBUG "%s: inst%d(%p)\n", __FUNCTION__, i, st->i_array[i]);
+			if (st->i_array[i]->obj == obj)
+				rel++;
+		}
+		if (rel) {
+			read_unlock(&stacklist_lock);
+			release_stack(st);
+			read_lock(&stacklist_lock);
+		}
+	}
+	read_unlock(&stacklist_lock);
+	if (obj->refcnt)
+		printk(KERN_WARNING "release_stacks obj %s refcnt is %d\n",
+			obj->name, obj->refcnt);
+}
+
+#ifdef OBSOLETE
+static void
+get_free_instid(mISDNstack_t *st, mISDNinstance_t *inst) {
+	mISDNinstance_t *il;
+
+	inst->id = mISDN_get_lowlayer(inst->pid.layermask)<<20;
+	inst->id |= FLG_INSTANCE;
+	if (st) {
+		inst->id |= st->id;
+	} else {
+		list_for_each_entry(il, &mISDN_instlist, list) {
+			if (il->id == inst->id) {
+				if ((inst->id & IF_INSTMASK) >= INST_ID_MAX) {
+					inst->id = 0;
+					return;
+				}
+				inst->id += LAYER_ID_INC;
+				il = list_entry(mISDN_instlist.next, mISDNinstance_t, list);
+			}
+		}
+	}
+}
+#endif
+
+int
+register_layer(mISDNstack_t *st, mISDNinstance_t *inst)
+{
+	int		idx, err;
+	mISDNinstance_t	*dup;
+	u_long		flags;
+
+	if (!inst || !st)
+		return(-EINVAL);
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s:st(%p) inst(%p/%p) lmask(%x) id(%x)\n",
+			__FUNCTION__, st, inst, inst->obj,
+			inst->pid.layermask, inst->id);
+	if (inst->id) { /* already registered */
+		// if (inst->st || !st) {
+			int_errtxt("register duplicate %08x %p %p",
+				inst->id, inst->st, st);
+			return(-EBUSY);
+		//}
+	}
+	/*
+	 * To simplify registration we assume that our stacks are
+	 * always build with monoton increasing layernumbers from
+	 * bottom (HW,L0) to highest number
+	 */
+//	if (st) {
+		for (idx = 0; idx <= MAX_LAYER_NR; idx++)
+			if (!st->i_array[idx])
+				break;
+		if (idx > MAX_LAYER_NR) {
+			int_errtxt("stack %08x overflow", st->id);
+			return(-EXFULL);
+		}
+		inst->regcnt++;
+		st->i_array[idx] = inst;
+		inst->id = st->id | FLG_INSTANCE | idx;
+		dup = get_instance4id(inst->id);
+		if (dup) {
+			int_errtxt("register duplicate %08x i1(%p) i2(%p) i1->st(%p) i2->st(%p) st(%p)",
+				inst->id, inst, dup, inst->st, dup->st, st);
+			inst->regcnt--;
+			st->i_array[idx] = NULL;
+			inst->id = 0;
+			return(-EBUSY);
+		}
+//	}
+
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s: inst(%p/%p) id(%x)\n", __FUNCTION__,
+			inst, inst->obj, inst->id);
+
+	if (!list_empty(&inst->list)) {
+		if (core_debug & DEBUG_CORE_FUNC)
+			printk(KERN_DEBUG "%s: register preregistered instance st(%p/%p)\n",
+				__FUNCTION__, st, inst->st);
+		list_del_init(&inst->list);
+	}
+	inst->st = st;
+	write_lock_irqsave(&instlist_lock, flags);
+	list_add_tail(&inst->list, &mISDN_instlist);
+	write_unlock_irqrestore(&instlist_lock, flags);
+	err = mISDN_register_sysfs_inst(inst);
+	if (err) {
+		// FIXME error handling
+		printk(KERN_ERR "%s: register_sysfs failed %d st(%08x) inst(%08x)\n",
+			__FUNCTION__, err, st->id, inst->id);
+	}
+	return(0);
+}
+
+int
+preregister_layer(mISDNstack_t *st, mISDNinstance_t *inst)
+{
+	if (!inst || !st)
+		return(-EINVAL);
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s:st(%08x) inst(%p:%08x) lmask(%x)\n",
+			__FUNCTION__, st->id, inst, inst->id, inst->pid.layermask);
+	if (inst->id) {
+		/* already registered */
+		int_errtxt("register duplicate %08x %p %p",
+			inst->id, inst->st, st);
+		return(-EBUSY);
+	}
+	inst->st = st;
+	list_add_tail(&inst->list, &st->prereg);
+	return(0);
+}
+
+int
+unregister_instance(mISDNinstance_t *inst) {
+	int	i;
+	u_long	flags;
+
+	if (!inst)
+		return(-EINVAL);
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s: st(%p) inst(%p):%x lay(%x)\n",
+			__FUNCTION__, inst->st, inst, inst->id, inst->pid.layermask);
+	mISDN_unregister_sysfs_inst(inst);
+	if (inst->st && inst->id) {
+		i = inst->id & LAYER_ID_MASK;
+		if (i > MAX_LAYER_NR) {
+			int_errtxt("unregister %08x  st(%08x) wrong layer", inst->id, inst->st->id);
+			return(-EINVAL);
+		}
+		if (inst->st->i_array[i] == inst) {
+			inst->regcnt--;
+			inst->st->i_array[i] = NULL;
+		} else if (inst->st->i_array[i]) {
+			int_errtxt("unregister %08x  st(%08x) wrong instance %08x",
+				inst->id, inst->st->id, inst->st->i_array[i]->id);
+			return(-EINVAL);
+		} else
+			printk(KERN_WARNING "unregister %08x  st(%08x) not in stack",
+				inst->id, inst->st->id);
+		if (inst->st && (inst->st->mgr != inst))
+			inst->st = NULL;
+	}
+	if (inst->parent) { /*we are cloned */
+		inst->parent->clone = inst->clone;
+		if (inst->clone)
+			inst->clone->parent = inst->parent;
+		inst->clone = NULL;
+		inst->parent = NULL;
+	} else if (inst->clone) {
+		/* deleting the top level master of a clone */
+		/* FIXME: should be handled somehow, maybe unregister the clone */
+		int_errtxt("removed master(%08x) of clone(%08x)", inst->id, inst->clone->id);
+		inst->clone->parent = NULL;
+		inst->clone = NULL;
+	}
+	write_lock_irqsave(&instlist_lock, flags);
+	if (inst->list.prev && inst->list.next)
+		list_del_init(&inst->list);
+	else
+		int_errtxt("uninitialized list inst(%08x)", inst->id);
+	inst->id = 0;
+	write_unlock_irqrestore(&instlist_lock, flags);
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s: mISDN_instlist(%p<-%p->%p)\n", __FUNCTION__,
+			mISDN_instlist.prev, &mISDN_instlist, mISDN_instlist.next);
+	return(0);
+}
+
+int
+copy_pid(mISDN_pid_t *dpid, mISDN_pid_t *spid, u_char *pbuf)
+{
+	memcpy(dpid, spid, sizeof(mISDN_pid_t));
+	if (spid->pbuf && spid->maxplen) {
+		if (!pbuf) {
+			int_error();
+			return(-ENOMEM);
+		}
+		dpid->pbuf = pbuf;
+		memcpy(dpid->pbuf, spid->pbuf, spid->maxplen);
+	}
+	return(0);
+}
+
+int
+set_stack(mISDNstack_t *st, mISDN_pid_t *pid)
+{
+	int 		err, i;
+	u_char		*pbuf = NULL;
+	mISDNinstance_t	*inst;
+//	mISDNlayer_t	*hl, *hln;
+
+	if (!st || !pid) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (!st->mgr || !st->mgr->obj) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (pid->pbuf)
+		pbuf = kmalloc(pid->maxplen, GFP_ATOMIC);
+	err = copy_pid(&st->pid, pid, pbuf);
+	if (err)
+		return(err);
+	memcpy(&st->mgr->pid, &st->pid, sizeof(mISDN_pid_t));
+	if (!mISDN_SetHandledPID(st->mgr->obj, &st->mgr->pid)) {
+		int_error();
+		return(-ENOPROTOOPT);
+	} else {
+		mISDN_RemoveUsedPID(pid, &st->mgr->pid);
+	}
+	err = mISDN_ctrl(st, MGR_REGLAYER | REQUEST, st->mgr);
+	if (err) {
+		int_error();
+		return(err);
+	}
+	while (pid->layermask) {
+		inst = get_next_instance(st, pid);
+		if (!inst) {
+			int_error();
+			mISDN_ctrl(st, MGR_CLEARSTACK| REQUEST, (void *)1);
+			return(-ENOPROTOOPT);
+		}
+		mISDN_RemoveUsedPID(pid, &inst->pid);
+	}
+	if (!list_empty(&st->prereg))
+		int_errtxt("st(%08x)->prereg not empty\n", st->id);
+
+	for (i = 0; i <= MAX_LAYER_NR; i++) {
+		inst = st->i_array[i];
+		if (!inst)
+			break;
+		if (!inst->obj) {
+			int_error();
+			continue;
+		}
+		if (!inst->obj->own_ctrl) {
+			int_error();
+			continue;
+		}
+		inst->obj->own_ctrl(inst, MGR_SETSTACK | INDICATION, NULL);
+	}
+	return(0);
+}
+
+int
+clear_stack(mISDNstack_t *st, int wait) {
+	struct sk_buff	*skb;
+	mISDN_headext_t	*hhe;
+
+	if (!st)
+		return(-EINVAL);
+	if (core_debug & DEBUG_CORE_FUNC)
+		printk(KERN_DEBUG "%s: st(%08x)\n", __FUNCTION__, st->id);
+
+	if (!(skb = alloc_skb(8, GFP_ATOMIC)))
+		return(-ENOMEM);
+	hhe = mISDN_HEADEXT_P(skb);
+	hhe->prim = MGR_CLEARSTACK | REQUEST;
+	hhe->addr = st->id;
+
+	if (wait) {
+		DECLARE_MUTEX_LOCKED(sem);
+
+		hhe->data[0] = &sem;
+		_queue_message(st, skb);
+		if (st->thread == current) {/* we cannot wait for us */
+			int_error();
+			return(-EBUSY);
+		}
+		down(&sem);
+	} else {
+		hhe->data[0] = NULL;
+		_queue_message(st, skb);
+	}
+	return(0);
+}
+
+static int
+test_stack_protocol(mISDNstack_t *st, u_int l1prot, u_int l2prot, u_int l3prot)
+{
+	int		cnt = MAX_LAYER_NR + 1, ret = 1;
+	mISDN_pid_t	pid;
+	mISDNinstance_t	*inst;
+
+	clear_stack(st,1);
+	memset(&pid, 0, sizeof(mISDN_pid_t));
+	pid.layermask = ISDN_LAYER(1);
+	if (!(((l2prot == 2) || (l2prot == 0x40)) && (l3prot == 1)))
+		pid.layermask |= ISDN_LAYER(2);
+	if (!(l3prot == 1))
+		pid.layermask |= ISDN_LAYER(3);
+
+	pid.protocol[1] = l1prot | ISDN_PID_LAYER(1) | ISDN_PID_BCHANNEL_BIT;
+	if (pid.layermask & ISDN_LAYER(2))
+		pid.protocol[2] = l2prot | ISDN_PID_LAYER(2) | ISDN_PID_BCHANNEL_BIT;
+	if (pid.layermask & ISDN_LAYER(3))
+		pid.protocol[3] = l3prot | ISDN_PID_LAYER(3) | ISDN_PID_BCHANNEL_BIT;
+	copy_pid(&st->pid, &pid, NULL);
+	memcpy(&st->mgr->pid, &pid, sizeof(mISDN_pid_t));
+	if (!mISDN_SetHandledPID(st->mgr->obj, &st->mgr->pid)) {
+		memset(&st->pid, 0, sizeof(mISDN_pid_t));
+		return(-ENOPROTOOPT);
+	} else {
+		mISDN_RemoveUsedPID(&pid, &st->mgr->pid);
+	}
+	if (!pid.layermask) {
+		memset(&st->pid, 0, sizeof(mISDN_pid_t));
+		return(0);
+	}
+	ret = mISDN_ctrl(st, MGR_REGLAYER | REQUEST, st->mgr);
+	if (ret) {
+		clear_stack(st, 1);
+		return(ret);
+	}
+	while (pid.layermask && cnt--) {
+		inst = get_next_instance(st, &pid);
+		if (!inst) {
+			ret = -ENOPROTOOPT;
+			break;
+		}
+		mISDN_RemoveUsedPID(&pid, &inst->pid);
+	}
+	if (!cnt)
+		ret = -ENOPROTOOPT;
+	clear_stack(st, 1);
+	return(ret);
+}
+
+static u_int	validL1pid4L2[ISDN_PID_IDX_MAX + 1] = {
+			0x022d,
+			0x03ff,
+			0x0000,
+			0x0000,
+			0x0010,
+			0x022d,
+			0x03ff,
+			0x0380,
+			0x022d,
+			0x022d,
+			0x022d,
+			0x01c6,
+			0x0000,
+};
+
+static u_int	validL2pid4L3[ISDN_PID_IDX_MAX + 1] = {
+			0x1fff,
+			0x0000,
+			0x0101,
+			0x0101,
+			0x0010,
+			0x0010,
+			0x0000,
+			0x00c0,
+			0x0000,
+};
+
+int
+evaluate_stack_pids(mISDNstack_t *st, mISDN_pid_t *pid)
+{
+	int 		err;
+	mISDN_pid_t	pidmask;
+	u_int		l1bitm, l2bitm, l3bitm;
+	u_int		l1idx, l2idx, l3idx;
+
+	if (!st || !pid) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (!st->mgr || !st->mgr->obj) {
+		int_error();
+		return(-EINVAL);
+	}
+	copy_pid(&pidmask, pid, NULL);
+	memset(pid, 0, sizeof(mISDN_pid_t));
+	for (l1idx=0; l1idx <= ISDN_PID_IDX_MAX; l1idx++) {
+		l1bitm = 1 << l1idx;
+		if (!(pidmask.protocol[1] & l1bitm))
+			continue;
+		for (l2idx=0; l2idx <= ISDN_PID_IDX_MAX; l2idx++) {
+			l2bitm = 1 << l2idx;
+			if (!(pidmask.protocol[2] & l2bitm))
+				continue;
+			if (!(validL1pid4L2[l2idx] & l1bitm))
+				continue;
+			for (l3idx=0; l3idx <= ISDN_PID_IDX_MAX; l3idx++) {
+				err = 1;
+				l3bitm = 1 << l3idx;
+				if (!(pidmask.protocol[3] & l3bitm))
+					continue;
+				if (!(validL2pid4L3[l3idx] & l2bitm))
+					continue;
+				err = test_stack_protocol(st, l1bitm, l2bitm, l3bitm);
+				if (!err) {
+					pid->protocol[3] |= l3bitm;
+					pid->protocol[2] |= l2bitm;
+					pid->protocol[1] |= l1bitm;
+				}
+			}
+		}
+	}
+	clear_stack(st, 1);
+	return(0);
+}
+
+EXPORT_SYMBOL(mISDN_queue_message);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/supp_serv.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/supp_serv.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/supp_serv.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,852 @@
+/* $Id: supp_serv.c,v 1.11 2006/03/06 12:52:07 keil Exp $
+ *
+ */
+
+#include "m_capi.h"
+#include "asn1_comp.h"
+#include "asn1_enc.h"
+#include "dss1.h"
+#include "helper.h"
+#include "debug.h"
+
+#define T_ACTIVATE    4000
+#define T_DEACTIVATE  4000
+#define T_INTERROGATE 4000
+
+static void	SSProcessAddTimer(SSProcess_t *, int);
+
+static __u8 *
+encodeInvokeComponentHead(__u8 *p)
+{
+	*p++ = 0;     // length -- not known yet
+	*p++ = 0x91;  // remote operations protocol
+	*p++ = 0xa1;  // invoke component
+	*p++ = 0;     // length -- not known yet
+	return p;
+}
+
+static void
+encodeInvokeComponentLength(__u8 *msg, __u8 *p)
+{
+	msg[3] = p - &msg[4];
+	msg[0] = p - &msg[1];
+}
+
+
+static int
+SSProcess_L4L3(SSProcess_t *spc, __u32 prim, struct sk_buff *skb) {
+	int	err;
+
+	err = ControllerL4L3(spc->contr, prim, MISDN_ID_DUMMY, skb);
+	if (err)
+		dev_kfree_skb(skb);
+	return(err);
+}
+
+static __inline__ int capiGetWord(__u8 *p, __u8 *end, __u16 *word)
+{
+	if (p + 2 > end) {
+		return -1;
+	}
+	*word = *p + (*(p+1) << 8);
+
+	return 2;
+}
+
+static __inline__ int capiGetDWord(__u8 *p, __u8 *end, __u32 *dword)
+{
+	if (p + 4 > end) {
+		return -1;
+	}
+	*dword = *p + (*(p+1) << 8) + (*(p+2) << 16) + (*(p+3) << 24);
+
+	return 4;
+}
+
+static __inline__ int capiGetStruct(__u8 *p, __u8 *_end, __u8 **strct)
+{
+	int len = *p++;
+	__u8 *end = p + len;
+
+	if (end > _end) return -1;
+
+	*strct = p - 1;
+
+	return len + 1;
+}
+
+#define CAPI_GET(func, parm) \
+	ret = func(p, end, parm); \
+	if (ret < 0) return -1; \
+	p += ret
+
+static __inline__ int capiGetFacReqListen(__u8 *p, __u8 *_end, struct FacReqListen *listen)
+{
+	int len = *p++;
+	int ret;
+	__u8 *end = p + len;
+
+	if (end > _end) return -1;
+
+	CAPI_GET(capiGetDWord, &listen->NotificationMask);
+
+	if (p != end) return -1;
+	return len + 1;
+}
+
+static __inline__ int capiGetFacReqSuspend(__u8 *p, __u8 *_end, struct FacReqSuspend *suspend)
+{
+	int len = *p++;
+	int ret;
+	__u8 *end = p + len;
+
+	if (end > _end) return -1;
+
+	CAPI_GET(capiGetStruct, &suspend->CallIdentity);
+
+	if (p != end) return -1;
+	return len + 1;
+}
+
+static __inline__ int capiGetFacReqResume(__u8 *p, __u8 *_end, struct FacReqResume *resume)
+{
+	int len = *p++;
+	int ret;
+	__u8 *end = p + len;
+
+	if (end > _end) return -1;
+
+	CAPI_GET(capiGetStruct, &resume->CallIdentity);
+
+	if (p != end) return -1;
+	return len + 1;
+}
+
+static __inline__ int capiGetFacReqCFActivate(__u8 *p, __u8 *_end, struct FacReqCFActivate *CFActivate)
+{
+	int len = *p++;
+	int ret;
+	__u8 *end = p + len;
+
+	if (end > _end) return -1;
+
+	CAPI_GET(capiGetDWord, &CFActivate->Handle);
+	CAPI_GET(capiGetWord, &CFActivate->Procedure);
+	CAPI_GET(capiGetWord, &CFActivate->BasicService);
+	CAPI_GET(capiGetStruct, &CFActivate->ServedUserNumber);
+	CAPI_GET(capiGetStruct, &CFActivate->ForwardedToNumber);
+	CAPI_GET(capiGetStruct, &CFActivate->ForwardedToSubaddress);
+
+	if (p != end) return -1;
+	return len + 1;
+}
+
+static __inline__ int capiGetFacReqCFDeactivate(__u8 *p, __u8 *_end, struct FacReqCFDeactivate *CFDeactivate)
+{
+	int len = *p++;
+	int ret;
+	__u8 *end = p + len;
+
+	if (end > _end) return -1;
+
+	CAPI_GET(capiGetDWord, &CFDeactivate->Handle);
+	CAPI_GET(capiGetWord, &CFDeactivate->Procedure);
+	CAPI_GET(capiGetWord, &CFDeactivate->BasicService);
+	CAPI_GET(capiGetStruct, &CFDeactivate->ServedUserNumber);
+
+	if (p != end) return -1;
+	return len + 1;
+}
+
+#define capiGetFacReqCFInterrogateParameters capiGetFacReqCFDeactivate
+
+static __inline__ int capiGetFacReqCFInterrogateNumbers(__u8 *p, __u8 *_end, struct FacReqCFInterrogateNumbers *CFInterrogateNumbers)
+{
+	int len = *p++;
+	int ret;
+	__u8 *end = p + len;
+
+	if (end > _end) return -1;
+
+	CAPI_GET(capiGetDWord, &CFInterrogateNumbers->Handle);
+
+	if (p != end)
+		return(-1);
+	return(len + 1);
+}
+
+static __inline__ int capiGetFacReqCD(__u8 *p, __u8 *_end, struct FacReqCDeflection *CD)
+{
+	int len = *p++;
+	int ret;
+	__u8 *end = p + len;
+
+	if (end > _end) return -1;
+
+	CAPI_GET(capiGetWord, &CD->PresentationAllowed);
+	CAPI_GET(capiGetStruct, &CD->DeflectedToNumber);
+	CAPI_GET(capiGetStruct, &CD->DeflectedToSubaddress);
+
+	if (p != end) return -1;
+	return len + 1;
+}
+
+
+static __inline__ int capiGetFacReqParm(__u8 *p, struct FacReqParm *facReqParm)
+{
+	int len = *p++;
+	int ret;
+	__u8 *end = p + len;
+
+	CAPI_GET(capiGetWord, &facReqParm->Function);
+
+	switch (facReqParm->Function) {
+		case 0x0000: // GetSupportedServices
+			if (*p++ != 0x00) return -1; // empty struct
+			break;
+		case 0x0001: // Listen
+			CAPI_GET(capiGetFacReqListen, &facReqParm->u.Listen);
+			break;
+		case 0x0004: // Suspend
+			CAPI_GET(capiGetFacReqSuspend, &facReqParm->u.Suspend);
+			break;
+		case 0x0005: // Resume
+			CAPI_GET(capiGetFacReqResume, &facReqParm->u.Resume);
+			break;
+		case 0x0009: // CF Activate
+			CAPI_GET(capiGetFacReqCFActivate, &facReqParm->u.CFActivate);
+			break;
+		case 0x000a: // CF Deactivate
+			CAPI_GET(capiGetFacReqCFDeactivate, &facReqParm->u.CFDeactivate);
+			break;
+		case 0x000b: // CF Interrogate Parameters
+			CAPI_GET(capiGetFacReqCFInterrogateParameters, &facReqParm->u.CFInterrogateParameters);
+			break;
+		case 0x000c: // CF Interrogate Numbers
+			CAPI_GET(capiGetFacReqCFInterrogateNumbers, &facReqParm->u.CFInterrogateNumbers);
+			break;
+		case 0x000d: // CD
+			CAPI_GET(capiGetFacReqCD, &facReqParm->u.CDeflection);
+			break;
+		default:
+			return(len + 1);
+	}
+
+	if (p != end)
+		return(-1);
+	return(len + 1);
+}
+
+static int
+GetSupportedServices(FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	facConfParm->u.GetSupportedServices.SupplementaryServiceInfo = CapiSuccess;
+	facConfParm->u.GetSupportedServices.SupportedServices = mISDNSupportedServices;
+	return CapiSuccess;
+}
+static int
+FacListen(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	if (facReqParm->u.Listen.NotificationMask &~ mISDNSupportedServices) {
+		facConfParm->u.Info.SupplementaryServiceInfo = CapiSupplementaryServiceNotSupported;
+	} else {
+		appl->NotificationMask = facReqParm->u.Listen.NotificationMask;
+		facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
+	}
+	return CapiSuccess;
+}
+
+static int
+FacCFInterrogateParameters(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	SSProcess_t	*sspc;
+	struct sk_buff	*skb = mISDN_alloc_l3msg(260, MT_FACILITY);
+	__u8		*p;
+
+	if (!skb)
+		return CAPI_MSGOSRESOURCEERR;
+	sspc = SSProcessConstr(appl, facReqParm->Function, 
+				  facReqParm->u.CFInterrogateParameters.Handle);
+	if (!sspc) {
+		kfree_skb(skb);
+		return CAPI_MSGOSRESOURCEERR;
+	}
+
+	p = encodeInvokeComponentHead(sspc->buf);
+	p += encodeInt(p, sspc->invokeId);
+	p += encodeInt(p, 11); // interrogationDiversion
+	p += encodeInterrogationDiversion(p,  &facReqParm->u.CFInterrogateParameters);
+	encodeInvokeComponentLength(sspc->buf, p);
+	mISDN_AddIE(skb, IE_FACILITY, sspc->buf);
+
+	SSProcess_L4L3(sspc, CC_FACILITY | REQUEST, skb);
+	SSProcessAddTimer(sspc, T_INTERROGATE);
+
+	facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
+	return CapiSuccess;
+}
+
+static int
+FacCFInterrogateNumbers(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	SSProcess_t	*sspc;
+	struct sk_buff	*skb = mISDN_alloc_l3msg(260, MT_FACILITY);
+	__u8		*p;
+
+	if (!skb)
+		return CAPI_MSGOSRESOURCEERR;
+	sspc = SSProcessConstr(appl, facReqParm->Function, 
+				  facReqParm->u.CFInterrogateNumbers.Handle);
+	if (!sspc) {
+		kfree_skb(skb);
+		return CAPI_MSGOSRESOURCEERR;
+	}
+
+	p = encodeInvokeComponentHead(sspc->buf);
+	p += encodeInt(p, sspc->invokeId);
+	p += encodeInt(p, 17); // InterrogateServedUserNumbers
+	encodeInvokeComponentLength(sspc->buf, p);
+	mISDN_AddIE(skb, IE_FACILITY, sspc->buf);
+	SSProcess_L4L3(sspc, CC_FACILITY | REQUEST, skb);
+	SSProcessAddTimer(sspc, T_INTERROGATE);
+
+	facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
+	return CapiSuccess;
+}
+
+static int
+FacCFActivate(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	SSProcess_t	*sspc;
+	struct sk_buff	*skb = mISDN_alloc_l3msg(260, MT_FACILITY);
+	__u8		*p;
+
+	if (!skb)
+		return CAPI_MSGOSRESOURCEERR;
+	sspc = SSProcessConstr(appl, facReqParm->Function, facReqParm->u.CFActivate.Handle);
+	if (!sspc) {
+		kfree_skb(skb);
+		return CAPI_MSGOSRESOURCEERR;
+	}
+	p = encodeInvokeComponentHead(sspc->buf);
+	p += encodeInt(p, sspc->invokeId);
+	p += encodeInt(p, 7); // activationDiversion
+	p += encodeActivationDiversion(p, &facReqParm->u.CFActivate);
+	encodeInvokeComponentLength(sspc->buf, p);
+	mISDN_AddIE(skb, IE_FACILITY, sspc->buf);
+	SSProcess_L4L3(sspc, CC_FACILITY | REQUEST, skb);
+	SSProcessAddTimer(sspc, T_ACTIVATE);
+
+	facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
+	return CapiSuccess;
+}
+
+static int
+FacCFDeactivate(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	SSProcess_t	*sspc;
+	struct sk_buff	*skb = mISDN_alloc_l3msg(260, MT_FACILITY);
+	__u8		*p;
+
+	if (!skb)
+		return CAPI_MSGOSRESOURCEERR;
+	sspc = SSProcessConstr(appl, facReqParm->Function, facReqParm->u.CFDeactivate.Handle);
+	if (!sspc) {
+		kfree_skb(skb);
+		return CAPI_MSGOSRESOURCEERR;
+	}
+	p = encodeInvokeComponentHead(sspc->buf);
+	p += encodeInt(p, sspc->invokeId);
+	p += encodeInt(p, 8); // dectivationDiversion
+	p += encodeDeactivationDiversion(p, &facReqParm->u.CFDeactivate);
+	encodeInvokeComponentLength(sspc->buf, p);
+	mISDN_AddIE(skb, IE_FACILITY, sspc->buf);
+
+	SSProcess_L4L3(sspc, CC_FACILITY | REQUEST, skb);
+	SSProcessAddTimer(sspc, T_DEACTIVATE);
+
+	facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
+	return CapiSuccess;
+}
+ 
+static int
+FacCDeflection(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
+{
+	SSProcess_t	*sspc;
+	struct sk_buff	*skb = mISDN_alloc_l3msg(260, MT_FACILITY);
+	__u8		*p;
+
+	if (!skb)
+		return CAPI_MSGOSRESOURCEERR;
+	sspc = SSProcessConstr(aplci->appl, facReqParm->Function, facReqParm->u.CFActivate.Handle);
+	if (!sspc) {
+		kfree_skb(skb);
+		return CAPI_MSGOSRESOURCEERR;
+	}
+	p = encodeInvokeComponentHead(sspc->buf);
+	p += encodeInt(p, sspc->invokeId);
+	p += encodeInt(p, 13); // Calldefection
+	p += encodeInvokeDeflection(p, &facReqParm->u.CDeflection);
+	encodeInvokeComponentLength(sspc->buf, p);
+	mISDN_AddIE(skb, IE_FACILITY, sspc->buf);
+	if (aplci->plci)
+		plciL4L3(aplci->plci, CC_FACILITY | REQUEST, skb);
+	SSProcessAddTimer(sspc, T_ACTIVATE);
+	facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
+	return CapiSuccess;
+}
+
+void
+SupplementaryFacilityReq(Application_t *appl, _cmsg *cmsg)
+{
+	__u8		tmp[10];
+	__u16		Info;
+	FacReqParm_t	facReqParm;
+	FacConfParm_t	facConfParm;
+	Plci_t		*plci;
+	AppPlci_t	*aplci;
+	int		ret;
+
+	if (capiGetFacReqParm(cmsg->FacilityRequestParameter, &facReqParm) < 0) {
+		SendCmsgAnswer2Application(appl, cmsg, CapiIllMessageParmCoding);
+		return;
+	}
+	facConfParm.Function = facReqParm.Function;
+	switch (facReqParm.Function) {
+		case 0x0000: // GetSupportedServices
+			Info = GetSupportedServices(&facReqParm, &facConfParm);
+			break;
+		case 0x0001: // Listen
+			Info = FacListen(appl, &facReqParm, &facConfParm);
+			break;
+		case 0x0002: // Hold
+			aplci = getAppPlci4addr(appl, cmsg->adr.adrPLCI);
+			if (!aplci) {
+				Info = CapiIllContrPlciNcci;
+				break;
+			}
+			Info = AppPlciFacHoldReq(aplci, &facReqParm, &facConfParm);
+			break;
+		case 0x0003: // Retrieve
+			aplci = getAppPlci4addr(appl, cmsg->adr.adrPLCI);
+			if (!aplci) {
+				Info = CapiIllContrPlciNcci;
+				break;
+			}
+			Info = AppPlciFacRetrieveReq(aplci, &facReqParm, &facConfParm);
+			break;
+		case 0x0004: // Suspend
+			aplci = getAppPlci4addr(appl, cmsg->adr.adrPLCI);
+			if (!aplci) {
+				Info = CapiIllContrPlciNcci;
+				break;
+			}
+			Info = AppPlciFacSuspendReq(aplci, &facReqParm, &facConfParm);
+			break;
+		case 0x0005: // Resume
+			ret = ControllerNewPlci(appl->contr, &plci, MISDN_ID_ANY);
+			if (ret) {
+				Info = CapiNoPlciAvailable;
+				break;
+			}
+			aplci = ApplicationNewAppPlci(appl, plci);
+			if (!aplci) {
+				ControllerReleasePlci(plci);
+				Info = CapiNoPlciAvailable;
+				break;
+			}
+			Info = AppPlciFacResumeReq(aplci, &facReqParm, &facConfParm);
+			if (Info == CapiSuccess)
+				cmsg->adr.adrPLCI = plci->addr;
+			break;
+		case 0x0009: // CF Activate
+			Info = FacCFActivate(appl, &facReqParm, &facConfParm);
+			break;
+		case 0x000a: // CF Deactivate
+			Info = FacCFDeactivate(appl, &facReqParm, &facConfParm);
+			break;
+		case 0x000b: // CF Interrogate Parameters
+			Info = FacCFInterrogateParameters(appl, &facReqParm, &facConfParm);
+			break;
+		case 0x000c: // CF Interrogate Numbers
+			Info = FacCFInterrogateNumbers(appl, &facReqParm, &facConfParm);
+			break;
+		case 0x000d: // CD
+			aplci = getAppPlci4addr(appl, cmsg->adr.adrPLCI);
+			if (!aplci) {
+				Info = CapiIllContrPlciNcci;
+				break;
+			}
+			Info = FacCDeflection(aplci, &facReqParm, &facConfParm);
+			break;
+		default:
+			Info = CapiSuccess;
+			facConfParm.u.Info.SupplementaryServiceInfo = CapiSupplementaryServiceNotSupported;
+	}
+
+	if (Info == 0x0000)
+		capiEncodeFacConfParm(tmp, &facConfParm);
+	else
+		tmp[0] = 0;
+	cmsg->FacilityConfirmationParameter = tmp;
+	SendCmsgAnswer2Application(appl, cmsg, Info);
+}
+
+SSProcess_t *
+SSProcessConstr(Application_t *appl, __u16 Function, __u32 Handle)
+{
+	SSProcess_t	*sspc;
+
+	sspc = SSProcess_alloc();
+	if (!sspc)
+		return(NULL);
+	memset(sspc, 0, sizeof(SSProcess_t));
+	sspc->ApplId = appl->ApplId;
+	sspc->Function = Function;
+	sspc->Handle = Handle;
+	ControllerAddSSProcess(appl->contr, sspc);
+	return(sspc);
+}
+
+void SSProcessDestr(SSProcess_t *sspc)
+{
+	del_timer(&sspc->tl);
+	list_del_init(&sspc->head);
+	SSProcess_free(sspc);
+}
+
+static void
+SendSSFacilityInd(Application_t *appl, __u32 addr, __u8 *para)
+{
+	_cmsg	*cmsg;
+
+	CMSG_ALLOC(cmsg);
+	capi_cmsg_header(cmsg, appl->ApplId, CAPI_FACILITY, CAPI_IND, appl->MsgId++, addr);
+	cmsg->FacilitySelector = 0x0003;
+	cmsg->FacilityIndicationParameter = para;
+	SendCmsg2Application(appl, cmsg);
+}
+
+void
+SendSSNotificationEvent(AppPlci_t *aplci, u16 event)
+{
+	__u8		tmp[4], *p;
+
+	if (!aplci->appl)
+		return;
+	switch (event) {
+		case 0x8000: // user hold
+		case 0x8001: // user retrieve
+			if (!(aplci->appl->NotificationMask & SuppServiceHR))
+				return;
+			break;
+		case 0x8002: // user suspended
+		case 0x8003: // user resumed
+			if (!(aplci->appl->NotificationMask & SuppServiceTP))
+				return;
+			break;
+		case 0x8004: // call is diverting
+		case 0x8005: // diversion activated
+			if (!(aplci->appl->NotificationMask & SuppServiceCF))
+				return;
+			break;
+		default:
+			int_errtxt("Event %x not known\n", event);
+			return;
+	}
+	p = &tmp[1];
+	p += capiEncodeWord(p, event); // Suspend/Resume Notification
+	*p++ = 0; // empty struct
+	tmp[0] = p - &tmp[1];
+	SendSSFacilityInd(aplci->appl, aplci->addr, tmp);
+}
+
+static void
+SendSSFacilityInd2All(Controller_t *contr, __u32 nMask, __u8 *para)
+{
+	struct list_head	*item;
+	Application_t		*appl;
+
+	list_for_each(item, &contr->Applications) {
+		appl = (Application_t *)item;
+		if (test_bit(APPL_STATE_RELEASE, &appl->state))
+			continue;
+		if (!(appl->NotificationMask & nMask))
+			continue;
+		SendSSFacilityInd(appl, contr->addr, para);
+	}
+}
+
+void
+SSProcessTimeout(unsigned long arg)
+{
+	SSProcess_t	*sspc = (SSProcess_t *) arg;
+	Application_t	*appl;
+	__u8		tmp[10], *p;
+
+	appl = getApplication4Id(sspc->contr, sspc->ApplId);
+	if (!appl) {
+		SSProcessDestr(sspc);
+		return;
+	}
+	p = &tmp[1];
+	p += capiEncodeWord(p, sspc->Function);
+	p += capiEncodeFacIndCFact(p, CapiTimeOut, sspc->Handle);
+	tmp[0] = p - &tmp[1];
+	SendSSFacilityInd(appl, sspc->addr, tmp);
+	SSProcessDestr(sspc);
+}
+
+void SSProcessAddTimer(SSProcess_t *sspc, int msec)
+{
+	sspc->tl.function = SSProcessTimeout;
+	sspc->tl.data = (unsigned long) sspc;
+	init_timer(&sspc->tl);
+	sspc->tl.expires = jiffies + (msec * HZ) / 1000;
+	add_timer(&sspc->tl);
+}
+
+
+#ifdef ASN1_DEBUG
+void printPublicPartyNumber(struct PublicPartyNumber *publicPartyNumber)
+{
+	printk(KERN_DEBUG "(%d) %s\n", publicPartyNumber->publicTypeOfNumber, 
+	       publicPartyNumber->numberDigits);
+}
+
+void printPartyNumber(struct PartyNumber *partyNumber)
+{
+	switch (partyNumber->type) {
+	case 0: 
+		printk(KERN_DEBUG "unknown %s\n", partyNumber->p.unknown);
+		break;
+	case 1:
+		printPublicPartyNumber(&partyNumber->p.publicPartyNumber);
+		break;
+	}
+}
+
+void printServedUserNr(struct ServedUserNr *servedUserNr)
+{
+	if (servedUserNr->all) {
+		printk("all\n");
+	} else {
+		printPartyNumber(&servedUserNr->partyNumber);
+	}
+}
+
+void printAddress(struct Address *address)
+{
+	printPartyNumber(&address->partyNumber);
+	if (address->partySubaddress[0]) {
+		printk("sub %s\n", address->partySubaddress);
+	}
+}
+#endif
+
+static void 
+SSProcessSingleFacility(Controller_t *contr, struct asn1_parm *parm)
+{
+	Application_t		*appl;
+	SSProcess_t		*sspc;
+	__u8			*p, tmp[256];
+
+	switch (parm->comp) {
+		case invoke:
+#ifdef ASN1_DEBUG
+			printk("invokeId %d\n", parm->u.inv.invokeId);
+			printk("operationValue %d\n", parm->u.inv.operationValue);
+#endif
+			switch (parm->u.inv.operationValue) {
+				case 0x0009: 
+#ifdef ASN1_DEBUG
+					printk("procedure %d basicService %d\n", parm->u.inv.o.actNot.procedure,
+						parm->u.inv.o.actNot.basicService);
+					printServedUserNr(&parm->u.inv.o.actNot.servedUserNr);
+					printAddress(&parm->u.inv.o.actNot.address);
+#endif
+					p = &tmp[1];
+					p += capiEncodeWord(p, 0x8006);
+					p += capiEncodeFacIndCFNotAct(p, &parm->u.inv.o.actNot);
+					tmp[0] = p - &tmp[1];
+					SendSSFacilityInd2All(contr, SuppServiceCF, tmp);
+					break;
+				case 0x000a: 
+#ifdef ASN1_DEBUG
+					printk("procedure %d basicService %d\n", parm->u.inv.o.deactNot.procedure,
+						parm->u.inv.o.deactNot.basicService);
+					printServedUserNr(&parm->u.inv.o.deactNot.servedUserNr);
+#endif
+					p = &tmp[1];
+					p += capiEncodeWord(p, 0x8007);
+					p += capiEncodeFacIndCFNotDeact(p, &parm->u.inv.o.deactNot);
+					tmp[0] = p - &tmp[1];
+					SendSSFacilityInd2All(contr, SuppServiceCF, tmp);
+					break;
+				default:
+					int_error();
+			}
+			break;
+		case returnResult:
+			sspc = getSSProcess4Id(contr, parm->u.retResult.invokeId);
+			if (!sspc)
+				return;
+			appl = getApplication4Id(contr, sspc->ApplId);
+			if (!appl)
+				return;
+			p = &tmp[1];
+			p += capiEncodeWord(p, sspc->Function);
+			switch (sspc->Function) {
+				case 0x0009:
+					p += capiEncodeFacIndCFact(p, 0, sspc->Handle);
+					break;
+				case 0x000a:
+					p += capiEncodeFacIndCFdeact(p, 0, sspc->Handle);
+					break;
+				case 0x000b:
+					p += capiEncodeFacIndCFinterParameters(p, 0, sspc->Handle, 
+						&parm->u.retResult.o.resultList);
+					break;
+				case 0x000c:
+					p += capiEncodeFacIndCFinterNumbers(p, 0, sspc->Handle, 
+						&parm->u.retResult.o.list);
+					break;
+				default:
+					int_errtxt("returnResult for Function %04x", sspc->Function);
+					break;
+			}
+			tmp[0] = p - &tmp[1];
+			SendSSFacilityInd(appl, sspc->addr, tmp);
+			SSProcessDestr(sspc);
+			break;
+		case returnError:
+			sspc = getSSProcess4Id(contr, parm->u.retResult.invokeId);
+			if (!sspc)
+				return;
+			appl = getApplication4Id(contr, sspc->ApplId);
+			if (!appl)
+				return;
+			p = &tmp[1];
+			p += capiEncodeWord(p, sspc->Function);
+			p += capiEncodeFacIndCFact(p, 0x3600 | (parm->u.retError.errorValue & 0xff), 
+				sspc->Handle);
+			tmp[0] = p - &tmp[1];
+			SendSSFacilityInd(appl, sspc->addr, tmp);
+			SSProcessDestr(sspc);
+			break;
+		case reject:
+			if (parm->u.reject.invokeId == -1) /* ID := NULL */
+				return;
+			if (parm->u.reject.problem != InvokeP) {
+				int_errtxt("reject problem class %d problem %d do not match CAPI errors",
+					parm->u.reject.problem, parm->u.reject.problemValue);
+				/* this is not compatible, but better as ignore */
+				switch (parm->u.reject.problem) {
+					case GeneralP:
+						parm->u.reject.problemValue |= 0x80;
+						break;
+					default:
+						parm->u.reject.problemValue |= (parm->u.reject.problem << 4);
+				}
+			}
+			sspc = getSSProcess4Id(contr, parm->u.reject.invokeId);
+			if (!sspc)
+				return;
+			appl = getApplication4Id(contr, sspc->ApplId);
+			if (!appl)
+				return;
+			p = &tmp[1];
+			p += capiEncodeWord(p, sspc->Function);
+			p += capiEncodeFacIndCFact(p, 0x3700 | (parm->u.reject.problemValue & 0xff), 
+				sspc->Handle);
+			tmp[0] = p - &tmp[1];
+			SendSSFacilityInd(appl, sspc->addr, tmp);
+			SSProcessDestr(sspc);
+			break;
+		default:
+			int_errtxt("component %x not handled", parm->comp);
+			break;
+	}
+}
+
+static void 
+SSProcessFacility(Controller_t *contr, __u8 *p)
+{
+        int			ie_len, l;
+	struct asn1_parm	parm;
+        __u8			*end;
+
+        ie_len = *p++;
+        end = p + ie_len;
+
+        p++; // Supplementary Service Applications checked before
+
+        while (p < end) {
+	        parm.comp = -1;
+	        l = ParseComponent(&parm, p, end);
+	        // printk(KERN_DEBUG "ie_len (%d) l(%d) parm.comp %d\n", ie_len, l, parm.comp);
+	        if (parm.comp != -1) {
+	        	SSProcessSingleFacility(contr, &parm);
+	        } else {
+			static char logbuf[3*260];
+
+			int_errtxt("component %x not handled", parm.comp);
+			if (ie_len > 260)
+				ie_len = 260;
+			mISDN_QuickHex(logbuf, p, ie_len);
+			printk(KERN_DEBUG "facIE: %s\n", logbuf);
+		}
+	        if (l>0)
+	        	p += l;
+		else
+			break;
+	}
+}
+
+int
+Supplementary_l3l4(Controller_t *contr, __u32 prim, struct sk_buff *skb)
+{
+	int		ret = -EINVAL;
+	Q931_info_t	*qi;
+	ie_info_t	*fac;
+	__u8		*p, *end;
+
+	if (!skb)
+		return(ret);
+	switch (prim) {
+		case CC_FACILITY | INDICATION:
+			qi = (Q931_info_t *)skb->data;
+			if (skb->len <= L3_EXTRA_SIZE) {
+				int_error();
+				break;
+			}
+		        if (!qi->facility.off) {
+		        	int_error();
+		        	break;
+			}
+			fac = &qi->facility;
+			while(fac && fac->off) {
+				p = (__u8 *)qi;
+				p += L3_EXTRA_SIZE + fac->off + 1;
+			        end = p + *p;
+			        if (end > skb->data + skb->len) {
+			                int_error();
+			                fac = NULL;
+				} else if (p[1] == 0x91) { // Supplementary Service Applications
+					SSProcessFacility(contr, p);
+				} else {
+					int_errtxt("FACILITY but not a Supplementary Service ID %x", p[1]);
+				}
+				if (fac->repeated)
+					fac = &qi->ext[fac->ridx].ie;
+				else
+					fac = NULL;
+			}
+			dev_kfree_skb(skb);
+			ret = 0;
+			break;
+		default:
+			int_error();
+	}
+	return(ret);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,77 @@
+/* $Id: sysfs.h,v 1.2 2006/03/06 12:58:31 keil Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * mISDN sysfs common defines
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+#include <linux/stringify.h>
+
+extern ssize_t	mISDN_show_pid_protocol(mISDN_pid_t *, char *);
+extern ssize_t	mISDN_show_pid_parameter(mISDN_pid_t *, char *);
+
+static inline ssize_t show_pid_layermask(mISDN_pid_t *pid, char *buf)
+{
+	return sprintf(buf, "0x%08x\n", pid->layermask);
+}
+
+static inline ssize_t show_pid_global(mISDN_pid_t *pid, char *buf)
+{
+	return sprintf(buf, "0x%04x\n", pid->global);
+}
+
+static inline ssize_t show_pid_maxplen(mISDN_pid_t *pid, char *buf)
+{
+	return sprintf(buf, "%d\n", pid->maxplen);
+}
+
+#define MISDN_PROTO(_type, _name, _mode) \
+static ssize_t show_protocol_##_name(struct class_device *class_dev, char *buf) \
+{ \
+	_type##_t	*p = to_##_type(class_dev); \
+	return(mISDN_show_pid_protocol(&p->_name, buf)); \
+} \
+struct class_device_attribute _type##_attr_protocol_##_name = \
+	__ATTR(protocol,_mode,show_protocol_##_name, NULL); \
+static ssize_t show_parameter_##_name(struct class_device *class_dev, char *buf) \
+{ \
+	_type##_t	*p = to_##_type(class_dev); \
+	return(mISDN_show_pid_parameter(&p->_name, buf)); \
+} \
+struct class_device_attribute _type##_attr_parameter_##_name = \
+	__ATTR(parameter,_mode,show_parameter_##_name, NULL); \
+static ssize_t show_layermask_##_name(struct class_device *class_dev, char *buf) \
+{ \
+	_type##_t	*p = to_##_type(class_dev); \
+	return(show_pid_layermask(&p->_name, buf)); \
+} \
+struct class_device_attribute _type##_attr_layermask_##_name = \
+	__ATTR(layermask,_mode,show_layermask_##_name, NULL); \
+static ssize_t show_global_##_name(struct class_device *class_dev, char *buf) \
+{ \
+	_type##_t	*p = to_##_type(class_dev); \
+	return(show_pid_global(&p->_name, buf)); \
+} \
+struct class_device_attribute _type##_attr_global_##_name = \
+	__ATTR(global,_mode,show_global_##_name, NULL); \
+static ssize_t show_maxplen_##_name(struct class_device *class_dev, char *buf) \
+{ \
+	_type##_t	*p = to_##_type(class_dev); \
+	return(show_pid_maxplen(&p->_name, buf)); \
+} \
+struct class_device_attribute _type##_attr_maxplen_##_name = \
+	__ATTR(maxplen,_mode,show_maxplen_##_name, NULL); \
+static struct attribute *attr_##_name[] = { \
+	&_type##_attr_global_##_name.attr, \
+	&_type##_attr_layermask_##_name.attr, \
+	&_type##_attr_maxplen_##_name.attr, \
+	&_type##_attr_parameter_##_name.attr, \
+	&_type##_attr_protocol_##_name.attr, \
+	NULL \
+}; \
+static struct attribute_group _name##_group = { \
+	.name  = __stringify(_name), \
+	.attrs  = attr_##_name, \
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_inst.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_inst.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_inst.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,140 @@
+/* $Id: sysfs_inst.c,v 1.10 2006/09/06 17:24:22 crich Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * mISDN sysfs stuff for isnstances
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+#include "core.h"
+#include "sysfs.h"
+
+#define to_mISDNinstance(d) container_of(d, mISDNinstance_t, class_dev)
+
+static ssize_t show_inst_id(struct class_device *class_dev, char *buf)
+{
+	mISDNinstance_t	*inst = to_mISDNinstance(class_dev);
+	return sprintf(buf, "%08x\n", inst->id);
+}
+static CLASS_DEVICE_ATTR(id, S_IRUGO, show_inst_id, NULL);
+
+static ssize_t show_inst_name(struct class_device *class_dev, char *buf)
+{
+	mISDNinstance_t	*inst = to_mISDNinstance(class_dev);
+	return sprintf(buf, "%s\n", inst->name);
+}
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_inst_name, NULL);
+
+static ssize_t show_inst_extentions(struct class_device *class_dev, char *buf)
+{
+	mISDNinstance_t	*inst = to_mISDNinstance(class_dev);
+	return sprintf(buf, "%08x\n", inst->extentions);
+}
+static CLASS_DEVICE_ATTR(extentions, S_IRUGO, show_inst_extentions, NULL);
+
+static ssize_t show_inst_regcnt(struct class_device *class_dev, char *buf)
+{
+	mISDNinstance_t	*inst = to_mISDNinstance(class_dev);
+	return sprintf(buf, "%d\n", inst->regcnt);
+}
+static CLASS_DEVICE_ATTR(regcnt, S_IRUGO, show_inst_regcnt, NULL);
+
+#ifdef SYSFS_SUPPORT
+MISDN_PROTO(mISDNinstance, pid, S_IRUGO);
+#endif
+
+static void release_mISDN_inst(struct class_device *dev)
+{
+#ifdef SYSFS_SUPPORT
+	mISDNinstance_t	*inst = to_mISDNinstance(dev);
+
+	if (inst->obj)
+		sysfs_remove_link(&dev->kobj, "obj");
+	sysfs_remove_group(&inst->class_dev.kobj, &pid_group);
+#endif
+	if (core_debug & DEBUG_SYSFS)
+		printk(KERN_INFO "release instance class dev %s\n", dev->class_id);
+}
+
+static struct class inst_dev_class = {
+	.name		= "mISDN-instances",
+#ifndef CLASS_WITHOUT_OWNER
+	.owner		= THIS_MODULE,
+#endif
+	.release	= &release_mISDN_inst,
+};
+
+int
+mISDN_register_sysfs_inst(mISDNinstance_t *inst) {
+	int	err;
+#ifdef SYSFS_SUPPORT
+	char	name[8];
+#endif
+
+	inst->class_dev.class = &inst_dev_class;
+	snprintf(inst->class_dev.class_id, BUS_ID_SIZE, "inst-%08x", inst->id);
+	err = class_device_register(&inst->class_dev);
+	if (err)
+		return(err);
+
+	class_device_create_file(&inst->class_dev, &class_device_attr_id);
+	class_device_create_file(&inst->class_dev, &class_device_attr_name);
+	class_device_create_file(&inst->class_dev, &class_device_attr_extentions);
+	class_device_create_file(&inst->class_dev, &class_device_attr_regcnt);
+
+#ifdef SYSFS_SUPPORT
+	err = sysfs_create_group(&inst->class_dev.kobj, &pid_group);
+	if (err)
+		goto out_unreg;
+	if (inst->obj)
+		sysfs_create_link(&inst->class_dev.kobj, &inst->obj->class_dev.kobj, "obj");
+	if (inst->st) {
+		sprintf(name,"layer.%d", inst->id & LAYER_ID_MASK);
+		sysfs_create_link(&inst->st->class_dev.kobj, &inst->class_dev.kobj, name);
+		sysfs_create_link(&inst->class_dev.kobj, &inst->st->class_dev.kobj, "stack");
+		if (inst->st->mgr == inst) {
+			sysfs_create_link(&inst->st->class_dev.kobj, &inst->class_dev.kobj, "mgr");
+		}
+	}
+#endif
+	return(err);
+
+#ifdef SYSFS_SUPPORT
+out_unreg:
+	class_device_unregister(&inst->class_dev);
+	return(err);
+#endif
+}
+
+void
+mISDN_unregister_sysfs_inst(mISDNinstance_t *inst)
+{
+	char	name[8];
+
+	if (inst && inst->id) {
+		if (inst->st) {
+			sprintf(name,"layer.%d", inst->id & LAYER_ID_MASK);
+
+#ifdef SYSFS_SUPPORT
+			sysfs_remove_link(&inst->st->class_dev.kobj, name);
+			sysfs_remove_link(&inst->class_dev.kobj, "stack");
+			if (inst->st->mgr == inst)
+				sysfs_remove_link(&inst->st->class_dev.kobj, "mgr");
+#endif
+		}
+		class_device_unregister(&inst->class_dev);
+	}
+}
+
+int
+mISDN_sysfs_inst_init(void)
+{
+	return(class_register(&inst_dev_class));
+}
+
+void
+mISDN_sysfs_inst_cleanup(void)
+{
+	class_unregister(&inst_dev_class);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_obj.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_obj.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_obj.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,173 @@
+/* $Id: sysfs_obj.c,v 1.10 2006/08/07 23:35:59 keil Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * mISDN sysfs object and common stuff
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+#include "core.h"
+#include "sysfs.h"
+
+#define to_mISDNobject(d) container_of(d, mISDNobject_t, class_dev)
+
+static ssize_t show_obj_name(struct class_device *class_dev, char *buf)
+{
+	mISDNobject_t *obj = to_mISDNobject(class_dev);
+	return sprintf(buf, "%s\n", obj->name);
+}
+
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_obj_name, NULL);
+
+static ssize_t show_obj_id(struct class_device *class_dev, char *buf)
+{
+	mISDNobject_t *obj = to_mISDNobject(class_dev);
+	return sprintf(buf, "%d\n", obj->id);
+}
+static CLASS_DEVICE_ATTR(id, S_IRUGO, show_obj_id, NULL);
+
+static ssize_t show_obj_refcnt(struct class_device *class_dev, char *buf)
+{
+	mISDNobject_t *obj = to_mISDNobject(class_dev);
+	return sprintf(buf, "%d\n", obj->refcnt);
+}
+static CLASS_DEVICE_ATTR(refcnt, S_IRUGO, show_obj_refcnt, NULL);
+
+ssize_t mISDN_show_pid_protocol(mISDN_pid_t *pid, char *buf)
+{
+	char	*p = buf;
+	uint	i;
+
+	for (i=0; i <= MAX_LAYER_NR; i++)
+		p += sprintf(p,"0x%08x,", pid->protocol[i]);
+	p--;
+	*p++ = '\n';
+	return (p -buf);
+}
+
+ssize_t mISDN_show_pid_parameter(mISDN_pid_t *pid, char *buf)
+{
+	char	*p = buf, *t;
+	uint	i, l;
+
+
+	for (i=0; i <= MAX_LAYER_NR; i++) {
+		if (pid->param[i]) {
+			if (pid->pbuf) {
+				t = pid->param[i] + pid->pbuf;
+				l = *t++;
+				p += sprintf(p,"0x%02x,", l);
+				while(l--)
+					p += sprintf(p,"0x%02x,", *t++);
+			} else {
+				p += sprintf(p,"0x00,");
+			}
+		} else {
+			p += sprintf(p,"0x00,");
+		}
+	}
+	p--;
+	*p++ = '\n';
+	return (p -buf);
+}
+
+#ifdef SYSFS_SUPPORT
+MISDN_PROTO(mISDNobject, BPROTO, S_IRUGO);
+MISDN_PROTO(mISDNobject, DPROTO, S_IRUGO);
+#endif
+
+static void release_mISDN_obj(struct class_device *dev)
+{
+#ifdef SYSFS_SUPPORT
+	mISDNobject_t	*obj = to_mISDNobject(dev);
+
+	if ( core_debug & DEBUG_SYSFS) 
+		printk(KERN_INFO "release object class dev %s\n", dev->class_id);
+
+	if (obj->owner)
+#ifdef MODULE_MKOBJ_POINTER
+	if (obj->owner->mkobj)
+#endif
+		sysfs_remove_link(&dev->kobj, "module");
+	sysfs_remove_group(&obj->class_dev.kobj, &BPROTO_group);
+	sysfs_remove_group(&obj->class_dev.kobj, &DPROTO_group);
+#endif
+
+}
+
+static struct class obj_dev_class = {
+	.name		= "mISDN-objects",
+#ifndef CLASS_WITHOUT_OWNER
+	.owner		= THIS_MODULE,
+#endif
+	.release	= &release_mISDN_obj,
+};
+
+int
+mISDN_register_sysfs_obj(mISDNobject_t *obj) {
+	int	err;
+
+	obj->class_dev.class = &obj_dev_class;
+	snprintf(obj->class_dev.class_id, BUS_ID_SIZE, "obj-%d", obj->id);
+	err = class_device_register(&obj->class_dev);
+	if (err)
+		goto out;
+
+	class_device_create_file(&obj->class_dev, &class_device_attr_id);
+	class_device_create_file(&obj->class_dev, &class_device_attr_name);
+	class_device_create_file(&obj->class_dev, &class_device_attr_refcnt);
+#ifdef SYSFS_SUPPORT
+	err = sysfs_create_group(&obj->class_dev.kobj, &BPROTO_group);
+	if (err)
+		goto out_unreg;
+	err = sysfs_create_group(&obj->class_dev.kobj, &DPROTO_group);
+	if (err)
+		goto out_unreg;
+	if (obj->owner)
+#ifdef MODULE_MKOBJ_POINTER
+		if (obj->owner->mkobj)
+			sysfs_create_link(&obj->class_dev.kobj, &obj->owner->mkobj->kobj, "module");
+#else
+		sysfs_create_link(&obj->class_dev.kobj, &obj->owner->mkobj.kobj, "module");
+#endif
+
+#endif
+	return(err);
+
+#ifdef SYSFS_SUPPORT
+out_unreg:
+	class_device_unregister(&obj->class_dev);
+#endif
+
+out:
+	return(err);
+}
+
+int
+mISDN_sysfs_init(void) {
+	int	err;
+
+	err = class_register(&obj_dev_class);
+	if (err)
+		return(err);
+	err = mISDN_sysfs_inst_init();
+	if (err)
+		goto unreg_obj;
+	err = mISDN_sysfs_st_init();
+	if (err)
+		goto unreg_inst;
+	return(err);
+unreg_inst:
+	mISDN_sysfs_inst_cleanup();
+unreg_obj:
+	class_unregister(&obj_dev_class);
+	return(err);
+}
+
+void
+mISDN_sysfs_cleanup(void) {
+	class_unregister(&obj_dev_class);
+	mISDN_sysfs_inst_cleanup();
+	mISDN_sysfs_st_cleanup();
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_st.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_st.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/sysfs_st.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,289 @@
+/* $Id: sysfs_st.c,v 1.11 2006/09/06 17:24:22 crich Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ * mISDN sysfs stack stuff
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+#include "core.h"
+#include "sysfs.h"
+
+#define to_mISDNstack(d) container_of(d, mISDNstack_t, class_dev)
+
+static ssize_t show_st_id(struct class_device *class_dev, char *buf)
+{
+	mISDNstack_t	*st = to_mISDNstack(class_dev);
+	return sprintf(buf, "%08x\n", st->id);
+}
+static CLASS_DEVICE_ATTR(id, S_IRUGO, show_st_id, NULL);
+
+static ssize_t show_st_status(struct class_device *class_dev, char *buf)
+{
+	mISDNstack_t	*st = to_mISDNstack(class_dev);
+	return sprintf(buf, "0x%08lx\n", st->status);
+}
+
+static ssize_t store_st_status(struct class_device *class_dev, const char *buf, size_t count)
+{
+	mISDNstack_t	*st = to_mISDNstack(class_dev);
+	ulong	status;
+	int	err;
+
+	status = simple_strtol(buf, NULL, 0);
+	printk(KERN_DEBUG "%s: status %08lx\n", __FUNCTION__, status);
+	if (status == (1<<mISDN_STACK_INIT)) {
+		/* we want to make st->new_pid activ */
+		err = clear_stack(st, 1);
+		if (err) {
+			int_errtxt("clear_stack:%d", err);
+			return(err);
+		}
+		err = set_stack(st ,&st->new_pid);
+		if (err) {
+			int_errtxt("set_stack:%d", err);
+			return(err);
+		}
+		return(count);
+	} else if (status == (1<<mISDN_STACK_THREADSTART)) {
+		/* we want to start a new process after abort */
+		err = mISDN_start_stack_thread(st);
+		if (err) {
+			int_errtxt("start_stack_thread:%d", err);
+			return(err);
+		}
+		return(count);
+	}
+	st->status = status;
+	wake_up_interruptible(&st->workq);
+	return(count);
+}
+static CLASS_DEVICE_ATTR(status, S_IRUGO | S_IWUSR, show_st_status, store_st_status);
+
+static ssize_t store_st_protocol(struct class_device *class_dev, const char *buf, size_t count)
+{
+	mISDNstack_t	*st = to_mISDNstack(class_dev);
+	ulong	tmp;
+	char	*p = (char *)buf;
+	u_int	i;
+
+	memset(&st->new_pid.protocol, 0, (MAX_LAYER_NR + 1)*sizeof(st->new_pid.protocol[0]));
+	for (i=0; i<=MAX_LAYER_NR; i++) {
+		if (!*p)
+			break;
+		tmp = simple_strtol(p, &p, 0);
+		st->new_pid.protocol[i] = tmp;
+		if (*p)
+			p++;
+	}
+	if (*p)
+		int_errtxt("overflow");
+	return(count);
+}
+
+static ssize_t store_st_layermask(struct class_device *class_dev, const char *buf, size_t count)
+{
+	mISDNstack_t	*st = to_mISDNstack(class_dev);
+	ulong		mask = (1<<(MAX_LAYER_NR + 1)) -1;
+
+	st->new_pid.layermask = simple_strtol(buf, NULL, 0);
+	if (st->new_pid.layermask > mask) {
+		int_errtxt("overflow");
+		st->new_pid.layermask &= mask;
+	}
+	return(count);
+}
+
+static ssize_t store_st_parameter(struct class_device *class_dev, const char *buf, size_t count)
+{
+	mISDNstack_t	*st = to_mISDNstack(class_dev);
+	ulong	tmp;
+	char	*p = (char *)buf;
+	u_int	i, j, l;
+
+	memset(&st->new_pid.param, 0, (MAX_LAYER_NR + 1)*sizeof(st->new_pid.param[0]));
+	kfree(st->new_pid.pbuf);
+	l = 0;
+	for (i=0; i<=MAX_LAYER_NR; i++) {
+		if (!*p)
+			break;
+		tmp = simple_strtol(p, &p, 0);
+		if (*p)
+			p++;
+		if (tmp) {
+			j = tmp;
+			l += j+1;
+			while(j--) {
+				if (!*p)
+					break;
+				tmp = simple_strtol(p, &p, 0);
+				if (*p)
+					p++;
+				else
+					break;
+			}
+		}
+	}
+	if (*p)
+		int_errtxt("overflow");
+	if (l == 0) {
+		st->new_pid.maxplen = 0;
+		return(count);
+	}
+	st->new_pid.pbuf = kzalloc(l + 1, GFP_ATOMIC);
+	if (!st->new_pid.pbuf)
+		return(-ENOMEM);
+	st->new_pid.maxplen = l + 1;
+	st->new_pid.pidx = 1;
+	p = (char *)buf;
+	for (i=0; i<=MAX_LAYER_NR; i++) {
+		if (!*p)
+			break;
+		tmp = simple_strtol(p, &p, 0);
+		if (*p)
+			p++;
+		if (tmp) {
+			j = tmp;
+			st->new_pid.param[i] = st->new_pid.pidx;
+			st->new_pid.pbuf[st->new_pid.pidx++] = tmp & 0xff;
+			while(j--) {
+				if (!*p)
+					break;
+				tmp = simple_strtol(p, &p, 0);
+				st->new_pid.pbuf[st->new_pid.pidx++] = tmp & 0xff;
+				if (*p)
+					p++;
+				else
+					break;
+			}
+		}
+	}
+	return(count);
+}
+
+#ifdef SYSFS_SUPPORT
+MISDN_PROTO(mISDNstack, pid, S_IRUGO);
+#endif
+MISDN_PROTO(mISDNstack, new_pid, S_IRUGO);
+
+static ssize_t show_st_qlen(struct class_device *class_dev, char *buf)
+{
+	mISDNstack_t	*st = to_mISDNstack(class_dev);
+	return sprintf(buf, "%d\n", skb_queue_len(&st->msgq));
+}
+static CLASS_DEVICE_ATTR(qlen, S_IRUGO, show_st_qlen, NULL);
+
+static void release_mISDN_stack(struct class_device *dev)
+{
+#ifdef SYSFS_SUPPORT
+	mISDNstack_t	*st = to_mISDNstack(dev);
+	char		name[12];
+
+	sysfs_remove_group(&st->class_dev.kobj, &pid_group);
+	sysfs_remove_group(&st->class_dev.kobj, &new_pid_group);
+	if (core_debug & DEBUG_SYSFS)
+		printk(KERN_INFO "release stack class dev %s\n", dev->class_id);
+	if (st->parent) {
+		sysfs_remove_link(&dev->kobj, "parent");
+		snprintf(name, 12, "child%d", (CHILD_ID_MASK & st->id) >> 16);
+		sysfs_remove_link(&st->parent->class_dev.kobj, name);
+
+	}
+	if (st->master) {
+		sysfs_remove_link(&dev->kobj, "master");
+		snprintf(name, 12, "clone%d", (CLONE_ID_MASK & st->id) >> 16);
+		sysfs_remove_link(&st->master->class_dev.kobj, name);
+	}
+#endif
+
+}
+
+static struct class stack_dev_class = {
+	.name		= "mISDN-stacks",
+#ifndef CLASS_WITHOUT_OWNER
+	.owner		= THIS_MODULE,
+#endif
+	.release	= &release_mISDN_stack,
+};
+
+int
+mISDN_register_sysfs_stack(mISDNstack_t *st)
+{
+	int	err;
+#ifdef SYSFS_SUPPORT
+	char	name[12];
+#endif
+
+	st->class_dev.class = &stack_dev_class;
+	if (st->id & FLG_CHILD_STACK)
+		snprintf(st->class_dev.class_id, BUS_ID_SIZE, "chst-%08x", st->id);
+	else if (st->id & FLG_CLONE_STACK)
+		snprintf(st->class_dev.class_id, BUS_ID_SIZE, "clst-%08x", st->id);
+	else
+		snprintf(st->class_dev.class_id, BUS_ID_SIZE, "st-%08x", st->id);
+	if (st->mgr)
+		st->class_dev.dev = st->mgr->class_dev.dev;
+	err = class_device_register(&st->class_dev);
+	if (err)
+		return(err);
+#ifdef SYSFS_SUPPORT
+	err = sysfs_create_group(&st->class_dev.kobj, &pid_group);
+	if (err)
+		goto out_unreg;
+#endif
+	mISDNstack_attr_protocol_new_pid.attr.mode |= S_IWUSR;
+	mISDNstack_attr_protocol_new_pid.store = store_st_protocol;
+	mISDNstack_attr_parameter_new_pid.attr.mode |= S_IWUSR;
+	mISDNstack_attr_parameter_new_pid.store = store_st_parameter;
+	mISDNstack_attr_layermask_new_pid.attr.mode |= S_IWUSR;
+	mISDNstack_attr_layermask_new_pid.store = store_st_layermask;
+
+#ifdef SYSFS_SUPPORT
+	err = sysfs_create_group(&st->class_dev.kobj, &new_pid_group);
+	if (err)
+		goto out_unreg;
+#endif
+
+	class_device_create_file(&st->class_dev, &class_device_attr_id);
+	class_device_create_file(&st->class_dev, &class_device_attr_qlen);
+	class_device_create_file(&st->class_dev, &class_device_attr_status);
+
+#ifdef SYSFS_SUPPORT
+	if (st->parent) {
+		sysfs_create_link(&st->class_dev.kobj, &st->parent->class_dev.kobj, "parent");
+		snprintf(name, 12, "child%d", (CHILD_ID_MASK & st->id) >> 16);
+		sysfs_create_link(&st->parent->class_dev.kobj, &st->class_dev.kobj, name);
+	}
+	if (st->master) {
+		sysfs_create_link(&st->class_dev.kobj, &st->master->class_dev.kobj, "master");
+		snprintf(name, 12, "clone%d", (CLONE_ID_MASK & st->id) >> 16);
+		sysfs_create_link(&st->master->class_dev.kobj, &st->class_dev.kobj, name);
+	}
+#endif
+	return(err);
+
+#ifdef SYSFS_SUPPORT
+out_unreg:
+	class_device_unregister(&st->class_dev);
+	return(err);
+#endif
+}
+
+void
+mISDN_unregister_sysfs_st(mISDNstack_t *st)
+{
+	class_device_unregister(&st->class_dev);
+}
+
+int
+mISDN_sysfs_st_init(void)
+{
+	return(class_register(&stack_dev_class));
+}
+
+void
+mISDN_sysfs_st_cleanup(void)
+{
+	class_unregister(&stack_dev_class);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/tei.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/tei.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/tei.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,520 @@
+/* $Id: tei.c,v 1.11 2006/03/23 13:11:43 keil Exp $
+ *
+ * Author       Karsten Keil (keil at isdn4linux.de)
+ *
+ *		This file is (c) under GNU PUBLIC LICENSE
+ *		For changes and modifications please read
+ *		../../../Documentation/isdn/mISDN.cert
+ *
+ */
+#include "layer2.h"
+#include "helper.h"
+#include "debug.h"
+#include <linux/random.h>
+
+const char *tei_revision = "$Revision: 1.11 $";
+
+#define ID_REQUEST	1
+#define ID_ASSIGNED	2
+#define ID_DENIED	3
+#define ID_CHK_REQ	4
+#define ID_CHK_RES	5
+#define ID_REMOVE	6
+#define ID_VERIFY	7
+
+#define TEI_ENTITY_ID	0xf
+
+static
+struct Fsm teifsm =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_TEI_NOP,
+	ST_TEI_IDREQ,
+	ST_TEI_IDVERIFY,
+};
+
+#define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1)
+
+static char *strTeiState[] =
+{
+	"ST_TEI_NOP",
+	"ST_TEI_IDREQ",
+	"ST_TEI_IDVERIFY",
+};
+
+enum {
+	EV_IDREQ,
+	EV_ASSIGN,
+	EV_ASSIGN_REQ,
+	EV_DENIED,
+	EV_CHKREQ,
+	EV_REMOVE,
+	EV_VERIFY,
+	EV_T202,
+};
+
+#define TEI_EVENT_COUNT (EV_T202+1)
+
+static char *strTeiEvent[] =
+{
+	"EV_IDREQ",
+	"EV_ASSIGN",
+	"EV_ASSIGN_REQ",
+	"EV_DENIED",
+	"EV_CHKREQ",
+	"EV_REMOVE",
+	"EV_VERIFY",
+	"EV_T202",
+};
+
+unsigned int
+random_ri(void)
+{
+	unsigned int x;
+
+	get_random_bytes(&x, sizeof(x));
+	return (x & 0xffff);
+}
+
+static teimgr_t *
+findtei(teimgr_t *tm, int tei)
+{
+	static teimgr_t *ptr = NULL;
+	struct sk_buff *skb;
+
+	if (tei == 127)
+		return (NULL);
+	skb = create_link_skb(MDL_FINDTEI | REQUEST, tei, sizeof(void), &ptr, 0);
+	if (!skb)
+		return (NULL);
+	if (!tei_l2(tm->l2, skb))
+		return(ptr);
+	dev_kfree_skb(skb);
+	return (NULL);
+}
+
+static void
+put_tei_msg(teimgr_t *tm, u_char m_id, unsigned int ri, u_char tei)
+{
+	struct sk_buff *skb;
+	u_char bp[8];
+
+	bp[0] = (TEI_SAPI << 2);
+	if (test_bit(FLG_LAPD_NET, &tm->l2->flag))
+		bp[0] |= 2; /* CR:=1 for net command */
+	bp[1] = (GROUP_TEI << 1) | 0x1;
+	bp[2] = UI;
+	bp[3] = TEI_ENTITY_ID;
+	bp[4] = ri >> 8;
+	bp[5] = ri & 0xff;
+	bp[6] = m_id;
+	bp[7] = (tei << 1) | 1;
+	skb = create_link_skb(MDL_UNITDATA | REQUEST, 0, 8, bp, 0);
+	if (!skb) {
+		printk(KERN_WARNING "mISDN: No skb for TEI manager\n");
+		return;
+	}
+	if (tei_l2(tm->l2, skb))
+		dev_kfree_skb(skb);
+}
+
+static void
+tei_id_request(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+
+	if (tm->l2->tei != -1) {
+		tm->tei_m.printdebug(&tm->tei_m,
+			"assign request for allready assigned tei %d",
+			tm->l2->tei);
+		return;
+	}
+	tm->ri = random_ri();
+	if (tm->debug)
+		tm->tei_m.printdebug(&tm->tei_m,
+			"assign request ri %d", tm->ri);
+	put_tei_msg(tm, ID_REQUEST, tm->ri, 127);
+	mISDN_FsmChangeState(fi, ST_TEI_IDREQ);
+	mISDN_FsmAddTimer(&tm->t202, tm->T202, EV_T202, NULL, 1);
+	tm->N202 = 3;
+}
+
+static void
+tei_assign_req(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+	u_char *dp = arg;
+
+	if (tm->l2->tei == -1) {
+		tm->tei_m.printdebug(&tm->tei_m,
+			"net tei assign request without tei");
+		return;
+	}
+	tm->ri = ((unsigned int) *dp++ << 8);
+	tm->ri += *dp++;
+	if (tm->debug)
+		tm->tei_m.printdebug(&tm->tei_m,
+			"net assign request ri %d teim %d", tm->ri, *dp);
+	put_tei_msg(tm, ID_ASSIGNED, tm->ri, tm->l2->tei);
+	mISDN_FsmChangeState(fi, ST_TEI_NOP);
+}
+
+static void
+tei_id_assign(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *otm, *tm = fi->userdata;
+	struct sk_buff *skb;
+	u_char *dp = arg;
+	int ri, tei;
+
+	ri = ((unsigned int) *dp++ << 8);
+	ri += *dp++;
+	dp++;
+	tei = *dp >> 1;
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "identity assign ri %d tei %d",
+			ri, tei);
+	if ((otm = findtei(tm, tei))) {	/* same tei is in use */
+		if (ri != otm->ri) {
+			tm->tei_m.printdebug(fi,
+				"possible duplicate assignment tei %d", tei);
+			skb = create_link_skb(MDL_ERROR | RESPONSE, 0, 0,
+				NULL, 0);
+			if (!skb)
+				return;
+			if (tei_l2(otm->l2, skb))
+				dev_kfree_skb(skb);
+		}
+	} else if (ri == tm->ri) {
+		mISDN_FsmDelTimer(&tm->t202, 1);
+		mISDN_FsmChangeState(fi, ST_TEI_NOP);
+		skb = create_link_skb(MDL_ASSIGN | REQUEST, tei, 0, NULL, 0);
+		if (!skb)
+			return;
+		if (tei_l2(tm->l2, skb))
+			dev_kfree_skb(skb);
+//		cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
+	}
+}
+
+static void
+tei_id_test_dup(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *otm, *tm = fi->userdata;
+	u_char *dp = arg;
+	int tei, ri;
+
+	ri = ((unsigned int) *dp++ << 8);
+	ri += *dp++;
+	dp++;
+	tei = *dp >> 1;
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d",
+			ri, tei);
+	if ((otm = findtei(tm, tei))) {	/* same tei is in use */
+		if (ri != otm->ri) {	/* and it wasn't our request */
+			tm->tei_m.printdebug(fi,
+				"possible duplicate assignment tei %d", tei);
+			mISDN_FsmEvent(&otm->tei_m, EV_VERIFY, NULL);
+		}
+	} 
+}
+
+static void
+tei_id_denied(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+	u_char *dp = arg;
+	int ri, tei;
+
+	ri = ((unsigned int) *dp++ << 8);
+	ri += *dp++;
+	dp++;
+	tei = *dp >> 1;
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "identity denied ri %d tei %d",
+			ri, tei);
+}
+
+static void
+tei_id_chk_req(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+	u_char *dp = arg;
+	int tei;
+
+	tei = *(dp+3) >> 1;
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "identity check req tei %d", tei);
+	if ((tm->l2->tei != -1) && ((tei == GROUP_TEI) || (tei == tm->l2->tei))) {
+		mISDN_FsmDelTimer(&tm->t202, 4);
+		mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP);
+		put_tei_msg(tm, ID_CHK_RES, random_ri(), tm->l2->tei);
+	}
+}
+
+static void
+tei_id_remove(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+	u_char *dp = arg;
+	struct sk_buff *skb;
+	int tei;
+
+	tei = *(dp+3) >> 1;
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "identity remove tei %d", tei);
+	if ((tm->l2->tei != -1) && ((tei == GROUP_TEI) || (tei == tm->l2->tei))) {
+		mISDN_FsmDelTimer(&tm->t202, 5);
+		mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP);
+		skb = create_link_skb(MDL_REMOVE | REQUEST, 0, 0, NULL, 0);
+		if (!skb)
+			return;
+		if (tei_l2(tm->l2, skb))
+			dev_kfree_skb(skb);
+//		cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
+	}
+}
+
+static void
+tei_id_verify(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+
+	if (tm->debug)
+		tm->tei_m.printdebug(fi, "id verify request for tei %d",
+			tm->l2->tei);
+	put_tei_msg(tm, ID_VERIFY, 0, tm->l2->tei);
+	mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY);
+	mISDN_FsmAddTimer(&tm->t202, tm->T202, EV_T202, NULL, 2);
+	tm->N202 = 2;
+}
+
+static void
+tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+	struct sk_buff *skb;
+
+	if (--tm->N202) {
+		tm->ri = random_ri();
+		if (tm->debug)
+			tm->tei_m.printdebug(fi, "assign req(%d) ri %d",
+				4 - tm->N202, tm->ri);
+		put_tei_msg(tm, ID_REQUEST, tm->ri, 127);
+		mISDN_FsmAddTimer(&tm->t202, tm->T202, EV_T202, NULL, 3);
+	} else {
+		tm->tei_m.printdebug(fi, "assign req failed");
+		skb = create_link_skb(MDL_ERROR | REQUEST, 0, 0, NULL, 0);
+		if (!skb)
+			return;
+		if (tei_l2(tm->l2, skb))
+			dev_kfree_skb(skb);
+//		cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
+		mISDN_FsmChangeState(fi, ST_TEI_NOP);
+	}
+}
+
+static void
+tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
+{
+	teimgr_t *tm = fi->userdata;
+	struct sk_buff *skb;
+
+	if (--tm->N202) {
+		if (tm->debug)
+			tm->tei_m.printdebug(fi,
+				"id verify req(%d) for tei %d",
+				3 - tm->N202, tm->l2->tei);
+		put_tei_msg(tm, ID_VERIFY, 0, tm->l2->tei);
+		mISDN_FsmAddTimer(&tm->t202, tm->T202, EV_T202, NULL, 4);
+	} else {
+		tm->tei_m.printdebug(fi, "verify req for tei %d failed",
+			tm->l2->tei);
+		skb = create_link_skb(MDL_REMOVE | REQUEST, 0, 0, NULL, 0);
+		if (!skb)
+			return;
+		if (tei_l2(tm->l2, skb))
+			dev_kfree_skb(skb);
+//		cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
+		mISDN_FsmChangeState(fi, ST_TEI_NOP);
+	}
+}
+
+static int
+tei_ph_data_ind(teimgr_t *tm, int dtyp, struct sk_buff *skb)
+{
+	u_char *dp;
+	int mt;
+	int ret = -EINVAL;
+
+	if (!skb)
+		return(ret);
+	if (test_bit(FLG_FIXED_TEI, &tm->l2->flag) &&
+		!test_bit(FLG_LAPD_NET, &tm->l2->flag))
+		return(ret);
+	if (skb->len < 8) {
+		tm->tei_m.printdebug(&tm->tei_m,
+			"short mgr frame %ld/8", skb->len);
+		return(ret);
+	}
+	dp = skb->data + 2;
+	if ((*dp & 0xef) != UI) {
+		tm->tei_m.printdebug(&tm->tei_m,
+			"mgr frame is not ui %x", *dp);
+		return(ret);
+	}
+	dp++;
+	if (*dp++ != TEI_ENTITY_ID) {
+		/* wrong management entity identifier, ignore */
+		dp--;
+		tm->tei_m.printdebug(&tm->tei_m,
+			"tei handler wrong entity id %x", *dp);
+		return(ret);
+	} else {
+		mt = *(dp+2);
+		if (tm->debug)
+			tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt);
+		if (mt == ID_ASSIGNED)
+			mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp);
+		else if (mt == ID_DENIED)
+			mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp);
+		else if (mt == ID_CHK_REQ)
+			mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp);
+		else if (mt == ID_REMOVE)
+			mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp);
+		else if (mt == ID_REQUEST && 
+			test_bit(FLG_LAPD_NET, &tm->l2->flag))
+			mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN_REQ, dp);
+		else {
+			tm->tei_m.printdebug(&tm->tei_m,
+				"tei handler wrong mt %x", mt);
+			return(ret);
+		}
+	}
+	dev_kfree_skb(skb);
+	return(0);
+}
+
+int
+l2_tei(teimgr_t *tm, struct sk_buff *skb)
+{
+	mISDN_head_t	*hh;
+	int		ret = -EINVAL;
+
+	if (!tm || !skb)
+		return(ret);
+	hh = mISDN_HEAD_P(skb);
+	if (tm->debug)
+		printk(KERN_DEBUG "%s: prim(%x)\n", __FUNCTION__, hh->prim);
+	switch(hh->prim) {
+	    case (MDL_UNITDATA | INDICATION):
+	    	return(tei_ph_data_ind(tm, hh->dinfo, skb));
+	    case (MDL_ASSIGN | INDICATION):
+		if (test_bit(FLG_FIXED_TEI, &tm->l2->flag)) {
+			if (tm->debug)
+				tm->tei_m.printdebug(&tm->tei_m,
+					"fixed assign tei %d", tm->l2->tei);
+			skb_trim(skb, 0);
+			mISDN_sethead(MDL_ASSIGN | REQUEST, tm->l2->tei, skb);
+			if (!tei_l2(tm->l2, skb))
+				return(0);
+//			cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
+		} else
+			mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL);
+		break;
+	    case (MDL_ERROR | INDICATION):
+	    	if (!test_bit(FLG_FIXED_TEI, &tm->l2->flag))
+			mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL);
+		break;
+	}
+	dev_kfree_skb(skb);
+	return(0);
+}
+
+static void
+tei_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	teimgr_t	*tm = fi->userdata;
+	logdata_t	log;
+	char		head[24];
+
+	va_start(log.args, fmt);
+	sprintf(head,"tei %s", tm->l2->inst.name);
+	log.fmt = fmt;
+	log.head = head;
+	mISDN_ctrl(&tm->l2->inst, MGR_DEBUGDATA | REQUEST, &log);
+	va_end(log.args);
+}
+
+static struct FsmNode TeiFnList[] =
+{
+	{ST_TEI_NOP, EV_IDREQ, tei_id_request},
+	{ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
+	{ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req},
+	{ST_TEI_NOP, EV_VERIFY, tei_id_verify},
+	{ST_TEI_NOP, EV_REMOVE, tei_id_remove},
+	{ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req},
+	{ST_TEI_IDREQ, EV_T202, tei_id_req_tout},
+	{ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign},
+	{ST_TEI_IDREQ, EV_DENIED, tei_id_denied},
+	{ST_TEI_IDVERIFY, EV_T202, tei_id_ver_tout},
+	{ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
+	{ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
+};
+
+#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
+
+void
+release_tei(teimgr_t *tm)
+{
+	mISDN_FsmDelTimer(&tm->t202, 1);
+	kfree(tm);
+}
+
+int
+create_teimgr(layer2_t *l2) {
+	teimgr_t *ntei;
+
+	if (!l2) {
+		printk(KERN_ERR "create_tei no layer2\n");
+		return(-EINVAL);
+	}
+	if (!(ntei = kmalloc(sizeof(teimgr_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc teimgr failed\n");
+		return(-ENOMEM);
+	}
+	memset(ntei, 0, sizeof(teimgr_t));
+	ntei->l2 = l2;
+	ntei->T202 = 2000;	/* T202  2000 milliseconds */
+	ntei->debug = l2->debug;
+	ntei->tei_m.debug = l2->debug;
+	ntei->tei_m.userdata = ntei;
+	ntei->tei_m.printdebug = tei_debug;
+	if (test_bit(FLG_LAPD_NET, &l2->flag)) {
+		ntei->tei_m.fsm = &teifsm;
+		ntei->tei_m.state = ST_TEI_NOP;
+	} else {
+		ntei->tei_m.fsm = &teifsm;
+		ntei->tei_m.state = ST_TEI_NOP;
+	}
+	mISDN_FsmInitTimer(&ntei->tei_m, &ntei->t202);
+	l2->tm = ntei;
+	return(0);
+}
+
+int TEIInit(void)
+{
+	teifsm.state_count = TEI_STATE_COUNT;
+	teifsm.event_count = TEI_EVENT_COUNT;
+	teifsm.strEvent = strTeiEvent;
+	teifsm.strState = strTeiState;
+	mISDN_FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT);
+	return(0);
+}
+
+void TEIFree(void)
+{
+	mISDN_FsmFree(&teifsm);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/udevice.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/udevice.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/udevice.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,2035 @@
+/* $Id: udevice.c,v 1.25 2007/02/13 10:43:45 crich Exp $
+ *
+ * Copyright 2000  by Karsten Keil <kkeil at isdn4linux.de>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/poll.h>
+#include <linux/vmalloc.h>
+#include <linux/timer.h>
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+#include "core.h"
+
+#define MAX_HEADER_LEN	4
+
+#define FLG_MGR_SETSTACK	1
+#define FLG_MGR_OWNSTACK	2
+
+#define FLG_MGR_TIMER_INIT	1
+#define	FLG_MGR_TIMER_RUNING	2
+
+#define MAX_USERDEVICE_ID	MAX_LAYER_NR
+
+typedef struct _devicelayer {
+	struct list_head	list;
+	mISDNdevice_t		*dev;
+	mISDNinstance_t		inst;
+	mISDNinstance_t		*slave;
+//	mISDNif_t		s_up;
+//	mISDNif_t		s_down;
+	u_int			id;
+	u_int			lm_st;
+	u_long			Flags;
+} devicelayer_t;
+
+typedef struct _devicestack {
+	struct list_head	list;
+	mISDNdevice_t		*dev;
+	mISDNstack_t		*st;
+	int			extentions;
+} devicestack_t;
+
+typedef struct _mISDNtimer {
+	struct list_head	list;
+	struct _mISDNdevice	*dev;
+	struct timer_list	tl;
+	u_int			id;
+	u_long			Flags;
+} mISDNtimer_t;
+
+typedef struct entity_item {
+	struct list_head	head;
+	int			entity;
+} entity_item_t;
+
+static LIST_HEAD(mISDN_devicelist);
+static rwlock_t	mISDN_device_lock = RW_LOCK_UNLOCKED;
+
+static mISDNobject_t	udev_obj;
+static char MName[] = "UserDevice";
+
+static int device_debug = 0;
+
+static int from_up_down(mISDNinstance_t *, struct sk_buff *);
+
+// static int from_peer(mISDNif_t *, u_int, int, int, void *);
+// static int to_peer(mISDNif_t *, u_int, int, int, void *);
+
+
+static mISDNdevice_t *
+get_mISDNdevice4minor(int minor)
+{
+	mISDNdevice_t	*dev;
+
+	read_lock(&mISDN_device_lock);
+	list_for_each_entry(dev, &mISDN_devicelist, list) {
+		if (dev->minor == minor) {
+			read_unlock(&mISDN_device_lock);
+			return(dev);
+		}
+	}
+	read_unlock(&mISDN_device_lock);
+	return(NULL);
+}
+
+#ifdef FIXME
+static int
+mISDN_rdata_raw(mISDNinstance_t *inst, struct sk_buff *skb) {
+	mISDNdevice_t	*dev;
+	mISDN_head_t	*hh;
+	u_long		flags;
+	int		retval = 0;
+
+	dev = inst->priv;
+	hh = mISDN_HEAD_P(skb);
+	if (hh->prim == (PH_DATA | INDICATION)) {
+		if (test_bit(FLG_mISDNPORT_OPEN, &dev->rport.Flag)) {
+			spin_lock_irqsave(&dev->rport.lock, flags);
+			if (skb_queue_len(&dev->rport.queue) >= dev->rport.maxqlen)
+				retval = -ENOSPC;
+			else
+				skb_queue_tail(&dev->rport.queue, skb);
+			spin_unlock_irqrestore(&dev->rport.lock, flags);
+			wake_up_interruptible(&dev->rport.procq);
+		} else {
+			printk(KERN_WARNING "%s: PH_DATA_IND device(%d) not read open\n",
+				__FUNCTION__, dev->minor);
+			retval = -ENOENT;
+		}
+	} else if (hh->prim == (PH_DATA | CONFIRM)) {
+		test_and_clear_bit(FLG_mISDNPORT_BLOCK, &dev->wport.Flag);
+		dev_kfree_skb_any(skb);
+		spin_lock_irqsave(&dev->wport.lock, flags);
+		if (test_and_set_bit(FLG_mISDNPORT_BUSY, &dev->wport.Flag)) {
+			spin_unlock_irqrestore(&dev->wport.lock, flags);
+			return(0);
+		}
+		while ((skb = skb_dequeue(&dev->wport.queue))) {
+			if (device_debug & DEBUG_DEV_OP)
+				printk(KERN_DEBUG "%s: wflg(%lx)\n", __FUNCTION__, dev->wport.Flag);
+			if (test_bit(FLG_mISDNPORT_BLOCK, &dev->wport.Flag)) {
+				skb_queue_head(&dev->wport.queue, skb); 
+				break;
+			}
+			if (test_bit(FLG_mISDNPORT_ENABLED, &dev->wport.Flag)) {
+				spin_unlock_irqrestore(&dev->wport.lock, flags);
+				retval = if_newhead(&dev->wport.pif, PH_DATA | REQUEST, (int)skb, skb);
+				spin_lock_irqsave(&dev->wport.lock, flags);
+				if (retval) {
+					printk(KERN_WARNING "%s: dev(%d) down err(%d)\n",
+						__FUNCTION__, dev->minor, retval);
+					dev_kfree_skb(skb);
+				} else {
+					test_and_set_bit(FLG_mISDNPORT_BLOCK, &dev->wport.Flag);
+					wake_up(&dev->wport.procq);
+					break;
+				}
+			} else {
+				printk(KERN_WARNING "%s: dev(%d) wport not enabled\n",
+					__FUNCTION__, dev->minor);
+				dev_kfree_skb(skb);
+			}
+			wake_up(&dev->wport.procq);
+		}
+		test_and_clear_bit(FLG_mISDNPORT_BUSY, &dev->wport.Flag);
+		spin_unlock_irqrestore(&dev->wport.lock, flags);
+	} else if ((hh->prim == (PH_ACTIVATE | CONFIRM)) ||
+		(hh->prim == (PH_ACTIVATE | INDICATION))) {
+			test_and_set_bit(FLG_mISDNPORT_ENABLED,
+				&dev->wport.Flag);
+			test_and_clear_bit(FLG_mISDNPORT_BLOCK,
+				&dev->wport.Flag);
+	} else if ((hh->prim == (PH_DEACTIVATE | CONFIRM)) ||
+		(hh->prim == (PH_DEACTIVATE | INDICATION))) {
+			test_and_clear_bit(FLG_mISDNPORT_ENABLED,
+				&dev->wport.Flag);
+	} else {
+		printk(KERN_WARNING "%s: prim(%x) dinfo(%x) not supported\n",
+			__FUNCTION__, hh->prim, hh->dinfo);
+		retval = -EINVAL;
+	}
+	if (!retval)
+		dev_kfree_skb_any(skb);
+	return(retval);
+}
+#endif
+
+static int
+mISDN_rdata(mISDNdevice_t *dev, struct sk_buff *skb)
+{
+	mISDN_head_t	*hp;
+	u_long		flags;
+
+	hp = mISDN_HEAD_P(skb);
+	if (hp->len <= 0)
+		skb_trim(skb, 0);
+	if (device_debug & DEBUG_RDATA)
+		printk(KERN_DEBUG "%s: %x:%x %x %d %d\n",
+			__FUNCTION__, hp->addr, hp->prim, hp->dinfo, hp->len, skb->len);
+	spin_lock_irqsave(&dev->rport.lock, flags);
+
+	if (skb_queue_len(&dev->rport.queue) >= dev->rport.maxqlen) {
+		/*print the rport queue overflow error, only X times per second..*/
+		static unsigned long j;
+		static int flag=1;
+		if (flag) {
+			flag=0;
+			j=jiffies;
+		}
+			
+		if (   jiffies > (j+(HZ*500/1000))  ) {
+			flag=1;
+			printk(KERN_WARNING "%s: rport queue overflow (after 500ms!) %d/%d [addr:%x prim:%x dinfo:%x]\n",
+			       __FUNCTION__, skb_queue_len(&dev->rport.queue), dev->rport.maxqlen,
+			       hp->addr, hp->prim, hp->dinfo);
+		}
+		spin_unlock_irqrestore(&dev->rport.lock, flags);
+		return(-ENOSPC);
+	}
+	skb_queue_tail(&dev->rport.queue, skb);
+	spin_unlock_irqrestore(&dev->rport.lock, flags);
+	wake_up_interruptible(&dev->rport.procq);
+	return(0);
+}
+static int
+error_answer(mISDNdevice_t *dev, struct sk_buff *skb, int err)
+{
+	mISDN_head_t	*hp;
+
+	hp = mISDN_HEAD_P(skb);
+	hp->prim |= 1; /* CONFIRM or RESPONSE */
+	hp->len = err;
+	return(mISDN_rdata(dev, skb));
+}
+
+static devicelayer_t
+*get_devlayer(mISDNdevice_t *dev, u_int addr)
+{
+	devicelayer_t *dl;
+
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "%s: addr:%x\n", __FUNCTION__, addr);
+	list_for_each_entry(dl, &dev->layerlist, list) {
+//		if (device_debug & DEBUG_MGR_FUNC)
+//			printk(KERN_DEBUG "%s: dl(%p) id:%x\n",
+//				__FUNCTION__, dl, dl->id);
+		if (dl->id == (INST_ID_MASK & addr))
+			return(dl);
+		if (dl->inst.id == (INST_ID_MASK & addr))
+			return(dl);
+		if (dl->slave && (dl->slave->id == (INST_ID_MASK & addr)))
+			return(dl);
+	}
+	return(NULL);
+}
+
+static u_int
+get_new_devicelayer_id(mISDNdevice_t *dev, u_int addr)
+{
+	devicelayer_t	*dl;
+	u_int		i, found;
+
+	addr |= (FLG_INSTANCE | FLG_ID_USER);
+	for (i=0; i<= MAX_USERDEVICE_ID; i++) {
+		found = 0;
+		list_for_each_entry(dl, &dev->layerlist, list) {
+			if (dl->id == (addr | i))
+				found++;
+		}
+		if (!found)
+			return(addr | i);
+	}
+	return(0);
+}
+
+static devicestack_t
+*get_devstack(mISDNdevice_t *dev, int addr)
+{
+	devicestack_t *ds;
+
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "%s: addr:%x\n", __FUNCTION__, addr);
+	list_for_each_entry(ds, &dev->stacklist, list) {
+		if (ds->st && (ds->st->id == (u_int)addr))
+			return(ds);
+	}
+	return(NULL);
+}
+
+static mISDNtimer_t
+*get_devtimer(mISDNdevice_t *dev, int id)
+{
+	mISDNtimer_t	*ht;
+
+	if (device_debug & DEBUG_DEV_TIMER)
+		printk(KERN_DEBUG "%s: dev:%p id:%x\n", __FUNCTION__, dev, id);
+	list_for_each_entry(ht, &dev->timerlist, list) {
+		if (ht->id == id)
+			return(ht);
+	}
+	return(NULL);
+}
+
+static int
+stack_inst_flg(mISDNdevice_t *dev, mISDNstack_t *st, int bit, int clear)
+{
+	int ret;
+	devicelayer_t *dl;
+
+	list_for_each_entry(dl, &dev->layerlist, list) {
+		if (dl->inst.st == st) {
+			if (clear)
+				ret = test_and_clear_bit(bit, &dl->Flags);
+			else
+				ret = test_and_set_bit(bit, &dl->Flags);
+			return(ret);
+		}
+	}
+	return(-1);
+}
+
+static int
+new_devstack(mISDNdevice_t *dev, stack_info_t *si)
+{
+	int		err;
+	mISDNstack_t	*st;
+	mISDNinstance_t	inst;
+	devicestack_t	*nds;
+
+	memset(&inst, 0, sizeof(mISDNinstance_t));
+	st = get_stack4id(si->id);
+	if (si->extentions & EXT_STACK_CLONE) {
+		if (st) {
+			inst.st = st;
+		} else {
+			int_errtxt("ext(%x) st(%x)", si->extentions, si->id);
+			return(-EINVAL);
+		}
+	}
+	err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &inst);
+	if (err) {
+		int_error();
+		return(err);
+	}
+	if (!(nds = kmalloc(sizeof(devicestack_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc devicestack failed\n");
+		mISDN_ctrl(inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return(-ENOMEM);
+	}
+	memset(nds, 0, sizeof(devicestack_t));
+	nds->dev = dev;
+	if (si->extentions & EXT_STACK_CLONE) {
+//		memcpy(&inst.st->pid, &st->pid, sizeof(mISDN_pid_t));
+		// FIXME that is a ugly idea, but I don't have a better one 
+		inst.st->childlist.prev = &st->childlist;
+	} else {
+		memcpy(&inst.st->pid, &si->pid, sizeof(mISDN_pid_t));
+	}
+	nds->extentions = si->extentions;
+	inst.st->extentions |= si->extentions;
+	inst.st->mgr = get_instance4id(si->mgr);
+	nds->st = inst.st;
+	list_add_tail(&nds->list, &dev->stacklist);
+	return(inst.st->id);
+}
+
+static mISDNstack_t *
+sel_channel(u_int addr, u_int channel)
+{
+	mISDNstack_t	*st;
+	channel_info_t	ci;
+
+	st = get_stack4id(addr);
+	if (!st)
+		return(NULL);
+	ci.channel = channel;
+	ci.st.p = NULL;
+	if (mISDN_ctrl(st, MGR_SELCHANNEL | REQUEST, &ci))
+		return(NULL);
+	return(ci.st.p);
+}
+
+static int
+from_up_down(mISDNinstance_t *inst, struct sk_buff *skb) {
+	
+	devicelayer_t	*dl;
+	mISDN_head_t	*hh; 
+	int		retval = -EINVAL;
+
+	dl = inst->privat;
+	hh = mISDN_HEAD_P(skb);
+	hh->len = skb->len;
+//	hh->addr = dl->iaddr;
+	if (device_debug & DEBUG_RDATA)
+		printk(KERN_DEBUG "from_up_down: %x(%x) dinfo:%x len:%d\n",
+			hh->prim, hh->addr, hh->dinfo, hh->len);
+	retval = mISDN_rdata(dl->dev, skb);
+	return(retval);
+}
+
+static int
+create_layer(mISDNdevice_t *dev, struct sk_buff *skb)
+{
+	layer_info_t	*linfo;
+	mISDNstack_t	*st;
+	int		i, ret;
+	devicelayer_t	*nl;
+	mISDNobject_t	*obj;
+	mISDNinstance_t *inst = NULL;
+	mISDN_head_t	*hp;
+
+	hp = mISDN_HEAD_P(skb);
+	linfo = (layer_info_t *)skb->data;
+	if (!(st = get_stack4id(linfo->st))) {
+		/* should be changed */
+		printk(KERN_WARNING "%s: no stack found for id(%08x)\n", __FUNCTION__, linfo->st);
+		return(-ENODEV);
+	}
+	if (linfo->object_id != -1) {
+		obj = get_object(linfo->object_id);
+		if (!obj) {
+			printk(KERN_WARNING "%s: no object %x found\n",
+				__FUNCTION__, linfo->object_id);
+			return(-ENODEV);
+		}
+		ret = obj->own_ctrl(st, MGR_NEWLAYER | REQUEST, &linfo->pid);
+		if (ret) {
+			printk(KERN_WARNING "%s: error nl req %d\n",
+				__FUNCTION__, ret);
+			return(ret);
+		}
+		inst = getlayer4lay(st, linfo->pid.layermask);
+		if (!inst) {
+			printk(KERN_WARNING "%s: no inst found\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+	} else if (linfo->extentions & EXT_INST_CLONE) {
+		mISDN_pid_t	*pid;
+
+		inst = get_instance4id(linfo->parent);
+		if (!inst) {
+			printk(KERN_WARNING "%s: no parent inst found\n", __FUNCTION__);
+			return(-EINVAL);
+		}
+		if (!(inst->extentions & EXT_INST_CLONE)) {
+			printk(KERN_WARNING "%s: inst(%08x) ext(%x) is not cloneable\n",
+				__FUNCTION__, inst->id, inst->extentions);
+			return(-ENOSYS);
+		}
+		for(i=0; i<=MAX_LAYER_NR; i++)
+			if (!st->i_array[i])
+				break;
+		if (i > MAX_LAYER_NR) {
+			printk(KERN_WARNING "%s: no free instance slot in stack id(%08x)\n",
+				__FUNCTION__, st->id);
+			return(-EBUSY);
+		}
+		pid = kmalloc(sizeof(mISDN_pid_t), GFP_ATOMIC);
+		if (!pid) {
+			printk(KERN_ERR "kmalloc pid failed\n");
+			return(-ENOMEM);
+		}
+		memset(pid, 0, sizeof(mISDN_pid_t));
+		if (inst->pid.pbuf && inst->pid.maxplen) {
+			pid->pbuf = kmalloc(inst->pid.maxplen, GFP_ATOMIC);
+			if (!pid->pbuf) {
+				kfree(pid);
+				printk(KERN_ERR "kmalloc pid->pbuf failed\n");
+				return(-ENOMEM);
+			}
+			memset(pid->pbuf, 0, inst->pid.maxplen);
+		}
+		copy_pid(pid, &inst->pid, pid->pbuf);
+		ret = inst->obj->own_ctrl(st, MGR_NEWLAYER | REQUEST, pid);
+		kfree(pid->pbuf);
+		kfree(pid);
+		if (ret) {
+			printk(KERN_WARNING "%s: MGR_NEWLAYER | REQUEST for clone returns %d\n", __FUNCTION__, ret);
+			return(ret);
+		}
+		if (!st->i_array[i]) {
+			int_error();
+			return(-EINVAL);
+		} else {
+			while (inst->clone)
+				inst = inst->clone;
+			inst->clone = st->i_array[i];
+			st->i_array[i]->parent = inst;
+			inst = st->i_array[i];
+		}	
+	}
+#if 0
+	else if ((inst = getlayer4lay(st, linfo->pid.layermask))) {
+		if (!(linfo->extentions & EXT_INST_MIDDLE)) {
+			printk(KERN_WARNING
+				"mISDN create_layer st(%x) LM(%x) inst not empty(%08x)\n",
+				st->id, linfo->pid.layermask, inst->id);
+			return(-EBUSY);
+		}
+	}
+#endif
+	if (!(nl = kmalloc(sizeof(devicelayer_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc devicelayer failed\n");
+		return(-ENOMEM);
+	}
+	memset(nl, 0, sizeof(devicelayer_t));
+	if (inst)
+		nl->id = get_new_devicelayer_id(dev, inst->id);
+	else if (st)
+		nl->id = get_new_devicelayer_id(dev, st->id);
+	else
+		nl->id = get_new_devicelayer_id(dev, 0);
+	if (!nl->id) {
+		int_errtxt("overflow devicelayer ids");
+		kfree(nl);
+		return(-EBUSY);
+	}
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG
+			"mISDN create_layer LM(%x) nl(%p:%08x) nl->inst(%p) inst(%p)\n",
+			linfo->pid.layermask, nl, nl->id, &nl->inst, inst);
+	nl->dev = dev;
+	list_add_tail(&nl->list, &dev->layerlist);
+	if (!inst) {
+		mISDN_init_instance(&nl->inst, &udev_obj, nl, from_up_down);
+		memcpy(&nl->inst.pid, &linfo->pid, sizeof(mISDN_pid_t));
+		strcpy(nl->inst.name, linfo->name);
+		nl->inst.extentions = linfo->extentions;
+		for (i=0; i<= MAX_LAYER_NR; i++) {
+			if (linfo->pid.layermask & ISDN_LAYER(i)) {
+				if (st && (st->pid.protocol[i] == ISDN_PID_NONE)) {
+					st->pid.protocol[i] = linfo->pid.protocol[i];
+					nl->lm_st |= ISDN_LAYER(i);
+				}
+			}
+		}
+		if (st && (linfo->extentions & EXT_INST_MGR)) {
+			st->mgr = &nl->inst;
+			test_and_set_bit(FLG_MGR_OWNSTACK, &nl->Flags);
+		}
+		if (st)
+			mISDN_ctrl(st, MGR_ADDLAYER | REQUEST, &nl->inst);
+	} else {
+		nl->slave = inst;
+		nl->inst.extentions |= EXT_INST_UNUSED;
+	}
+	skb_trim(skb, 0);
+	memcpy(skb_put(skb, sizeof(nl->id)), &nl->id, sizeof(nl->id));
+	if (inst)
+		memcpy(skb_put(skb, sizeof(inst->id)), &inst->id, sizeof(inst->id));
+	else
+		memset(skb_put(skb, sizeof(nl->id)), 0, sizeof(nl->id));
+	return(8);
+}
+
+static int
+del_stack(devicestack_t *ds)
+{
+	mISDNdevice_t	*dev;
+
+	if (!ds) {
+		int_error();
+		return(-EINVAL);
+	}
+	dev = ds->dev;
+	if (device_debug & DEBUG_MGR_FUNC) {
+		printk(KERN_DEBUG "%s: ds(%p) dev(%p)\n", 
+			__FUNCTION__, ds, dev);
+	}
+	if (!dev)
+		return(-EINVAL);
+	if (ds->st) {
+		if (ds->extentions & EXT_STACK_CLONE)
+			INIT_LIST_HEAD(&ds->st->childlist);
+		mISDN_ctrl(ds->st, MGR_DELSTACK | REQUEST, NULL);
+	}
+	list_del(&ds->list);
+	kfree(ds);
+	return(0);
+}
+
+static int
+del_layer(devicelayer_t *dl)
+{
+	mISDNinstance_t *inst = &dl->inst;
+	mISDNdevice_t	*dev = dl->dev;
+	int		i;
+
+	if (device_debug & DEBUG_MGR_FUNC) {
+		printk(KERN_DEBUG "%s: dl(%p) inst(%p) LM(%x) dev(%p)\n", 
+			__FUNCTION__, dl, inst, inst->pid.layermask, dev);
+		printk(KERN_DEBUG "%s: iaddr %x inst(%08x) %s slave %p\n",
+			__FUNCTION__, dl->id, inst->id, inst->name, dl->slave);
+	}
+	if (dl->slave) {
+		if (dl->slave->obj)
+			dl->slave->obj->own_ctrl(dl->slave,
+				MGR_UNREGLAYER | REQUEST, NULL);
+		else
+			dl->slave = NULL; 
+	}
+	if (dl->lm_st && inst->st) {
+		for (i=0; i<= MAX_LAYER_NR; i++) {
+			if (dl->lm_st & ISDN_LAYER(i)) {
+				inst->st->pid.protocol[i] = ISDN_PID_NONE;
+			}
+		}
+		dl->lm_st = 0;
+	}
+	if (test_and_clear_bit(FLG_MGR_SETSTACK, &dl->Flags) && inst->st) {
+		if (device_debug & DEBUG_MGR_FUNC)
+			printk(KERN_DEBUG "del_layer: CLEARSTACK id(%x)\n",
+				inst->st->id);
+		mISDN_ctrl(inst->st, MGR_CLEARSTACK | REQUEST, NULL);
+	}
+	dl->id = 0;
+	list_del(&dl->list);
+	if (!(inst->extentions & EXT_INST_UNUSED)) {
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+	}
+	if (test_and_clear_bit(FLG_MGR_OWNSTACK, &dl->Flags)) {
+		if (dl->inst.st) {
+			del_stack(get_devstack(dev, dl->inst.st->id));
+		}
+	}
+	kfree(dl);
+	return(0);
+}
+
+#ifdef OBSOLETE
+static mISDNinstance_t *
+clone_instance(devicelayer_t *dl, mISDNstack_t  *st, mISDNinstance_t *peer)
+{
+	int		err;
+
+	if (dl->slave) {
+		printk(KERN_WARNING "%s: layer has slave, cannot clone\n",
+			__FUNCTION__);
+		return(NULL);
+	}
+	if (!(peer->extentions & EXT_INST_CLONE)) {
+		printk(KERN_WARNING "%s: peer cannot clone\n", __FUNCTION__);
+		return(NULL);
+	}
+	dl->slave = (mISDNinstance_t *)st;
+	if ((err = peer->obj->own_ctrl(peer, MGR_CLONELAYER | REQUEST,
+		&dl->slave))) {
+		dl->slave = NULL;
+		printk(KERN_WARNING "%s: peer clone error %d\n",
+			__FUNCTION__, err);
+		return(NULL);
+	}
+	return(dl->slave);
+}
+
+static int
+remove_if(devicelayer_t *dl, int stat) {
+	mISDNif_t *hif,*phif,*shif;
+	int err;
+
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "%s: dl(%p) stat(%x)\n", __FUNCTION__,
+			dl, stat);
+	phif = NULL;
+	if (stat & IF_UP) {
+		hif = &dl->inst.up;
+		shif = &dl->s_up;
+		if (shif->owner)
+			phif = &shif->owner->down;
+	} else if (stat & IF_DOWN) {
+		hif = &dl->inst.down;
+		shif = &dl->s_down;
+		if (shif->owner)
+			phif = &shif->owner->up;
+	} else {
+		printk(KERN_WARNING "%s: stat not UP/DOWN\n", __FUNCTION__);
+		return(-EINVAL);
+	}
+	err = mISDN_ctrl(hif->peer, MGR_DISCONNECT | REQUEST, hif);
+	if (phif) {
+		memcpy(phif, shif, sizeof(mISDNif_t));
+		memset(shif, 0, sizeof(mISDNif_t));
+	}
+	if (hif->predecessor)
+		hif->predecessor->clone = hif->clone;
+	if (hif->clone)
+		hif->clone->predecessor = hif->predecessor;
+	return(err);
+}
+
+static int
+connect_if_req(mISDNdevice_t *dev, struct sk_buff *skb)
+{
+	devicelayer_t		*dl;
+	interface_info_t	*ifi = (interface_info_t *)skb->data;
+	mISDNinstance_t		*owner;
+	mISDNinstance_t		*peer;
+	mISDNinstance_t		*pp;
+	mISDNif_t		*hifp;
+	int			stat;
+	mISDN_head_t		*hp;
+
+	hp = mISDN_HEAD_P(skb);
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "%s: addr:%x own(%x) peer(%x)\n",
+			__FUNCTION__, hp->addr, ifi->owner, ifi->peer);
+	if (!(dl=get_devlayer(dev, ifi->owner))) {
+		int_errtxt("no devive_layer for %08x", ifi->owner);
+		return(-ENXIO);
+	}
+	if (!(owner = get_instance4id(ifi->owner))) {
+		printk(KERN_WARNING "%s: owner(%x) not found\n",
+			__FUNCTION__, ifi->owner);
+		return(-ENODEV);
+	}
+	if (!(peer = get_instance4id(ifi->peer))) {
+		printk(KERN_WARNING "%s: peer(%x) not found\n",
+			__FUNCTION__, ifi->peer);
+		return(-ENODEV);
+	}
+	if (owner->pid.layermask < peer->pid.layermask) {
+		hifp = &peer->down;
+		stat = IF_DOWN;
+	} else if (owner->pid.layermask > peer->pid.layermask) {
+		hifp = &peer->up;
+		stat = IF_UP;
+	} else {
+		int_errtxt("OLM == PLM: %x", owner->pid.layermask);
+		return(-EINVAL);
+	}
+	if (ifi->extentions == EXT_IF_CHAIN) {
+		if (!(pp = hifp->peer)) {
+			printk(KERN_WARNING "%s: peer if has no peer\n",
+				__FUNCTION__);
+			return(-EINVAL);
+		}
+		if (stat == IF_UP) {
+			memcpy(&owner->up, hifp, sizeof(mISDNif_t));
+			memcpy(&dl->s_up, hifp, sizeof(mISDNif_t));
+			owner->up.owner = owner;
+			hifp->peer = owner;
+			hifp->func = from_up_down;
+			hifp->fdata = dl;
+			hifp = &pp->down;
+			memcpy(&owner->down, hifp, sizeof(mISDNif_t));
+			memcpy(&dl->s_down, hifp, sizeof(mISDNif_t));
+			owner->down.owner = owner;
+			hifp->peer = owner;
+			hifp->func = from_up_down;
+			hifp->fdata = dl;
+		} else {
+			memcpy(&owner->down, hifp, sizeof(mISDNif_t));
+			memcpy(&dl->s_down, hifp, sizeof(mISDNif_t));
+			owner->up.owner = owner;
+			hifp->peer = owner;
+			hifp->func = from_up_down;
+			hifp->fdata = dl;
+			hifp = &pp->up;
+			memcpy(&owner->up, hifp, sizeof(mISDNif_t));
+			memcpy(&dl->s_up, hifp, sizeof(mISDNif_t));
+			owner->down.owner = owner;
+			hifp->peer = owner;
+			hifp->func = from_up_down;
+			hifp->fdata = dl;
+		}
+		return(0);
+	}
+	if (ifi->extentions & EXT_IF_CREATE) {
+		/* create new instance if allready in use */
+		if (hifp->stat != IF_NOACTIV) {
+			if ((peer = clone_instance(dl, owner->st, peer))) {
+				if (stat == IF_UP)
+					hifp = &peer->up;
+				else
+					hifp = &peer->down;
+			} else {
+				printk(KERN_WARNING "%s: cannot create new peer instance\n",
+					__FUNCTION__);
+				return(-EBUSY);
+			}
+		}
+	}
+	if (ifi->extentions & EXT_IF_EXCLUSIV) {
+		if (hifp->stat != IF_NOACTIV) {
+			printk(KERN_WARNING "%s: peer if is in use\n",
+				__FUNCTION__);
+			return(-EBUSY);
+		}
+	}			
+	return(mISDN_ConnectIF(owner, peer));
+}
+
+static int
+set_if_req(mISDNdevice_t *dev, struct sk_buff *skb)
+{
+	mISDNif_t		*hif,*phif,*shif;
+	int			stat;
+	interface_info_t	*ifi = (interface_info_t *)skb->data;
+	devicelayer_t		*dl;
+	mISDNinstance_t		*inst, *peer;
+	mISDN_head_t		*hp;
+
+	hp = mISDN_HEAD_P(skb);
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "%s: addr:%x own(%x) peer(%x)\n",
+			__FUNCTION__, hp->addr, ifi->owner, ifi->peer);
+	if (!(dl=get_devlayer(dev, hp->addr)))
+		return(-ENXIO);
+	if (!(inst = get_instance4id(ifi->owner))) {
+		printk(KERN_WARNING "%s: owner(%x) not found\n",
+			__FUNCTION__, ifi->owner);
+		return(-ENODEV);
+	}
+	if (!(peer = get_instance4id(ifi->peer))) {
+		printk(KERN_WARNING "%s: peer(%x) not found\n",
+			__FUNCTION__, ifi->peer);
+		return(-ENODEV);
+	}
+
+	if (ifi->stat == IF_UP) {
+		hif = &dl->inst.up;
+		phif = &peer->down;
+		shif = &dl->s_up;
+		stat = IF_DOWN;
+	} else if (ifi->stat == IF_DOWN) {
+		hif = &dl->inst.down;
+		shif = &dl->s_down;
+		phif = &peer->up;
+		stat = IF_UP;
+	} else {
+		printk(KERN_WARNING "%s: if not UP/DOWN\n", __FUNCTION__);
+		return(-EINVAL);
+	}
+
+	
+	if (shif->stat != IF_NOACTIV) {
+		printk(KERN_WARNING "%s: save if busy\n", __FUNCTION__);
+		return(-EBUSY);
+	}
+	if (hif->stat != IF_NOACTIV) {
+		printk(KERN_WARNING "%s: own if busy\n", __FUNCTION__);
+		return(-EBUSY);
+	}
+	hif->stat = stat;
+	hif->owner = inst;
+	memcpy(shif, phif, sizeof(mISDNif_t));
+	memset(phif, 0, sizeof(mISDNif_t));
+	return(peer->obj->own_ctrl(peer, hp->prim, hif));
+}
+
+static int
+add_if_req(mISDNdevice_t *dev, struct sk_buff *skb)
+{
+	mISDNif_t		*hif;
+	interface_info_t	*ifi = (interface_info_t *)skb->data;
+	mISDNinstance_t		*inst, *peer;
+	mISDN_head_t		*hp;
+
+	hp = mISDN_HEAD_P(skb);
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "%s: addr:%x own(%x) peer(%x)\n",
+			__FUNCTION__, hp->addr, ifi->owner, ifi->peer);
+	if (!(inst = get_instance4id(ifi->owner))) {
+		printk(KERN_WARNING "%s: owner(%x) not found\n",
+			__FUNCTION__, ifi->owner);
+		return(-ENODEV);
+	}
+	if (!(peer = get_instance4id(ifi->peer))) {
+		printk(KERN_WARNING "%s: peer(%x) not found\n",
+			__FUNCTION__, ifi->peer);
+		return(-ENODEV);
+	}
+
+	if (ifi->stat == IF_DOWN) {
+		hif = &inst->up;
+	} else if (ifi->stat == IF_UP) {
+		hif = &inst->down;
+	} else {
+		printk(KERN_WARNING "%s: if not UP/DOWN\n", __FUNCTION__);
+		return(-EINVAL);
+	}
+	return(peer->obj->ctrl(peer, hp->prim, hif));
+}
+
+static int
+del_if_req(mISDNdevice_t *dev, u_int addr)
+{
+	devicelayer_t *dl;
+
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "%s: addr:%x\n", __FUNCTION__, addr);
+	if (!(dl=get_devlayer(dev, addr)))
+		return(-ENXIO);
+	return(remove_if(dl, addr));
+}
+
+static void
+get_if_info(struct sk_buff *skb)
+{
+	mISDN_head_t		*hp;
+	mISDNinstance_t		*inst;
+	mISDNif_t		*hif;
+	interface_info_t	*ii = (interface_info_t *)skb->data;
+	
+	hp = mISDN_HEAD_P(skb);
+	if (!(inst = get_instance4id(hp->addr & IF_ADDRMASK))) {
+		printk(KERN_WARNING "%s: no instance\n", __FUNCTION__);
+		hp->len = -ENODEV;
+		return;
+	}
+	if (hp->dinfo == IF_DOWN)
+		hif = &inst->down;
+	else if (hp->dinfo == IF_UP)
+		hif = &inst->up;
+	else {
+		printk(KERN_WARNING "%s: wrong interface %x\n",
+			__FUNCTION__, hp->dinfo);
+		hp->len = -EINVAL;
+		return;
+	}
+	hp->dinfo = 0;
+	memset(ii, 0, sizeof(interface_info_t));
+	if (hif->owner)
+		ii->owner = hif->owner->id;
+	if (hif->peer)
+		ii->peer = hif->peer->id;
+	ii->extentions = hif->extentions;
+	ii->stat = hif->stat;
+	hp->len = sizeof(interface_info_t);
+	skb_put(skb, hp->len);
+}
+#endif
+
+static int
+new_entity_req(mISDNdevice_t *dev, int *entity)
+{
+	int		ret;
+	entity_item_t	*ei = kmalloc(sizeof(entity_item_t), GFP_ATOMIC);
+
+	if (!ei)
+		return(-ENOMEM);
+	ret = mISDN_alloc_entity(entity);
+	ei->entity = *entity;
+	if (ret)
+		kfree(entity);
+	else
+		list_add((struct list_head *)ei, &dev->entitylist);
+	return(ret);
+}
+
+static int
+del_entity_req(mISDNdevice_t *dev, int entity)
+{
+	struct list_head	*item, *nxt;
+
+	list_for_each_safe(item, nxt, &dev->entitylist) {
+		if (((entity_item_t *)item)->entity == entity) {
+			list_del(item);
+			mISDN_delete_entity(entity);
+			kfree(item);
+			return(0);
+		}
+	}
+	return(-ENODEV);
+}
+
+static void
+dev_expire_timer(mISDNtimer_t *ht)
+{
+	struct sk_buff	*skb;
+	mISDN_head_t	*hp;
+
+	if (device_debug & DEBUG_DEV_TIMER)
+		printk(KERN_DEBUG "%s: timer(%x)\n", __FUNCTION__, ht->id);
+	if (test_and_clear_bit(FLG_MGR_TIMER_RUNING, &ht->Flags)) {
+		skb = alloc_stack_skb(16, 0);
+		if (!skb) {
+			printk(KERN_WARNING "%s: timer(%x) no skb\n",
+				__FUNCTION__, ht->id);
+			return;
+		}
+		hp = mISDN_HEAD_P(skb);
+		hp->dinfo = 0;
+		hp->prim = MGR_TIMER | INDICATION;
+		hp->addr = ht->id;
+		hp->len = 0;
+		if (mISDN_rdata(ht->dev, skb))
+			dev_kfree_skb(skb);
+	} else
+		printk(KERN_WARNING "%s: timer(%x) not active\n",
+			__FUNCTION__, ht->id);
+}
+
+static int
+dev_init_timer(mISDNdevice_t *dev, u_int id)
+{
+	mISDNtimer_t	*ht;
+
+	ht = get_devtimer(dev, id);
+	if (!ht) {
+		ht = kmalloc(sizeof(mISDNtimer_t), GFP_ATOMIC);
+		if (!ht)
+			return(-ENOMEM);
+		ht->dev = dev;
+		ht->id = id;
+		ht->tl.data = (long) ht;
+		ht->tl.function = (void *) dev_expire_timer;
+		init_timer(&ht->tl);
+		list_add_tail(&ht->list, &dev->timerlist);
+		if (device_debug & DEBUG_DEV_TIMER)
+			printk(KERN_DEBUG "%s: new(%x)\n", __FUNCTION__, ht->id);
+	} else if (device_debug & DEBUG_DEV_TIMER)
+		printk(KERN_DEBUG "%s: old(%x)\n", __FUNCTION__, ht->id);
+	if (timer_pending(&ht->tl)) {
+		if (device_debug & DEBUG_DEV_TIMER)	
+			printk(KERN_WARNING "%s: timer(%x) pending\n", 
+					__FUNCTION__, ht->id);
+		del_timer(&ht->tl);
+	}
+	init_timer(&ht->tl);
+	test_and_set_bit(FLG_MGR_TIMER_INIT, &ht->Flags);
+	return(0);
+}
+
+static int
+dev_add_timer(mISDNdevice_t *dev, mISDN_head_t *hp)
+{
+	mISDNtimer_t	*ht;
+
+	ht = get_devtimer(dev, hp->addr);
+	if (!ht) {
+		printk(KERN_WARNING "%s: no timer(%x)\n", __FUNCTION__,
+			hp->addr);
+		return(-ENODEV);
+	}
+	if (timer_pending(&ht->tl)) {
+		printk(KERN_WARNING "%s: timer(%x) pending\n",
+			__FUNCTION__, ht->id);
+		return(-EBUSY);
+	}
+	if (hp->dinfo < 10) {
+		printk(KERN_WARNING "%s: timer(%x): %d ms too short\n",
+			__FUNCTION__, ht->id, hp->dinfo);
+		return(-EINVAL);
+	}
+	if (device_debug & DEBUG_DEV_TIMER)
+		printk(KERN_DEBUG "%s: timer(%x) %d ms\n",
+			__FUNCTION__, ht->id, hp->dinfo);
+	init_timer(&ht->tl);
+	ht->tl.expires = jiffies + (hp->dinfo * HZ) / 1000;
+	test_and_set_bit(FLG_MGR_TIMER_RUNING, &ht->Flags);
+	add_timer(&ht->tl);
+	return(0);
+}
+
+static int
+dev_del_timer(mISDNdevice_t *dev, u_int id)
+{
+	mISDNtimer_t	*ht;
+
+	ht = get_devtimer(dev, id);
+	if (!ht) {
+		printk(KERN_WARNING "%s: no timer(%x)\n", __FUNCTION__,
+			id);
+		return(-ENODEV);
+	}
+	if (device_debug & DEBUG_DEV_TIMER)
+		printk(KERN_DEBUG "%s: timer(%x)\n",
+			__FUNCTION__, ht->id);
+	del_timer(&ht->tl);
+	if (!test_and_clear_bit(FLG_MGR_TIMER_RUNING, &ht->Flags)) {
+		if (device_debug & DEBUG_DEV_TIMER)
+			printk(KERN_WARNING "%s: timer(%x) not running\n",
+				__FUNCTION__, ht->id);
+	}
+	return(0);
+}
+
+static void
+dev_free_timer(mISDNtimer_t *ht)
+{
+	if (device_debug & DEBUG_DEV_TIMER)
+		printk(KERN_DEBUG "%s: timer(%x)\n", __FUNCTION__, ht->id);
+	del_timer(&ht->tl);
+	list_del(&ht->list);
+	kfree(ht);
+}
+
+static int
+dev_remove_timer(mISDNdevice_t *dev, u_int id)
+{
+	mISDNtimer_t	*ht;
+
+	ht = get_devtimer(dev, id);
+	if (!ht)  {
+		printk(KERN_WARNING "%s: no timer(%x)\n", __FUNCTION__, id);
+		return(-ENODEV);
+	}
+	dev_free_timer(ht);
+	return(0);
+}
+
+static int
+get_status(struct sk_buff *skb)
+{
+	mISDN_head_t	*hp;
+	status_info_t	*si = (status_info_t *)skb->data;
+	mISDNinstance_t	*inst;
+	int		err;
+
+	hp = mISDN_HEAD_P(skb);
+	if (!(inst = get_instance4id(hp->addr & INST_ID_MASK))) {
+		printk(KERN_WARNING "%s: no instance\n", __FUNCTION__);
+		err = -ENODEV;
+	} else {
+		err = inst->obj->own_ctrl(inst, MGR_STATUS | REQUEST, si);
+	}
+	if (err)
+		hp->len = err;
+	else {
+		hp->len = si->len + 2*sizeof(int);
+		skb_put(skb, hp->len);
+	}
+	return(err);	
+}
+
+static void
+get_layer_info(struct sk_buff *skb)
+{
+	mISDN_head_t	*hp;
+	mISDNinstance_t *inst;
+	layer_info_t	*li = (layer_info_t *)skb->data;
+
+	hp = mISDN_HEAD_P(skb);
+	if (!(inst = get_instance4id(hp->addr & INST_ID_MASK))) {
+		printk(KERN_WARNING "%s: no instance\n", __FUNCTION__);
+		hp->len = -ENODEV;
+		return;
+	}
+	memset(li, 0, sizeof(layer_info_t));
+	if (inst->obj)
+		li->object_id = inst->obj->id;
+	strcpy(li->name, inst->name);
+	li->extentions = inst->extentions;
+	li->id = inst->id;
+	if (inst->st)
+		li->st = inst->st->id;
+	if (inst->parent)
+		li->parent = inst->parent->id;
+	if (inst->clone)
+		li->clone = inst->clone->id;		
+	memcpy(&li->pid, &inst->pid, sizeof(mISDN_pid_t));
+	hp->len = sizeof(layer_info_t);
+	skb_put(skb, hp->len);
+}
+
+static int
+wdata_frame(mISDNdevice_t *dev, struct sk_buff *skb)
+{
+	mISDN_head_t	*hp;
+	devicelayer_t	*dl;
+	int		err = -ENXIO;
+
+	hp = mISDN_HEAD_P(skb);
+	if (device_debug & DEBUG_WDATA)
+		printk(KERN_DEBUG "%s: addr:%x\n", __FUNCTION__, hp->addr);
+	if (!(dl=get_devlayer(dev, hp->addr)))
+		return(err);
+	if (device_debug & DEBUG_WDATA)
+		printk(KERN_DEBUG "%s: pr(%x) di(%x) l(%d)\n",
+			__FUNCTION__, hp->prim, hp->dinfo, hp->len);
+	if (hp->len < 0) {
+		printk(KERN_WARNING "%s: data negativ(%d)\n",
+			__FUNCTION__, hp->len);
+		return(-EINVAL);
+	}
+	err = mISDN_queue_message(&dl->inst, hp->addr, skb);
+	if (device_debug & DEBUG_WDATA && err)
+		printk(KERN_DEBUG "%s: mISDN_send_message ret(%x)\n",
+			__FUNCTION__, err);
+	return(err);
+}
+
+static int
+mISDN_wdata_if(mISDNdevice_t *dev, struct sk_buff *skb)
+{
+	struct sk_buff	*nskb = NULL;
+	mISDN_head_t	*hp;
+	mISDNstack_t	*st;
+	devicelayer_t	*dl;
+	mISDNinstance_t *inst;
+	int		lay;
+	int		err = 0;
+
+	hp = mISDN_HEAD_P(skb);
+	if (device_debug & DEBUG_WDATA)
+		printk(KERN_DEBUG "%s: %x:%x %x %d %d\n",
+			__FUNCTION__, hp->addr, hp->prim, hp->dinfo, hp->len, skb->len);
+	if ((hp->len > 0) && (skb->len < hp->len)) {
+		printk(KERN_WARNING "%s: frame(%d/%d) too short\n",
+			__FUNCTION__, skb->len, hp->len);
+		return(error_answer(dev, skb, -EINVAL));
+	}
+	switch(hp->prim) {
+	    case (MGR_VERSION | REQUEST):
+		hp->prim = MGR_VERSION | CONFIRM;
+		hp->len = 0;
+		hp->dinfo = MISDN_VERSION;
+		break;
+	    case (MGR_GETSTACK | REQUEST):
+		hp->prim = MGR_GETSTACK | CONFIRM;
+		hp->dinfo = 0;
+		if (hp->addr <= 0) {
+			hp->dinfo = get_stack_cnt();
+			hp->len = 0;
+		} else {
+			nskb = alloc_stack_skb(1000, 0);
+			if (!nskb)
+				return(error_answer(dev, skb, -ENOMEM));
+			memcpy(mISDN_HEAD_P(nskb), hp, sizeof(mISDN_head_t));
+			get_stack_info(nskb);
+		}
+		break;
+	    case (MGR_SETSTACK | REQUEST):
+		if (skb->len < sizeof(mISDN_pid_t))
+			return(error_answer(dev, skb, -EINVAL));
+		hp->dinfo = 0;
+		if ((st = get_stack4id(hp->addr))) {
+			stack_inst_flg(dev, st, FLG_MGR_SETSTACK, 0);
+			hp->len = mISDN_ctrl(st, hp->prim, skb->data);
+		} else
+			hp->len = -ENODEV;
+		hp->prim = MGR_SETSTACK | CONFIRM;
+		break;
+	    case (MGR_NEWSTACK | REQUEST):
+		hp->dinfo = 0;
+		hp->prim = MGR_NEWSTACK | CONFIRM;
+		hp->len = 0;
+		err = new_devstack(dev, (stack_info_t *)skb->data);
+		if (err<0)
+			hp->len = err;
+ 		else
+ 			hp->dinfo = err;
+		break;	
+	    case (MGR_CLEARSTACK | REQUEST):
+		hp->dinfo = 0;
+		if ((st = get_stack4id(hp->addr))) {
+			stack_inst_flg(dev, st, FLG_MGR_SETSTACK, 1);
+			hp->len = mISDN_ctrl(st, hp->prim, NULL);
+		} else
+			hp->len = -ENODEV;
+		hp->prim = MGR_CLEARSTACK | CONFIRM;
+		break;
+	    case (MGR_SELCHANNEL | REQUEST):
+		hp->prim = MGR_SELCHANNEL | CONFIRM;
+		st = sel_channel(hp->addr, hp->dinfo);
+		if (st) {
+			hp->len = 0;
+			hp->dinfo = st->id;
+		} else {
+			hp->dinfo = 0;
+			hp->len = -ENODEV;
+		}
+		break;
+	    case (MGR_GETLAYERID | REQUEST):
+		hp->prim = MGR_GETLAYERID | CONFIRM;
+		lay = hp->dinfo;
+		hp->dinfo = 0;
+		if (LAYER_OUTRANGE(lay)) {
+			hp->len = -EINVAL;
+		} else {
+			hp->len = 0;
+			lay = ISDN_LAYER(lay);
+			if ((st = get_stack4id(hp->addr))) {
+				if ((inst = getlayer4lay(st, lay))) {
+					if (inst)
+						hp->dinfo = inst->id;
+				}
+			}
+		}
+		break;
+	    case (MGR_GETLAYER | REQUEST):
+		hp->prim = MGR_GETLAYER | CONFIRM;
+		hp->dinfo = 0;
+		skb_trim(skb, 0);
+		if (skb_tailroom(skb) < sizeof(layer_info_t)) {
+			nskb = alloc_stack_skb(sizeof(layer_info_t), 0);
+			if (!nskb)
+				return(error_answer(dev, skb, -ENOMEM));
+			memcpy(mISDN_HEAD_P(nskb), hp, sizeof(mISDN_head_t));
+			get_layer_info(nskb);
+		} else {
+			get_layer_info(skb);
+		}
+		break;
+	    case (MGR_NEWLAYER | REQUEST):
+		if (skb->len < sizeof(layer_info_t))
+			return(error_answer(dev, skb, -EINVAL));
+		hp->dinfo = 0;
+		hp->prim = MGR_NEWLAYER | CONFIRM;
+		hp->len = create_layer(dev, skb);
+		break;	
+	    case (MGR_REGLAYER | REQUEST):
+		lay = hp->dinfo;
+		hp->dinfo = 0;
+		if (!(st = get_stack4id(hp->addr)))
+			return(error_answer(dev, skb, -ENODEV));
+		if (!(dl = get_devlayer(dev, lay)))
+			return(error_answer(dev, skb, -ENODEV));
+		hp->prim = MGR_REGLAYER | CONFIRM;
+		hp->len = mISDN_ctrl(st, MGR_REGLAYER | REQUEST, &dl->inst);
+		if (core_debug & DEBUG_MGR_FUNC)
+			printk(KERN_DEBUG "MGR_REGLAYER | REQUEST: ret(%d)\n", hp->len);
+		break;	
+	    case (MGR_UNREGLAYER | REQUEST):
+		lay = hp->dinfo;
+		hp->dinfo = 0;
+		if (!(st = get_stack4id(hp->addr)))
+			return(error_answer(dev, skb, -ENODEV));
+		if (!(dl = get_devlayer(dev, lay)))
+			return(error_answer(dev, skb, -ENODEV));
+		hp->prim = MGR_UNREGLAYER | CONFIRM;
+		hp->len = mISDN_ctrl(st, MGR_UNREGLAYER | REQUEST, &dl->inst);
+		break;	
+	    case (MGR_DELLAYER | REQUEST):
+		hp->prim = MGR_DELLAYER | CONFIRM;
+		hp->dinfo = 0;
+		if ((dl = get_devlayer(dev, hp->addr)))
+			hp->len = del_layer(dl);
+		else
+			hp->len = -ENXIO;
+		break;
+#ifdef OBSOLETE
+	    case (MGR_GETIF | REQUEST):
+		hp->prim = MGR_GETIF | CONFIRM;
+		hp->dinfo = 0;
+		skb_trim(skb, 0);
+		if (skb_tailroom(skb) < sizeof(interface_info_t)) {
+			nskb = alloc_stack_skb(sizeof(interface_info_t), 0);
+			if (!nskb)
+				return(error_answer(dev, skb, -ENOMEM));
+			memcpy(mISDN_HEAD_P(nskb), hp, sizeof(mISDN_head_t));
+			get_if_info(nskb);
+		} else {
+			get_if_info(skb);
+		}
+		break;
+	    case (MGR_CONNECT | REQUEST):
+		if (skb->len < sizeof(interface_info_t))
+			return(error_answer(dev, skb, -EINVAL));
+		hp->len = connect_if_req(dev, skb);
+		hp->dinfo = 0;
+		hp->prim = MGR_CONNECT | CONFIRM;
+		break;
+	    case (MGR_SETIF | REQUEST):
+		hp->len = set_if_req(dev, skb);
+		hp->prim = MGR_SETIF | CONFIRM;
+		hp->dinfo = 0;
+		break;
+	    case (MGR_ADDIF | REQUEST):
+		hp->len = add_if_req(dev, skb);
+		hp->prim = MGR_ADDIF | CONFIRM;
+		hp->dinfo = 0;
+		break;
+	    case (MGR_DISCONNECT | REQUEST):
+		hp->len = del_if_req(dev, hp->addr);
+		hp->prim = MGR_DISCONNECT | CONFIRM;
+		hp->dinfo = 0;
+		break;
+#endif
+	    case (MGR_NEWENTITY | REQUEST):
+		hp->prim = MGR_NEWENTITY | CONFIRM;
+		hp->len = new_entity_req(dev, &hp->dinfo);
+		break;
+	    case (MGR_DELENTITY | REQUEST):
+		hp->prim = MGR_DELENTITY | CONFIRM;
+		hp->len = del_entity_req(dev, hp->dinfo);
+		break;
+	    case (MGR_INITTIMER | REQUEST):
+		hp->len = dev_init_timer(dev, hp->addr);
+		hp->prim = MGR_INITTIMER | CONFIRM;
+		break;
+	    case (MGR_ADDTIMER | REQUEST):
+		hp->len = dev_add_timer(dev, hp);
+		hp->prim = MGR_ADDTIMER | CONFIRM;
+		hp->dinfo = 0;
+		break;
+	    case (MGR_DELTIMER | REQUEST):
+		hp->len = dev_del_timer(dev, hp->addr);
+		hp->prim = MGR_DELTIMER | CONFIRM;
+		break;
+	    case (MGR_REMOVETIMER | REQUEST):
+		hp->len = dev_remove_timer(dev, hp->addr);
+		hp->prim = MGR_REMOVETIMER | CONFIRM;
+		hp->dinfo = 0;
+		break;
+	    case (MGR_TIMER | RESPONSE):
+	    	dev_kfree_skb(skb);
+	    	return(0);
+		break;
+	    case (MGR_STATUS | REQUEST):
+		hp->prim = MGR_STATUS | CONFIRM;
+		nskb = alloc_stack_skb(1000, 0);
+		if (!nskb)
+			return(error_answer(dev, skb, -ENOMEM));
+		memcpy(mISDN_HEAD_P(nskb), hp, sizeof(mISDN_head_t));
+		get_status(nskb);
+		hp->dinfo = 0;
+		break;
+	    case (MGR_SETDEVOPT | REQUEST):
+		hp->prim = MGR_SETDEVOPT | CONFIRM;
+	    	hp->len = 0;
+	    	if (hp->dinfo == FLG_mISDNPORT_ONEFRAME) {
+	    		test_and_set_bit(FLG_mISDNPORT_ONEFRAME,
+	    			&dev->rport.Flag);
+	    	} else if (!hp->dinfo) {
+	    		test_and_clear_bit(FLG_mISDNPORT_ONEFRAME,
+	    			&dev->rport.Flag);
+	    	} else {
+	    		hp->len = -EINVAL;
+	    	}
+	    	hp->dinfo = 0;
+	    	break;
+	    case (MGR_GETDEVOPT | REQUEST):
+	    	hp->prim = MGR_GETDEVOPT | CONFIRM;
+	    	hp->len = 0;
+	    	if (test_bit(FLG_mISDNPORT_ONEFRAME, &dev->rport.Flag))
+	    		hp->dinfo = FLG_mISDNPORT_ONEFRAME;
+	    	else
+	    		hp->dinfo = 0;
+	    	break;
+	    default:
+		if (hp->addr & FLG_INSTANCE) {
+			err = wdata_frame(dev, skb);
+			if (err) {
+				if (device_debug & DEBUG_WDATA)
+					printk(KERN_DEBUG "wdata_frame returns error %d\n", err);
+				err = error_answer(dev, skb, err);
+			}
+		} else {
+			if (device_debug)
+				printk(KERN_WARNING "mISDN: prim %x addr %x not implemented\n",
+					hp->prim, hp->addr);
+			err = error_answer(dev, skb, -EINVAL);
+		}
+		return(err);
+		break;
+	}
+	if (nskb) {
+		err = mISDN_rdata(dev, nskb);
+		if (err)
+			kfree_skb(nskb);
+		else
+			kfree_skb(skb);
+	} else
+		err = mISDN_rdata(dev, skb);
+	return(err);
+}
+
+static mISDNdevice_t *
+init_device(u_int minor) {
+	mISDNdevice_t	*dev;
+	u_long		flags;
+
+	dev = kmalloc(sizeof(mISDNdevice_t), GFP_KERNEL);
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "%s: dev(%d) %p\n",
+			__FUNCTION__, minor, dev); 
+	if (dev) {
+		memset(dev, 0, sizeof(mISDNdevice_t));
+		dev->minor = minor;
+		init_waitqueue_head(&dev->rport.procq);
+		init_waitqueue_head(&dev->wport.procq);
+		skb_queue_head_init(&dev->rport.queue);
+		skb_queue_head_init(&dev->wport.queue);
+		init_MUTEX(&dev->io_sema);
+		INIT_LIST_HEAD(&dev->layerlist);
+		INIT_LIST_HEAD(&dev->stacklist);
+		INIT_LIST_HEAD(&dev->timerlist);
+		INIT_LIST_HEAD(&dev->entitylist);
+		write_lock_irqsave(&mISDN_device_lock, flags);
+		list_add_tail(&dev->list, &mISDN_devicelist);
+		write_unlock_irqrestore(&mISDN_device_lock, flags);
+	}
+	return(dev);
+}
+
+#ifdef FIXME
+mISDNdevice_t *
+get_free_rawdevice(void)
+{
+	mISDNdevice_t	*dev;
+	u_int		minor;
+
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "%s:\n", __FUNCTION__);
+	for (minor=mISDN_MINOR_RAW_MIN; minor<=mISDN_MINOR_RAW_MAX; minor++) {
+		dev = get_mISDNdevice4minor(minor);
+		if (device_debug & DEBUG_MGR_FUNC)
+			printk(KERN_DEBUG "%s: dev(%d) %p\n",
+				__FUNCTION__, minor, dev); 
+		if (!dev) {
+			dev = init_device(minor);
+			if (!dev)
+				return(NULL);
+			dev->rport.pif.func = mISDN_rdata_raw;
+			dev->rport.pif.fdata = dev;
+			return(dev);
+		}
+	}
+	return(NULL);
+}
+#endif
+
+int
+free_device(mISDNdevice_t *dev)
+{
+	struct list_head *item, *ni;
+	u_long	flags;
+
+	if (!dev)
+		return(-ENODEV);
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "%s: dev(%d)\n", __FUNCTION__, dev->minor);
+	/* release related stuff */
+	list_for_each_safe(item, ni, &dev->layerlist)
+		del_layer(list_entry(item, devicelayer_t, list));
+	list_for_each_safe(item, ni, &dev->stacklist)
+		del_stack(list_entry(item, devicestack_t, list));
+	list_for_each_safe(item, ni, &dev->timerlist)
+		dev_free_timer(list_entry(item, mISDNtimer_t, list));
+	if (!skb_queue_empty(&dev->rport.queue))
+		discard_queue(&dev->rport.queue);
+	if (!skb_queue_empty(&dev->wport.queue))
+		discard_queue(&dev->wport.queue);
+	write_lock_irqsave(&mISDN_device_lock, flags);
+	list_del(&dev->list);
+	write_unlock_irqrestore(&mISDN_device_lock, flags);
+	if (!list_empty(&dev->entitylist)) {
+		if (device_debug ) printk(KERN_WARNING "MISDN %s: entitylist not empty\n", __FUNCTION__);
+		list_for_each_safe(item, ni, &dev->entitylist) {
+			struct entity_item *ei = list_entry(item, struct entity_item, head);
+			list_del(item);
+			mISDN_delete_entity(ei->entity);
+			kfree(ei);
+		}
+	}
+	kfree(dev);
+	return(0);
+}
+
+static int
+mISDN_open(struct inode *ino, struct file *filep)
+{
+	u_int		minor = iminor(ino);
+	mISDNdevice_t 	*dev = NULL;
+	int		isnew = 0;
+
+	if (device_debug & DEBUG_DEV_OP)
+		printk(KERN_DEBUG "mISDN_open in: minor(%d) %p %p mode(%x)\n",
+			minor, filep, filep->private_data, filep->f_mode);
+	if (minor) {
+		dev = get_mISDNdevice4minor(minor);
+		if (dev) {
+			if ((dev->open_mode & filep->f_mode) & (FMODE_READ | FMODE_WRITE))
+				return(-EBUSY);
+		} else
+			return(-ENODEV);
+	} else if ((dev = init_device(minor)))
+		isnew = 1;
+	else
+		return(-ENOMEM);
+	dev->open_mode |= filep->f_mode & (FMODE_READ | FMODE_WRITE);
+	if (dev->open_mode & FMODE_READ){
+		dev->rport.lock = SPIN_LOCK_UNLOCKED;
+		dev->rport.maxqlen = DEFAULT_PORT_QUEUELEN;
+		test_and_set_bit(FLG_mISDNPORT_OPEN, &dev->rport.Flag);
+	}
+	if (dev->open_mode & FMODE_WRITE) {
+		dev->wport.lock = SPIN_LOCK_UNLOCKED;
+		dev->wport.maxqlen = DEFAULT_PORT_QUEUELEN;
+		test_and_set_bit(FLG_mISDNPORT_OPEN, &dev->wport.Flag);
+	}
+	filep->private_data = dev;
+	if (device_debug & DEBUG_DEV_OP)
+		printk(KERN_DEBUG "mISDN_open out: %p %p\n", filep, filep->private_data);
+
+	mISDN_inc_usage();
+
+	return(0);
+}
+
+static int
+mISDN_close(struct inode *ino, struct file *filep)
+{
+	mISDNdevice_t	*dev, *nd;
+
+	if (device_debug & DEBUG_DEV_OP)
+		printk(KERN_DEBUG "mISDN: mISDN_close %p %p\n", filep, filep->private_data);
+	read_lock(&mISDN_device_lock);
+	list_for_each_entry_safe(dev, nd, &mISDN_devicelist, list) {
+		if (dev == filep->private_data) {
+			if (device_debug & DEBUG_DEV_OP)
+				printk(KERN_DEBUG "mISDN: dev(%d) %p mode %x/%x\n",
+					dev->minor, dev, dev->open_mode, filep->f_mode);
+			dev->open_mode &= ~filep->f_mode;
+			read_unlock(&mISDN_device_lock);
+			if (filep->f_mode & FMODE_READ) {
+				test_and_clear_bit(FLG_mISDNPORT_OPEN,
+					&dev->rport.Flag);
+			}
+			if (filep->f_mode & FMODE_WRITE) {
+				test_and_clear_bit(FLG_mISDNPORT_OPEN,
+					&dev->wport.Flag);
+			}
+			filep->private_data = NULL;
+			if (!dev->minor)
+				free_device(dev);
+			mISDN_dec_usage();
+			return 0;
+		}
+	}
+	read_unlock(&mISDN_device_lock);
+	mISDN_dec_usage();
+	printk(KERN_WARNING "mISDN: No private data while closing device\n");
+	return 0;
+}
+
+static __inline__ ssize_t
+do_mISDN_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+	mISDNdevice_t	*dev = file->private_data;
+	size_t		len;
+//	u_long		flags;
+	struct sk_buff	*skb;
+
+	if (*off != file->f_pos)
+		return(-ESPIPE);
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return(-EFAULT);
+	if ((dev->minor == 0) && (count < mISDN_HEADER_LEN)) {
+		printk(KERN_WARNING "mISDN_read: count(%ld) too small\n", (long)count);
+		return(-ENOSPC);
+	}
+	if (device_debug & DEBUG_DEV_OP)
+		printk(KERN_DEBUG "mISDN_read: file(%d) %p max %ld\n",
+			dev->minor, file, (long)count);
+	if (skb_queue_empty(&dev->rport.queue)) {
+		if (file->f_flags & O_NONBLOCK)
+			return(-EAGAIN);
+		wait_event_interruptible(dev->rport.procq, (!skb_queue_empty(&dev->rport.queue)));
+		if (signal_pending(current))
+			return(-ERESTARTSYS);
+	}
+//	spin_lock_irqsave(&dev->rport.lock, flags);
+	len = 0;
+	while ((skb = skb_dequeue(&dev->rport.queue))) {
+		if (dev->minor == mISDN_CORE_DEVICE) {
+			if ((skb->len + mISDN_HEADER_LEN) > (count - len))
+				goto nospace;
+			if (copy_to_user(buf, skb->cb, mISDN_HEADER_LEN))
+				goto efault;
+			len += mISDN_HEADER_LEN;
+			buf += mISDN_HEADER_LEN;
+		} else {
+			if (skb->len > (count - len)) {
+			    nospace:
+				skb_queue_head(&dev->rport.queue, skb);
+				if (len)
+					break;
+//				spin_unlock_irqrestore(&dev->rport.lock, flags);
+				return(-ENOSPC);
+			}
+		}
+		if (skb->len) {
+			if (copy_to_user(buf, skb->data, skb->len)) {
+			    efault:
+				skb_queue_head(&dev->rport.queue, skb);
+//				spin_unlock_irqrestore(&dev->rport.lock, flags);
+				return(-EFAULT);
+			}
+			len += skb->len;
+			buf += skb->len;
+		}
+		dev_kfree_skb(skb);
+		if (test_bit(FLG_mISDNPORT_ONEFRAME, &dev->rport.Flag))
+			break;
+	}
+	*off += len;
+//	spin_unlock_irqrestore(&dev->rport.lock, flags);
+	if (device_debug & DEBUG_DEV_OP)
+		printk(KERN_DEBUG "mISDN_read: file(%d) %ld\n",
+			dev->minor, (long)len);
+	return(len);
+}
+
+static ssize_t
+mISDN_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+	mISDNdevice_t	*dev = file->private_data;
+	ssize_t		ret;
+
+	if (!dev)
+		return(-ENODEV);
+	down(&dev->io_sema);
+	ret = do_mISDN_read(file, buf, count, off);
+	up(&dev->io_sema);
+	return(ret);
+}
+
+static loff_t
+mISDN_llseek(struct file *file, loff_t offset, int orig)
+{
+	return -ESPIPE;
+}
+
+static __inline__ ssize_t
+do_mISDN_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+	mISDNdevice_t	*dev = file->private_data;
+	size_t		len;
+//	u_long		flags;
+	struct sk_buff	*skb;
+	mISDN_head_t	head;
+
+	if (*off != file->f_pos)
+		return(-ESPIPE);
+	if (device_debug & DEBUG_DEV_OP)
+		printk(KERN_DEBUG "mISDN_write: file(%d) %p count %ld queue(%d)\n",
+			dev->minor, file, (long)count, skb_queue_len(&dev->wport.queue));
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return(-EFAULT);
+	if (dev->minor == 0) {
+		if (count < mISDN_HEADER_LEN)
+			return(-EINVAL);
+	}
+	if (skb_queue_len(&dev->wport.queue) >= dev->wport.maxqlen) {
+		if (file->f_flags & O_NONBLOCK)
+			return(-EAGAIN);
+		wait_event_interruptible(dev->wport.procq, (skb_queue_len(&dev->wport.queue) < dev->wport.maxqlen));
+		if (signal_pending(current))
+			return(-ERESTARTSYS);
+	}
+//	spin_lock_irqsave(&dev->wport.lock, flags);
+	if (dev->minor == mISDN_CORE_DEVICE) {
+		len = count;
+		while (len >= mISDN_HEADER_LEN) {
+			if (copy_from_user(&head.addr, buf, mISDN_HEADER_LEN)) {
+//				spin_unlock_irqrestore(&dev->rport.lock, flags);
+				return(-EFAULT);
+			}
+			if (head.len > 0)
+				skb = alloc_stack_skb((head.len > PORT_SKB_MINIMUM) ? 
+					head.len : PORT_SKB_MINIMUM, PORT_SKB_RESERVE);
+			else
+				skb = alloc_stack_skb(PORT_SKB_MINIMUM, PORT_SKB_RESERVE);
+			if (!skb)
+				break;
+			memcpy(skb->cb, &head.addr, mISDN_HEADER_LEN);
+			len -= mISDN_HEADER_LEN;
+			buf += mISDN_HEADER_LEN;
+			if (head.len > 0) {
+				if (head.len > len) {
+					/* since header is complete we can handle this later */
+					if (copy_from_user(skb_put(skb, len), buf, len)) {
+						dev_kfree_skb(skb);
+//						spin_unlock_irqrestore(&dev->rport.lock, flags);
+						return(-EFAULT);
+					}
+					len = 0;
+				} else {
+					if (copy_from_user(skb_put(skb, head.len), buf, head.len)) {
+						dev_kfree_skb(skb);
+//						spin_unlock_irqrestore(&dev->rport.lock, flags);
+						return(-EFAULT);
+					}
+					len -= head.len;
+					buf += head.len;
+				}
+			}
+			skb_queue_tail(&dev->wport.queue, skb);
+		}
+		if (len)
+			printk(KERN_WARNING "%s: incomplete frame data (%ld/%ld)\n", __FUNCTION__, (long)len, (long)count);
+		if (test_and_set_bit(FLG_mISDNPORT_BUSY, &dev->wport.Flag)) {
+//			spin_unlock_irqrestore(&dev->wport.lock, flags);
+			return(count-len);
+		}
+//		spin_unlock_irqrestore(&dev->wport.lock, flags);
+		while ((skb = skb_dequeue(&dev->wport.queue))) {
+			if (mISDN_wdata_if(dev, skb))
+				dev_kfree_skb(skb);
+			wake_up(&dev->wport.procq);
+		}
+		test_and_clear_bit(FLG_mISDNPORT_BUSY, &dev->wport.Flag);
+	} else { /* raw device */
+		len = 0;
+#ifdef FIXME
+		skb = alloc_stack_skb(count, PORT_SKB_RESERVE);
+		if (!skb) {
+//			spin_unlock_irqrestore(&dev->wport.lock, flags);
+			return(0);
+		}
+		if (copy_from_user(skb_put(skb, count), buf, count)) {
+			dev_kfree_skb(skb);
+//			spin_unlock_irqrestore(&dev->wport.lock, flags);
+			return(-EFAULT);
+		}
+		skb_queue_tail(&dev->wport.queue, skb);
+		if (test_and_set_bit(FLG_mISDNPORT_BUSY, &dev->wport.Flag)) {
+//			spin_unlock_irqrestore(&dev->wport.lock, flags);
+			return(count);
+		}
+		while ((skb = skb_dequeue(&dev->wport.queue))) {
+			if (device_debug & DEBUG_DEV_OP)
+				printk(KERN_DEBUG "%s: wflg(%lx)\n", __FUNCTION__, dev->wport.Flag);
+			if (test_bit(FLG_mISDNPORT_BLOCK, &dev->wport.Flag)) {
+				skb_queue_head(&dev->wport.queue, skb); 
+				break;
+			}
+			if (test_bit(FLG_mISDNPORT_ENABLED, &dev->wport.Flag)) {
+				int ret;
+//				spin_unlock_irqrestore(&dev->wport.lock, flags);
+				ret = if_newhead(&dev->wport.pif, PH_DATA | REQUEST, (int)skb, skb);
+//				spin_lock_irqsave(&dev->wport.lock, flags);
+				if (ret) {
+					printk(KERN_WARNING "%s: dev(%d) down err(%d)\n",
+						__FUNCTION__, dev->minor, ret);
+					dev_kfree_skb(skb);
+				} else
+					test_and_set_bit(FLG_mISDNPORT_BLOCK, &dev->wport.Flag);
+			} else {
+				printk(KERN_WARNING "%s: dev(%d) wport not enabled\n",
+					__FUNCTION__, dev->minor);
+				dev_kfree_skb(skb);
+			}
+			wake_up(&dev->wport.procq);
+		}
+		test_and_clear_bit(FLG_mISDNPORT_BUSY, &dev->wport.Flag);
+//		spin_unlock_irqrestore(&dev->wport.lock, flags);
+#endif
+	}
+	return(count - len);
+}
+
+static ssize_t
+mISDN_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+	mISDNdevice_t	*dev = file->private_data;
+	ssize_t		ret;
+
+	if (!dev)
+		return(-ENODEV);
+	down(&dev->io_sema);
+	ret = do_mISDN_write(file, buf, count, off);
+	up(&dev->io_sema);
+	return(ret);
+}
+
+static unsigned int
+mISDN_poll(struct file *file, poll_table * wait)
+{
+	unsigned int	mask = POLLERR;
+	mISDNdevice_t	*dev = file->private_data;
+	mISDNport_t	*rport = (file->f_mode & FMODE_READ) ?
+					&dev->rport : NULL;
+	mISDNport_t	*wport = (file->f_mode & FMODE_WRITE) ?
+					&dev->wport : NULL;
+
+	if (dev) {
+		if (device_debug & DEBUG_DEV_OP)
+			printk(KERN_DEBUG "mISDN_poll in: file(%d) %p\n",
+				dev->minor, file);
+		if (rport) {
+			poll_wait(file, &rport->procq, wait);
+			mask = 0;
+			if (!skb_queue_empty(&rport->queue))
+				mask |= (POLLIN | POLLRDNORM);
+		}
+		if (wport) {
+			poll_wait(file, &wport->procq, wait);
+			if (mask == POLLERR)
+				mask = 0;
+			if (skb_queue_len(&wport->queue) < wport->maxqlen)
+				mask |= (POLLOUT | POLLWRNORM);
+		}
+	}
+	if (device_debug & DEBUG_DEV_OP)
+		printk(KERN_DEBUG "mISDN_poll out: file %p mask %x\n",
+			file, mask);
+	return(mask);
+}
+
+static struct file_operations mISDN_fops =
+{
+	llseek:		mISDN_llseek,
+	read:		mISDN_read,
+	write:		mISDN_write,
+	poll:		mISDN_poll,
+//	ioctl:		mISDN_ioctl,
+	open:		mISDN_open,
+	release:	mISDN_close,
+};
+
+
+#ifdef OBSOLETE
+static int
+set_if(devicelayer_t *dl, u_int prim, mISDNif_t *hif)
+{
+	int err = 0;
+
+	err = mISDN_SetIF(&dl->inst, hif, prim, from_up_down, from_up_down, dl);
+	return(err);
+}
+#endif
+
+static void setstack_conf(devicelayer_t *dl)
+{
+	struct sk_buff	*skb = create_link_skb(MGR_SETSTACK | INDICATION, 0, 0, NULL, 16);
+	mISDN_head_t	*hh;
+
+	if (!skb)
+		return;
+	hh = mISDN_HEAD_P(skb);
+	hh->addr = dl->id;
+	if (mISDN_rdata(dl->dev, skb))
+		kfree_skb(skb);
+}
+
+static int
+udev_manager(void *data, u_int prim, void *arg) {
+	mISDNinstance_t *inst = data;
+	mISDNdevice_t	*dev;
+	devicelayer_t	*dl;
+	int		err = -EINVAL;
+
+	if (device_debug & DEBUG_MGR_FUNC)
+		printk(KERN_DEBUG "udev_manager data:%p prim:%x arg:%p\n",
+			data, prim, arg);
+	if (!data)
+		return(-EINVAL);
+	read_lock(&mISDN_device_lock);
+	list_for_each_entry(dev, &mISDN_devicelist, list) {
+		list_for_each_entry(dl, &dev->layerlist, list) {
+			if (&dl->inst == inst) {
+				err = 0;
+				break;
+			}
+		}
+		if (!err)
+			break;
+	}
+	if (err) {
+		if (device_debug) 
+			printk(KERN_WARNING "dev_manager prim %x without device layer\n", prim);
+		goto out;
+	}
+	switch(prim) {
+#ifdef OBSOLETE
+	    case MGR_CONNECT | REQUEST:
+	    	err = mISDN_ConnectIF(inst, arg);
+	    	break;
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+	    	err = set_if(dl, prim, arg);
+		break;
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+	    	err = mISDN_DisConnectIF(inst, arg);
+	    	break;
+#endif
+	    case MGR_REGLAYER | CONFIRM:
+		err = 0;
+		break;
+	    case MGR_SETSTACK | INDICATION:
+	    	setstack_conf(dl);
+		err = 0;
+		break;
+	    case MGR_RELEASE | INDICATION:
+		if (device_debug & DEBUG_MGR_FUNC)
+			printk(KERN_DEBUG "release_dev id %x\n",
+				dl->inst.st->id);
+	    	del_layer(dl);
+		err = 0;
+	    	break;
+	    default:
+		if (device_debug) printk(KERN_WARNING "dev_manager prim %x not handled\n", prim);
+		err = -EINVAL;
+		break;
+	}
+out:
+	read_unlock(&mISDN_device_lock);
+	return(err);
+}
+
+int init_mISDNdev (int debug) {
+	int err,i;
+
+	udev_obj.name = MName;
+	udev_obj.owner = THIS_MODULE;
+	for (i=0; i<=MAX_LAYER_NR; i++) {
+		udev_obj.DPROTO.protocol[i] = ISDN_PID_ANY;
+		udev_obj.BPROTO.protocol[i] = ISDN_PID_ANY;
+	}
+	spin_lock_init(&udev_obj.lock);
+	INIT_LIST_HEAD(&udev_obj.ilist);
+	udev_obj.own_ctrl = udev_manager;
+	device_debug = debug;
+	
+	if (register_chrdev(mISDN_MAJOR, "mISDN", &mISDN_fops)) {
+		printk(KERN_WARNING "mISDN: Could not register devices\n");
+		return(-EIO);
+	}
+
+#ifdef CLASSDEV_HAS_DEVT
+	udev_obj.class_dev.devt = MKDEV(mISDN_MAJOR, 0);
+#endif
+
+	err = mISDN_register(&udev_obj);
+	if (err) {
+		printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
+		unregister_chrdev(mISDN_MAJOR, "mISDN");
+		return(err);
+	} else
+#ifdef CONFIG_DEVFS_FS
+		devfs_mk_cdev(MKDEV(mISDN_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "mISDN");
+#endif
+	return(err);
+}
+
+int free_mISDNdev(void) {
+	int 		err = 0;
+	mISDNdevice_t	*dev, *nd;
+
+	if (!list_empty(&mISDN_devicelist)) {
+		printk(KERN_WARNING "mISDN: devices open on remove\n");
+		list_for_each_entry_safe(dev, nd, &mISDN_devicelist, list) {
+			free_device(dev);
+		}
+		err = -EBUSY;
+	}
+	if ((err = mISDN_unregister(&udev_obj))) {
+		printk(KERN_ERR "Can't unregister UserDevice(%d)\n", err);
+	}
+	if ((err = unregister_chrdev(mISDN_MAJOR, "mISDN"))) {
+		printk(KERN_WARNING "mISDN: devices busy on remove\n");
+	}
+#ifdef CONFIG_DEVFS_FS
+	devfs_remove("mISDN");
+#endif
+	return(err);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/w6692.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/w6692.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/w6692.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1621 @@
+/* $Id: w6692.c,v 1.23 2007/02/13 10:43:45 crich Exp $
+
+ * w6692.c     low level driver for CCD's hfc-pci based cards
+ *
+ * Author      Karsten Keil <kkeil at suse.de>
+ *             based on the w6692 I4L driver from Petr Novak <petr.novak at i.cz>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "core.h"
+#include "channel.h"
+#include "layer1.h"
+#include "helper.h"
+#include "debug.h"
+#include "w6692.h"
+
+#include <linux/isdn_compat.h>
+
+extern const char *CardType[];
+
+const char *w6692_rev = "$Revision: 1.23 $";
+
+#define DBUSY_TIMER_VALUE	80
+
+enum {
+	W6692_ASUS,
+	W6692_WINBOND,
+	W6692_USR
+};
+
+/* private data in the PCI devices list */
+typedef struct _w6692_map{
+	u_int	subtype;
+	char	*name;
+} w6692_map_t;
+
+static w6692_map_t w6692_map[] =
+{
+	{W6692_ASUS, "Dynalink/AsusCom IS64PH"},
+	{W6692_WINBOND, "Winbond W6692"},
+	{W6692_USR, "USR W6692"}
+};
+
+#ifndef PCI_VENDOR_ID_USR2
+#define PCI_VENDOR_ID_USR2	0x16ec
+#define PCI_DEVICE_ID_USR2_6692	0x3409
+#endif
+
+typedef struct _w6692_bc {
+	struct timer_list	timer;
+	u_char			b_mode;
+} w6692_bc;
+
+typedef struct _w6692pci {
+	struct list_head	list;
+	struct pci_dev		*pdev;
+	u_int			subtype;
+	u_int			irq;
+	u_int			irqcnt;
+	u_int			addr;
+	int			pots;
+	int			led;
+	spinlock_t		lock;
+	u_char			imask;
+	u_char			pctl;
+	u_char			xaddr;
+	u_char			xdata;
+	w6692_bc		wbc[2];
+	channel_t		dch;
+	channel_t		bch[2];
+} w6692pci;
+
+#define W_LED1_ON	1
+#define W_LED1_S0STATUS	2
+
+static __inline__ u_char
+ReadW6692(w6692pci *card, u_char offset)
+{
+	return (inb(card->addr + offset));
+}
+
+static __inline__ void
+WriteW6692(w6692pci *card, u_char offset, u_char value)
+{
+	outb(value, card->addr + offset);
+}
+
+static __inline__ u_char
+ReadW6692B(w6692pci *card, int bchan, u_char offset)
+{
+	return (inb(card->addr + (bchan ? 0x40 : 0) + offset));
+}
+
+static __inline__ void
+WriteW6692B(w6692pci *card, int bchan, u_char offset, u_char value)
+{
+	outb(value, card->addr + (bchan ? 0x40 : 0) + offset);
+}
+
+static void
+enable_hwirq(w6692pci *card)
+{
+	WriteW6692(card, W_IMASK, card->imask);
+}
+
+static void
+disable_hwirq(w6692pci *card)
+{
+	WriteW6692(card, W_IMASK, 0xff);
+}
+
+static char *W6692Ver[] __initdata =
+{"W6692 V00", "W6692 V01", "W6692 V10",
+ "W6692 V11"};
+
+static void
+W6692Version(w6692pci *card, char *s)
+{
+	int val;
+
+	val = ReadW6692(card, W_D_RBCH);
+	printk(KERN_INFO "%s Winbond W6692 version (%x): %s\n", s, val, W6692Ver[(val >> 6) & 3]);
+}
+
+static void
+w6692_led_handler(w6692pci *card, int on)
+{
+	if (!card->led || card->subtype == W6692_USR)
+		return;
+	if (on) {
+		card->xdata &= 0xfb;	/*  LED ON */
+		WriteW6692(card, W_XDATA, card->xdata);
+	} else {
+		card->xdata |= 0x04;	/*  LED OFF */
+		WriteW6692(card, W_XDATA, card->xdata);
+	}
+}
+
+static void
+ph_command(w6692pci *card, u_char command)
+{
+	if (card->dch.debug & L1_DEB_ISAC)
+		mISDN_debugprint(&card->dch.inst, "ph_command %x", command);
+	WriteW6692(card, W_CIX, command);
+}
+
+static void
+W6692_new_ph(channel_t *dch)
+{
+	u_int		prim = PH_SIGNAL | INDICATION;
+	u_int		para = 0;
+
+	switch (dch->state) {
+		case W_L1CMD_RST:
+			ph_command(dch->hw, W_L1CMD_DRC);
+			mISDN_queue_data(&dch->inst, FLG_MSG_UP, PH_CONTROL | INDICATION, HW_RESET, 0, NULL, 0);
+			/* fall trough */
+		case W_L1IND_CD:
+			prim = PH_CONTROL | CONFIRM;
+			para = HW_DEACTIVATE;
+			test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+			break;
+		case W_L1IND_DRD:
+			prim = PH_CONTROL | INDICATION;
+			para = HW_DEACTIVATE;
+			test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+			break;
+		case W_L1IND_CE:
+			prim = PH_CONTROL | INDICATION;
+			para = HW_POWERUP;
+			break;
+		case W_L1IND_LD:
+			para = ANYSIGNAL;
+			break;
+		case W_L1IND_ARD:
+			para = INFO2;
+			break;
+		case W_L1IND_AI8:
+			para = INFO4_P8;
+			test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+			break;
+		case W_L1IND_AI10:
+			para = INFO4_P10;
+			test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+			break;
+		default:
+			return;
+	}
+	mISDN_queue_data(&dch->inst, FLG_MSG_UP, prim, para, 0, NULL, 0);
+}
+
+static void
+W6692_empty_Dfifo(w6692pci *card, int count)
+{
+	channel_t	*dch = &card->dch;
+	u_char		*ptr;
+
+	if ((dch->debug & L1_DEB_ISAC) && !(dch->debug & L1_DEB_ISAC_FIFO))
+		mISDN_debugprint(&dch->inst, "empty_Dfifo");
+
+	if (!dch->rx_skb) {
+		if (!(dch->rx_skb = alloc_stack_skb(dch->maxlen, dch->up_headerlen))) {
+			printk(KERN_WARNING "mISDN: D receive out of memory\n");
+			WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
+			return;
+		}
+	}
+	if ((dch->rx_skb->len + count) >= dch->maxlen) {
+		if (dch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&dch->inst, "empty_Dfifo overrun %d",
+				dch->rx_skb->len + count);
+		WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
+		return;
+	}
+	ptr = skb_put(dch->rx_skb, count);
+	insb(card->addr + W_D_RFIFO, ptr, count);
+	WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
+	if (dch->debug & L1_DEB_ISAC_FIFO) {
+		char *t = dch->log;
+
+		t += sprintf(t, "empty_Dfifo cnt %d", count);
+		mISDN_QuickHex(t, ptr, count);
+		mISDN_debugprint(&dch->inst, dch->log);
+	}
+}
+
+static void
+W6692_fill_Dfifo(w6692pci *card)
+{
+	channel_t	*dch = &card->dch;
+	int		count;
+	u_char		*ptr;
+	u_char		cmd = W_D_CMDR_XMS;
+
+	if ((dch->debug & L1_DEB_ISAC) && !(dch->debug & L1_DEB_ISAC_FIFO))
+		mISDN_debugprint(&dch->inst, "fill_Dfifo");
+
+	if (!dch->tx_skb)
+		return;
+	count = dch->tx_skb->len - dch->tx_idx;
+	if (count <= 0)
+		return;
+	if (count > 32)
+		count = 32;
+	else
+		cmd |= W_D_CMDR_XME;
+	ptr = dch->tx_skb->data + dch->tx_idx;
+	dch->tx_idx += count;
+	outsb(card->addr + W_D_XFIFO, ptr, count);
+	WriteW6692(card, W_D_CMDR, cmd);
+	if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) {
+		mISDN_debugprint(&dch->inst, "fill_Dfifo dbusytimer running");
+		del_timer(&dch->timer);
+	}
+	init_timer(&dch->timer);
+	dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+	add_timer(&dch->timer);
+	if (dch->debug & L1_DEB_ISAC_FIFO) {
+		char *t = dch->log;
+
+		t += sprintf(t, "fill_Dfifo cnt %d", count);
+		mISDN_QuickHex(t, ptr, count);
+		mISDN_debugprint(&dch->inst, dch->log);
+	}
+}
+
+static void
+d_retransmit(w6692pci *card)
+{
+	channel_t *dch = &card->dch;
+
+	if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+		del_timer(&dch->timer);
+#ifdef FIXME
+	if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
+		dchannel_sched_event(dch, D_CLEARBUSY);
+#endif
+	if (test_bit(FLG_TX_BUSY, &dch->Flags)) {
+		/* Restart frame */
+		dch->tx_idx = 0;
+		W6692_fill_Dfifo(card);
+	} else if (dch->tx_skb) { /* should not happen */
+		int_error();
+		test_and_set_bit(FLG_TX_BUSY, &dch->Flags);
+		dch->tx_idx = 0;
+		W6692_fill_Dfifo(card);
+	} else {
+		printk(KERN_WARNING "mISDN: w6692 XDU no TX_BUSY\n");
+		mISDN_debugprint(&dch->inst, "XDU no TX_BUSY");
+		if (test_bit(FLG_TX_NEXT, &dch->Flags)) {
+			dch->tx_skb = dch->next_skb;
+			if (dch->tx_skb) {
+				mISDN_head_t	*hh = mISDN_HEAD_P(dch->tx_skb);
+
+				dch->next_skb = NULL;
+				test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+				dch->tx_idx = 0;
+				queue_ch_frame(dch, CONFIRM, hh->dinfo, NULL);
+				W6692_fill_Dfifo(card);
+			} else {
+				printk(KERN_WARNING "w6692 xdu irq TX_NEXT without skb\n");
+				test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+			}
+		}
+	}
+}
+
+static void
+handle_rxD(w6692pci *card) {
+	u_char	stat;
+	int	count;
+
+	stat = ReadW6692(card, W_D_RSTA);
+	if (stat & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) {
+		if (stat & W_D_RSTA_RDOV) {
+			if (card->dch.debug & L1_DEB_WARN)
+				mISDN_debugprint(&card->dch.inst, "D-channel RDOV");
+#ifdef ERROR_STATISTIC
+			card->dch.err_rx++;
+#endif
+		}
+		if (stat & W_D_RSTA_CRCE) {
+			if (card->dch.debug & L1_DEB_WARN)
+				mISDN_debugprint(&card->dch.inst, "D-channel CRC error");
+#ifdef ERROR_STATISTIC
+			card->dch.err_crc++;
+#endif
+		}
+		if (stat & W_D_RSTA_RMB) {
+			if (card->dch.debug & L1_DEB_WARN)
+				mISDN_debugprint(&card->dch.inst, "D-channel ABORT");
+#ifdef ERROR_STATISTIC
+			card->dch.err_rx++;
+#endif
+		}
+		if (card->dch.rx_skb)
+			dev_kfree_skb(card->dch.rx_skb);
+		WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST);
+	} else {
+		count = ReadW6692(card, W_D_RBCL) & (W_D_FIFO_THRESH - 1);
+		if (count == 0)
+			count = W_D_FIFO_THRESH;
+		W6692_empty_Dfifo(card, count);
+		if (card->dch.rx_skb)
+			mISDN_queueup_newhead(&card->dch.inst, 0, PH_DATA_IND,
+				MISDN_ID_ANY, card->dch.rx_skb);
+	}
+	card->dch.rx_skb = NULL;
+}
+
+static void
+handle_txD(w6692pci *card) {
+	register channel_t	*dch = &card->dch;
+
+	if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+		del_timer(&dch->timer);
+#ifdef FIXME
+	if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
+		dchannel_sched_event(dch, D_CLEARBUSY);
+#endif
+	if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len) {
+		W6692_fill_Dfifo(card);
+	} else {
+		if (dch->tx_skb)
+			dev_kfree_skb(dch->tx_skb);
+		if (test_bit(FLG_TX_NEXT, &dch->Flags)) {
+			dch->tx_skb = dch->next_skb;
+			if (dch->tx_skb) {
+				mISDN_head_t	*hh = mISDN_HEAD_P(dch->tx_skb);
+
+				dch->next_skb = NULL;
+				test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+				dch->tx_idx = 0;
+				queue_ch_frame(dch, CONFIRM, hh->dinfo, NULL);
+				W6692_fill_Dfifo(card);
+			} else {
+				printk(KERN_WARNING "w6692 txD irq TX_NEXT without skb\n");
+				test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+				test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+			}
+		} else {
+			dch->tx_skb = NULL;
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+		}
+	}
+}
+
+static void
+handle_statusD(w6692pci *card)
+{
+	register channel_t	*dch = &card->dch;
+	u_char			exval, v1, cir;
+
+	exval = ReadW6692(card, W_D_EXIR);
+	
+	if (card->dch.debug & L1_DEB_ISAC)
+		mISDN_debugprint(&card->dch.inst, "D_EXIR %02x", exval);
+	if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) {	/* Transmit underrun/collision */
+		if (card->dch.debug & L1_DEB_WARN)
+			mISDN_debugprint(&card->dch.inst, "D-channel underrun/collision");
+#ifdef ERROR_STATISTIC
+		dch->err_tx++;
+#endif
+		d_retransmit(card);
+	}
+	if (exval & W_D_EXI_RDOV) {	/* RDOV */
+		if (card->dch.debug & L1_DEB_WARN)
+			mISDN_debugprint(&card->dch.inst, "D-channel RDOV");
+		WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST);
+	}
+	if (exval & W_D_EXI_TIN2)	/* TIN2 - never */
+		if (card->dch.debug & L1_DEB_WARN)
+			mISDN_debugprint(&card->dch.inst, "spurious TIN2 interrupt");
+	if (exval & W_D_EXI_MOC) {	/* MOC - not supported */
+		v1 = ReadW6692(card, W_MOSR);
+		if (card->dch.debug & L1_DEB_ISAC) {
+			mISDN_debugprint(&card->dch.inst, "spurious MOC interrupt");
+			mISDN_debugprint(&card->dch.inst, "MOSR %02x", v1);
+		}
+	}
+	if (exval & W_D_EXI_ISC) {	/* ISC - Level1 change */
+		cir = ReadW6692(card, W_CIR);
+		if (card->dch.debug & L1_DEB_ISAC)
+			mISDN_debugprint(&card->dch.inst, "ISC CIR=0x%02X", cir);
+		if (cir & W_CIR_ICC) {
+			v1 = cir & W_CIR_COD_MASK;
+			if (card->dch.debug & L1_DEB_ISAC)
+				mISDN_debugprint(&card->dch.inst, "ph_state_change %x -> %x",
+					dch->state, v1);
+			dch->state = v1;
+			if (card->led & W_LED1_S0STATUS) {
+				switch (v1) {
+					case W_L1IND_AI8:
+					case W_L1IND_AI10:
+						w6692_led_handler(card, 1);
+						break;
+					default:
+						w6692_led_handler(card, 0);
+						break;
+				}
+			}
+			W6692_new_ph(dch);
+		}
+		if (cir & W_CIR_SCC) {
+			v1 = ReadW6692(card, W_SQR);
+			if (card->dch.debug & L1_DEB_ISAC)
+				mISDN_debugprint(&card->dch.inst, "SCC SQR=0x%02X", v1);
+		}
+	}
+	if (exval & W_D_EXI_WEXP) {
+		if (card->dch.debug & L1_DEB_WARN)
+			mISDN_debugprint(&card->dch.inst, "spurious WEXP interrupt!");
+	}
+	if (exval & W_D_EXI_TEXP) {
+		if (card->dch.debug & L1_DEB_WARN)
+			mISDN_debugprint(&card->dch.inst, "spurious TEXP interrupt!");
+	}
+}
+
+static void
+W6692_empty_Bfifo(channel_t *bch, int count)
+{
+	u_char		*ptr;
+	w6692pci	*card = bch->inst.privat;
+
+	if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
+		mISDN_debugprint(&bch->inst, "empty_Bfifo %d", count);
+	if (unlikely(bch->state == ISDN_PID_NONE)) {
+		if (bch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&bch->inst, "empty_Bfifo ISDN_PID_NONE");
+		WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+		if (bch->rx_skb)
+			skb_trim(bch->rx_skb, 0);
+		return;
+	}
+	if (!bch->rx_skb) {
+		bch->rx_skb = alloc_stack_skb(bch->maxlen, bch->up_headerlen);
+		if (unlikely(!bch->rx_skb)) {
+			printk(KERN_WARNING "mISDN: B receive out of memory\n");
+			WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+			return;
+		}
+	}
+	if (bch->rx_skb->len + count > bch->maxlen) {
+		if (bch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&bch->inst, "empty_Bfifo incoming packet too large");
+		WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+		skb_trim(bch->rx_skb, 0);
+		return;
+	}
+	ptr = skb_put(bch->rx_skb, count);
+	insb(card->addr + W_B_RFIFO + (bch->channel ? 0x40 : 0), ptr, count);
+	WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+
+	if (bch->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bch->log;
+
+		t += sprintf(t, "empty_Bfifo B%d cnt %d", bch->channel, count);
+		mISDN_QuickHex(t, ptr, count);
+		mISDN_debugprint(&bch->inst, bch->log);
+	}
+}
+
+static void
+W6692_fill_Bfifo(channel_t *bch)
+{
+	w6692pci	*card = bch->inst.privat;
+	int		count;
+	u_char		*ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS;
+
+	if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
+		mISDN_debugprint(&bch->inst, "%s", __FUNCTION__);
+	if (!bch->tx_skb)
+		return;
+	count = bch->tx_skb->len - bch->tx_idx;
+	if (count <= 0)
+		return;
+	ptr = bch->tx_skb->data + bch->tx_idx;
+	if (count > W_B_FIFO_THRESH) {
+		count = W_B_FIFO_THRESH;
+	} else {
+		if (test_bit(FLG_HDLC, &bch->Flags))
+			cmd |= W_B_CMDR_XME;
+	}
+	if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
+		mISDN_debugprint(&bch->inst, "%s: %d/%d", __FUNCTION__,
+			count, bch->tx_idx);
+	bch->tx_idx += count;
+	outsb(card->addr + W_B_XFIFO + (bch->channel ? 0x40 : 0), ptr, count);
+	WriteW6692B(card, bch->channel, W_B_CMDR, cmd);
+	if (bch->debug & L1_DEB_HSCX_FIFO) {
+		char *t = bch->log;
+
+		t += sprintf(t, "fill_Bfifo  B%d cnt %d",
+			     bch->channel, count);
+		mISDN_QuickHex(t, ptr, count);
+		mISDN_debugprint(&bch->inst, bch->log);
+	}
+}
+
+static int
+setvolume(channel_t *bch, int mic, struct sk_buff *skb)
+{
+	w6692pci	*card = bch->inst.privat;
+	u16		*vol = (u16 *)skb->data;
+	u_char		val;
+
+	if ((card->pots == 0) || !test_bit(FLG_TRANSPARENT, &bch->Flags))
+		return(-ENODEV);
+	if (skb->len < 2)
+		return(-EINVAL);
+	if (*vol > 7)
+		return(-EINVAL);
+	val = *vol & 7;
+	val = 7 - val;
+	if (mic) {
+		val <<= 3;
+		card->xaddr &= 0xc7;
+	} else {
+		card->xaddr &= 0xf8;
+	}
+	card->xaddr |= val;
+	WriteW6692(card, W_XADDR, card->xaddr);
+	return(0);
+}
+
+static int
+enable_pots(channel_t *bch)
+{
+	w6692_bc	*bhw  = bch->hw;
+	w6692pci	*card = bch->inst.privat;
+
+	if ((card->pots == 0) || !test_bit(FLG_TRANSPARENT, &bch->Flags))
+		return(-ENODEV);
+	
+	bhw->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0;
+	WriteW6692B(card, bch->channel, W_B_MODE, bhw->b_mode);
+	WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+	card->pctl |= (bch->channel ? W_PCTL_PCX : 0);
+	WriteW6692(card, W_PCTL, card->pctl);
+	return(0);
+}
+
+static int
+disable_pots(channel_t *bch)
+{
+	w6692_bc	*bhw  = bch->hw;
+	w6692pci	*card = bch->inst.privat;
+
+	if (card->pots == 0)
+		return(-ENODEV);
+	bhw->b_mode &= ~(W_B_MODE_EPCM | W_B_MODE_BSW0);
+	WriteW6692B(card, bch->channel, W_B_MODE, bhw->b_mode);
+	WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | W_B_CMDR_XRST);
+	return(0);
+}
+
+static int
+mode_w6692(channel_t *bch, int bc, int protocol)
+{
+	w6692pci	*card = bch->inst.privat;
+	w6692_bc	*bhw  = bch->hw;
+	
+
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "B%d protocol %x-->%x ch %d-->%d",
+			bch->channel, bch->state, protocol, bch->channel, bc);
+	switch (protocol) {
+		case (-1): /* used for init */
+			bch->state = -1;
+			bch->channel = bc;
+		case (ISDN_PID_NONE):
+			if (bch->state == ISDN_PID_NONE)
+				break;
+			bch->state = ISDN_PID_NONE;
+			if (card->pots && (bhw->b_mode & W_B_MODE_EPCM))
+				disable_pots(bch);
+			bhw->b_mode = 0;
+			bch->tx_idx = 0;
+			if (bch->next_skb) {
+				dev_kfree_skb(bch->next_skb);
+				bch->next_skb = NULL;
+			}
+			if (bch->tx_skb) {
+				dev_kfree_skb(bch->tx_skb);
+				bch->tx_skb = NULL;
+			}
+			if (bch->rx_skb) {
+				dev_kfree_skb(bch->rx_skb);
+				bch->rx_skb = NULL;
+			}
+			WriteW6692B(card, bch->channel, W_B_MODE, bhw->b_mode);
+			WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+			test_and_clear_bit(FLG_HDLC, &bch->Flags);
+			test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
+			break;
+		case (ISDN_PID_L1_B_64TRANS):
+			bch->state = protocol;
+			bhw->b_mode = W_B_MODE_MMS;
+			WriteW6692B(card, bch->channel, W_B_MODE, bhw->b_mode);
+			WriteW6692B(card, bch->channel, W_B_EXIM, 0);
+			WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | W_B_CMDR_XRST);
+			test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
+			break;
+		case (ISDN_PID_L1_B_64HDLC):
+			bch->state = protocol;
+			bhw->b_mode = W_B_MODE_ITF;
+			WriteW6692B(card, bch->channel, W_B_MODE, bhw->b_mode);
+			WriteW6692B(card, bch->channel, W_B_ADM1, 0xff);
+			WriteW6692B(card, bch->channel, W_B_ADM2, 0xff);
+			WriteW6692B(card, bch->channel, W_B_EXIM, 0);
+			WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | W_B_CMDR_XRST);
+			test_and_set_bit(FLG_HDLC, &bch->Flags);
+			break;
+		default:
+			mISDN_debugprint(&bch->inst, "prot not known %x", protocol);
+			return(-ENOPROTOOPT);
+	}
+	return(0);
+}
+
+static void
+send_next(channel_t *bch)
+{
+	if (test_bit(FLG_ACTIVE, &bch->Flags))
+		return;
+	if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
+		W6692_fill_Bfifo(bch);
+	else {
+		if (bch->tx_skb)
+			dev_kfree_skb(bch->tx_skb);
+		bch->tx_idx = 0;
+		if (test_bit(FLG_TX_NEXT, &bch->Flags)) {
+			bch->tx_skb = bch->next_skb;
+			if (bch->tx_skb) {
+				mISDN_head_t	*hh = mISDN_HEAD_P(bch->tx_skb);
+				bch->next_skb = NULL;
+				test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+				queue_ch_frame(bch, CONFIRM, hh->dinfo, NULL);
+				W6692_fill_Bfifo(bch);
+			} else {
+				test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
+				printk(KERN_WARNING "W6692 tx irq TX_NEXT without skb\n");
+				test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+			}
+		} else {
+			bch->tx_skb = NULL;
+			test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		}
+	}
+}
+
+static void
+W6692B_interrupt(w6692pci *card, int ch)
+{
+	channel_t	*bch = &card->bch[ch];
+	int		count;
+	u_char		stat, star = 0;
+	struct sk_buff	*skb;
+
+	stat = ReadW6692B(card, ch, W_B_EXIR);
+	if (bch->debug & L1_DEB_HSCX)
+		mISDN_debugprint(&bch->inst, "ch%d stat %#x", bch->channel, stat);
+
+	if (stat & W_B_EXI_RME) {
+		star = ReadW6692B(card, ch, W_B_STAR);
+		if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) {
+			if ((star & W_B_STAR_RDOV) && test_bit(FLG_ACTIVE, &bch->Flags)) {
+				if (bch->debug & L1_DEB_WARN)
+					mISDN_debugprint(&bch->inst, "B%d RDOV protocol=%x",
+						ch +1, bch->state);
+#ifdef ERROR_STATISTIC
+				bch->err_rdo++;
+#endif
+			}
+			if (test_bit(FLG_HDLC, &bch->Flags)) {
+				if (star & W_B_STAR_CRCE) {
+					if (bch->debug & L1_DEB_WARN)
+						mISDN_debugprint(&bch->inst,
+							"B%d CRC error", ch+1);
+#ifdef ERROR_STATISTIC
+					bch->err_crc++;
+#endif
+				}
+				if (star & W_B_STAR_RMB) {
+					if (bch->debug & L1_DEB_WARN)
+						mISDN_debugprint(&bch->inst,
+							"B%d message abort", ch+1);
+#ifdef ERROR_STATISTIC
+					bch->err_inv++;
+#endif
+				}
+			}
+			WriteW6692B(card, ch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
+			if (bch->rx_skb)
+				skb_trim(bch->rx_skb, 0);
+		} else {
+			count = ReadW6692B(card, ch, W_B_RBCL) & (W_B_FIFO_THRESH - 1);
+			if (count == 0)
+				count = W_B_FIFO_THRESH;
+			W6692_empty_Bfifo(bch, count);
+			if (bch->rx_skb && bch->rx_skb->len > 0) {
+				if (bch->debug & L1_DEB_HSCX)
+					mISDN_debugprint(&bch->inst, "Bchan Frame %d", bch->rx_skb->len);
+				if (bch->rx_skb->len < MISDN_COPY_SIZE) {
+					skb = alloc_stack_skb(bch->rx_skb->len, bch->up_headerlen);
+					if (skb) {
+						memcpy(skb_put(skb, bch->rx_skb->len),
+							bch->rx_skb->data, bch->rx_skb->len);
+						skb_trim(bch->rx_skb, 0);
+					} else {
+						skb = bch->rx_skb;
+						bch->rx_skb = NULL;
+					}
+				} else {
+					skb = bch->rx_skb;
+					bch->rx_skb = NULL;
+				}
+				queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, skb);
+			}
+		}
+	}
+	if (stat & W_B_EXI_RMR) {
+		if (!(stat & W_B_EXI_RME))
+			star = ReadW6692B(card, ch, W_B_STAR);
+		if (star & W_B_STAR_RDOV) {
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "B%d RDOV protocol=%x",
+					ch +1, bch->state);
+#ifdef ERROR_STATISTIC
+			bch->err_rdo++;
+#endif
+			WriteW6692B(card, ch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
+		} else {
+			W6692_empty_Bfifo(bch, W_B_FIFO_THRESH);
+			if (test_bit(FLG_TRANSPARENT, &bch->Flags) &&
+				bch->rx_skb && (bch->rx_skb->len > 0)) {
+				/* receive audio data */
+				if (bch->debug & L1_DEB_HSCX)
+					mISDN_debugprint(&bch->inst,
+						"Bchan Frame %d", bch->rx_skb->len);
+				queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, bch->rx_skb);
+				bch->rx_skb = NULL;
+			}
+		}
+	}
+	if (stat & W_B_EXI_RDOV) {
+		if (!(star & W_B_STAR_RDOV)) { /* only if it is not handled yet */
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "B%d RDOV IRQ protocol=%x",
+					ch +1, bch->state);
+#ifdef ERROR_STATISTIC
+			bch->err_rdo++;
+#endif
+			WriteW6692B(card, ch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);
+		}
+	}
+	if (stat & W_B_EXI_XFR) {
+		if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) {
+			star = ReadW6692B(card, ch, W_B_STAR);
+			if (bch->debug & L1_DEB_HSCX)
+				mISDN_debugprint(&bch->inst, "B%d star %02x", ch +1, star);
+		}
+		if (star & W_B_STAR_XDOW) {
+			if (bch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&bch->inst, "B%d XDOW protocol=%x",
+					ch +1, bch->state);
+#ifdef ERROR_STATISTIC
+			bch->err_xdu++;
+#endif
+			WriteW6692B(card, ch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
+			/* resend */
+			if (bch->tx_skb) {
+				if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+					bch->tx_idx = 0;
+			}
+		}
+		send_next(bch);
+		if (stat & W_B_EXI_XDUN)
+			return; /* handle XDOW only once */
+	}
+	if (stat & W_B_EXI_XDUN) {
+		if (bch->debug & L1_DEB_WARN)
+			mISDN_debugprint(&bch->inst, "B%d XDUN protocol=%x",
+				ch +1, bch->state);
+#ifdef ERROR_STATISTIC
+		bch->err_xdu++;
+#endif
+		WriteW6692B(card, ch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
+		/* resend */
+		if (bch->tx_skb) {
+			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+				bch->tx_idx = 0;
+		}
+		send_next(bch);
+	}
+}
+
+static irqreturn_t
+w6692_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	w6692pci	*card = dev_id;
+	u_char		ista;
+
+	spin_lock(&card->lock);
+	ista = ReadW6692(card, W_ISTA);
+	if ((ista | card->imask) == card->imask) {
+		/* possible a shared  IRQ reqest */
+		spin_unlock(&card->lock);
+		return IRQ_NONE;
+	}
+	card->irqcnt++;
+/* Begin IRQ handler */
+	if (card->dch.debug & L1_DEB_ISAC)
+		mISDN_debugprint(&card->dch.inst, "ista %02x", ista);
+	ista &= ~card->imask;
+	if (ista & W_INT_B1_EXI)
+		W6692B_interrupt(card, 0);
+	if (ista & W_INT_B2_EXI)
+		W6692B_interrupt(card, 1);
+	if (ista & W_INT_D_RME)
+		handle_rxD(card);
+	if (ista & W_INT_D_RMR)
+		W6692_empty_Dfifo(card, W_D_FIFO_THRESH);
+	if (ista & W_INT_D_XFR)
+		handle_txD(card);
+	if (ista & W_INT_D_EXI)
+		handle_statusD(card);
+	if (ista & (W_INT_XINT0 | W_INT_XINT1)) /* XINT0/1 - never */
+		mISDN_debugprint(&card->dch.inst, "W6692 spurious XINT!");
+/* End IRQ Handler */
+	spin_unlock(&card->lock);
+	return IRQ_HANDLED;
+}
+
+static void
+dbusy_timer_handler(channel_t *dch)
+{
+	w6692pci	*card = dch->hw;
+	int		rbch, star;
+	u_long		flags;
+
+	if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) {
+		spin_lock_irqsave(dch->inst.hwlock, flags);
+		rbch = ReadW6692(card, W_D_RBCH);
+		star = ReadW6692(card, W_D_STAR);
+		if (dch->debug) 
+			mISDN_debugprint(&dch->inst, "D-Channel Busy RBCH %02x STAR %02x",
+				rbch, star);
+		if (star & W_D_STAR_XBZ) {	/* D-Channel Busy */
+			test_and_set_bit(FLG_L1_BUSY, &dch->Flags);
+		} else {
+			/* discard frame; reset transceiver */
+			test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags);
+			if (dch->tx_idx) {
+				dch->tx_idx = 0;
+			} else {
+				printk(KERN_WARNING "mISDN: W6692 D-Channel Busy no tx_idx\n");
+				mISDN_debugprint(&dch->inst, "D-Channel Busy no tx_idx");
+			}
+			/* Transmitter reset */
+			WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST);	/* Transmitter reset */
+		}
+		spin_unlock_irqrestore(dch->inst.hwlock, flags);
+	}
+}
+
+void initW6692(w6692pci *card)
+{
+	u_char	val;
+
+	card->dch.timer.function = (void *) dbusy_timer_handler;
+	card->dch.timer.data = (u_long) &card->dch;
+	init_timer(&card->dch.timer);
+	mode_w6692(&card->bch[0], 0, -1);
+	mode_w6692(&card->bch[1], 1, -1);
+	WriteW6692(card, W_D_CTL, 0x00);
+	disable_hwirq(card);
+	WriteW6692(card, W_D_SAM, 0xff);
+	WriteW6692(card, W_D_TAM, 0xff);
+	WriteW6692(card, W_D_MODE, W_D_MODE_RACT);
+	card->dch.state = W_L1CMD_RST;
+	ph_command(card, W_L1CMD_RST);
+	ph_command(card, W_L1CMD_ECK);
+	/* enable all IRQ but extern */
+	card->imask = 0x18;
+	WriteW6692(card, W_D_EXIM, 0x00);
+	WriteW6692B(card, 0, W_B_EXIM, 0);
+	WriteW6692B(card, 1, W_B_EXIM, 0);
+	/* Reset D-chan receiver and transmitter */
+	WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST);
+	/* Reset B-chan receiver and transmitter */
+	WriteW6692B(card, 0, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+	WriteW6692B(card, 1, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+	/* enable peripheral */
+	if (card->subtype == W6692_USR) {
+		/* seems that USR implemented some power control features
+		 * Pin 79 is connected to the oscilator circuit so we
+		 * have to handle it here
+		 */
+		card->pctl = 0x80;
+		card->xdata = 0;
+		WriteW6692(card, W_PCTL, card->pctl);
+		WriteW6692(card, W_XDATA, card->xdata);
+	} else {
+		card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 | W_PCTL_OE1 | W_PCTL_OE0;
+		if (card->pots) {
+			card->xaddr = 0x00; /* all sw off */
+			card->xdata |= 0x06;  /*  POWER UP/ LED OFF / ALAW */
+			WriteW6692(card, W_PCTL, card->pctl);
+			WriteW6692(card, W_XADDR, card->xaddr);
+			WriteW6692(card, W_XDATA, card->xdata);
+			val = ReadW6692(card, W_XADDR);
+			if (card->dch.debug & L1_DEB_ISAC)
+				mISDN_debugprint(&card->dch.inst, "W_XADDR: %02x", val);
+			if (card->led & W_LED1_ON)
+				w6692_led_handler(card, 1);
+			else
+				w6692_led_handler(card, 0);
+		}
+	}
+}
+
+static void reset_w6692(w6692pci *card)
+{
+	WriteW6692(card, W_D_CTL, W_D_CTL_SRST);
+	mdelay(10);
+	WriteW6692(card, W_D_CTL, 0);
+}
+
+static int init_card(w6692pci *card)
+{
+	int	cnt = 3;
+	u_long	flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	disable_hwirq(card);
+	spin_unlock_irqrestore(&card->lock, flags);
+	if (request_irq(card->irq, w6692_interrupt, SA_SHIRQ, "w6692", card)) {
+		printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n", card->irq);
+		return(-EIO);
+	}
+	spin_lock_irqsave(&card->lock, flags);
+	while (cnt) {
+		initW6692(card);
+		enable_hwirq(card);
+		spin_unlock_irqrestore(&card->lock, flags);
+		/* Timeout 10ms */
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout((10*HZ)/1000);
+		printk(KERN_INFO "w6692: IRQ %d count %d\n",
+			card->irq, card->irqcnt);
+		if (!card->irqcnt) {
+			printk(KERN_WARNING
+			       "w6692: IRQ(%d) getting no interrupts during init %d\n",
+			       card->irq, 4 - cnt);
+			if (cnt == 1) {
+				return (-EIO);
+			} else {
+				spin_lock_irqsave(&card->lock, flags);
+				reset_w6692(card);
+				cnt--;
+			}
+		} else {
+			return(0);
+		}
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+	return(-EIO);
+}
+
+#define MAX_CARDS	4
+static int w6692_cnt;
+static u_int protocol[MAX_CARDS];
+static int layermask[MAX_CARDS];
+
+static mISDNobject_t	w6692;
+static int debug;
+static int pots[MAX_CARDS];
+static int led[MAX_CARDS];
+
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#define MODULE_PARM_T   "1-4i"
+MODULE_PARM(protocol, MODULE_PARM_T);
+MODULE_PARM(layermask, MODULE_PARM_T);
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+
+#ifdef OLD_MODULE_PARAM_ARRAY
+static int num_led=0, num_pots=0, num_protocol=0, num_layermask=0; 
+module_param_array(led, uint, num_led, S_IRUGO | S_IWUSR);
+module_param_array(pots, uint, num_pots, S_IRUGO | S_IWUSR);
+module_param_array(protocol, uint, num_protocol, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, num_layermask, S_IRUGO | S_IWUSR);
+#else 
+module_param_array(led, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(pots, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(protocol, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, NULL, S_IRUGO | S_IWUSR);
+#endif
+#endif
+#endif
+
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+static int
+w6692_bmsg(channel_t *bch, struct sk_buff *skb)
+{
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_ESTABLISH  | REQUEST))) {
+		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
+			spin_lock_irqsave(bch->inst.hwlock, flags);
+			ret = mode_w6692(bch, bch->channel, bch->inst.pid.protocol[1]);
+			spin_unlock_irqrestore(bch->inst.hwlock, flags);
+		}
+#ifdef FIXME
+		if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+			if (bch->dev)
+				if_link(&bch->dev->rport.pif,
+					hh->prim | CONFIRM, 0, 0, NULL, 0);
+#endif
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(&bch->inst, 0,
+			hh->prim | CONFIRM, ret, skb));
+	} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_RELEASE | REQUEST)) ||
+		((hh->prim == (PH_CONTROL | REQUEST) &&
+		(hh->dinfo == HW_DEACTIVATE)))) {
+		spin_lock_irqsave(bch->inst.hwlock, flags);
+		if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+			dev_kfree_skb(bch->next_skb);
+			bch->next_skb = NULL;
+		}
+		if (bch->tx_skb) {
+			dev_kfree_skb(bch->tx_skb);
+			bch->tx_skb = NULL;
+		}
+		if (bch->rx_skb) {
+			dev_kfree_skb(bch->rx_skb);
+			bch->rx_skb = NULL;
+		}
+		test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		mode_w6692(bch, bch->channel, ISDN_PID_NONE);
+		test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+		spin_unlock_irqrestore(bch->inst.hwlock, flags);
+		skb_trim(skb, 0);
+		if (hh->prim != (PH_CONTROL | REQUEST)) {
+#ifdef FIXME
+			if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+				if (bch->dev)
+					if_link(&bch->dev->rport.pif,
+						hh->prim | CONFIRM, 0, 0, NULL, 0);
+#endif
+			if (!mISDN_queueup_newhead(&bch->inst, 0,
+				hh->prim | CONFIRM, 0, skb))
+				return(0);
+		}
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		spin_lock_irqsave(bch->inst.hwlock, flags);
+		if (hh->dinfo == HW_POTS_ON) {
+			ret = enable_pots(bch);
+		} else if (hh->dinfo == HW_POTS_OFF) {
+			ret = disable_pots(bch);
+		} else if (hh->dinfo == HW_POTS_SETMICVOL) {
+			ret = setvolume(bch, 1, skb);
+		} else if (hh->dinfo == HW_POTS_SETSPKVOL) {
+			ret = setvolume(bch, 0, skb);
+		} else
+			ret = -EINVAL;
+		spin_unlock_irqrestore(bch->inst.hwlock, flags);
+	} else
+		ret = -EAGAIN;
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+static int
+w6692_dmsg(channel_t *dch, struct sk_buff *skb)
+{
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	if (hh->prim == (PH_SIGNAL | REQUEST)) {
+		spin_lock_irqsave(dch->inst.hwlock, flags);
+		if (hh->dinfo == INFO3_P8)
+			ph_command(dch->hw, W_L1CMD_AR8);
+		else if (hh->dinfo == INFO3_P10)
+			ph_command(dch->hw, W_L1CMD_AR10);
+		else
+			ret = -EINVAL;
+		spin_unlock_irqrestore(dch->inst.hwlock, flags);
+	} else if (hh->prim == (PH_CONTROL | REQUEST)) {
+		spin_lock_irqsave(dch->inst.hwlock, flags);
+		if (hh->dinfo == HW_RESET) {
+			if (dch->state != W_L1IND_DRD)
+				ph_command(dch->hw, W_L1CMD_RST);
+			ph_command(dch->hw, W_L1CMD_ECK);
+		} else if (hh->dinfo == HW_POWERUP) {
+			ph_command(dch->hw, W_L1CMD_ECK);
+		} else if (hh->dinfo == HW_DEACTIVATE) {
+			if (dch->next_skb) {
+				dev_kfree_skb(dch->next_skb);
+				dch->next_skb = NULL;
+			}
+			if (dch->tx_skb) {
+				dev_kfree_skb(dch->tx_skb);
+				dch->tx_skb = NULL;
+			}
+			if (dch->rx_skb) {
+				dev_kfree_skb(dch->rx_skb);
+				dch->rx_skb = NULL;
+			}
+			test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+			test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
+			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+			if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+				del_timer(&dch->timer);
+#ifdef FIXME
+			if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
+				dchannel_sched_event(dch, D_CLEARBUSY);
+#endif
+		} else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) {
+			u_char	val = 0;
+
+			if (1 & hh->dinfo)
+				val |= 0x0c;
+			if (2 & hh->dinfo)
+				val |= 0x3;
+			/* !!! not implemented yet */
+		} else {
+			if (dch->debug & L1_DEB_WARN)
+				mISDN_debugprint(&dch->inst, "w6692_dmsg unknown ctrl %x",
+					hh->dinfo);
+			ret = -EINVAL;
+		}
+		spin_unlock_irqrestore(dch->inst.hwlock, flags);
+	} else
+		ret = -EAGAIN;
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+static int
+w6692_l2l1(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*chan = container_of(inst, channel_t, inst);
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+
+	if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		ret = channel_senddata(chan, hh->dinfo, skb);
+		if (ret > 0) { /* direct TX */
+			if (test_bit(FLG_BCHANNEL, &chan->Flags))
+				W6692_fill_Dfifo(chan->hw);
+			else if (test_bit(FLG_DCHANNEL, &chan->Flags))
+				W6692_fill_Bfifo(chan);
+			else
+				int_error();
+			ret = 0;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		return(ret);
+	} 
+	if (test_bit(FLG_DCHANNEL, &chan->Flags)) {
+		ret = w6692_dmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (test_bit(FLG_BCHANNEL, &chan->Flags)) {
+		ret = w6692_bmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+int __init 
+setup_w6692(w6692pci *card)
+{
+	u_int	val;
+
+	if (!request_region(card->addr, 256, "w6692")) {
+		printk(KERN_WARNING
+		       "mISDN: %s config port %x-%x already in use\n",
+		       "w6692",
+		       card->addr,
+		       card->addr + 255);
+		return(-EIO);
+	}
+	W6692Version(card, "W6692:");
+	val = ReadW6692(card, W_ISTA);
+	if (debug)
+		printk(KERN_DEBUG "W6692 ISTA=0x%X\n", val);
+	val = ReadW6692(card, W_IMASK);
+	if (debug)
+		printk(KERN_DEBUG "W6692 IMASK=0x%X\n", val);
+	val = ReadW6692(card, W_D_EXIR);
+	if (debug)
+		printk(KERN_DEBUG "W6692 D_EXIR=0x%X\n", val);
+	val = ReadW6692(card, W_D_EXIM);
+	if (debug)
+		printk(KERN_DEBUG "W6692 D_EXIM=0x%X\n", val);
+	val = ReadW6692(card, W_D_RSTA);
+	if (debug)
+		printk(KERN_DEBUG "W6692 D_RSTA=0x%X\n", val);
+	return (0);
+}
+
+static void
+release_card(w6692pci *card)
+{
+	u_long	flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	disable_hwirq(card);
+	spin_unlock_irqrestore(&card->lock, flags);
+	free_irq(card->irq, card);
+	spin_lock_irqsave(&card->lock, flags);
+	mode_w6692(&card->bch[0], 0, ISDN_PID_NONE);
+	mode_w6692(&card->bch[1], 1, ISDN_PID_NONE);
+	if (card->led || card->subtype == W6692_USR) {
+		card->xdata |= 0x04;	/*  LED OFF */
+		WriteW6692(card, W_XDATA, card->xdata);
+	}
+	release_region(card->addr, 256);
+	mISDN_freechannel(&card->bch[1]);
+	mISDN_freechannel(&card->bch[0]);
+	mISDN_freechannel(&card->dch);
+	spin_unlock_irqrestore(&card->lock, flags);
+	mISDN_ctrl(&card->dch.inst, MGR_UNREGLAYER | REQUEST, NULL);
+	spin_lock_irqsave(&w6692.lock, flags);
+	list_del(&card->list);
+	spin_unlock_irqrestore(&w6692.lock, flags);
+	pci_disable_device(card->pdev);
+	pci_set_drvdata(card->pdev, NULL);
+	kfree(card);
+}
+
+static int
+w6692_manager(void *data, u_int prim, void *arg) {
+	w6692pci	*card;
+	mISDNinstance_t	*inst = data;
+	struct sk_buff	*skb;
+	int		channel = -1;
+	u_long		flags;
+
+	if (debug & 0x10000)
+		printk(KERN_DEBUG "%s: data(%p) prim(%x) arg(%p)\n",
+			__FUNCTION__, data, prim, arg);
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim,arg,&w6692)
+		printk(KERN_ERR "%s: no data prim %x arg %p\n",
+			__FUNCTION__, prim, arg);
+		return(-EINVAL);
+	}
+	spin_lock_irqsave(&w6692.lock, flags);
+	list_for_each_entry(card, &w6692.ilist, list) {
+		if (&card->dch.inst == inst) {
+			channel = 2;
+			break;
+		}
+		if (&card->bch[0].inst == inst) {
+			channel = 0;
+			break;
+		}
+		if (&card->bch[1].inst == inst) {
+			channel = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&w6692.lock, flags);
+	if (channel<0) {
+		printk(KERN_WARNING "%s: no channel data %p prim %x arg %p\n",
+			__FUNCTION__, data, prim, arg);
+		return(-EINVAL);
+	}
+
+	switch(prim) {
+	    case MGR_REGLAYER | CONFIRM:
+		if (channel == 2)
+			mISDN_setpara(&card->dch, &inst->st->para);
+		else
+			mISDN_setpara(&card->bch[channel], &inst->st->para);
+		break;
+	    case MGR_UNREGLAYER | REQUEST:
+		if ((skb = create_link_skb(PH_CONTROL | REQUEST,
+			HW_DEACTIVATE, 0, NULL, 0))) {
+			if (w6692_l2l1(inst, skb))
+				dev_kfree_skb(skb);
+		} else
+			printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+		break;
+	    case MGR_CLRSTPARA | INDICATION:
+		arg = NULL;
+	    case MGR_ADDSTPARA | INDICATION:
+		if (channel == 2)
+			mISDN_setpara(&card->dch, arg);
+		else
+			mISDN_setpara(&card->bch[channel], arg);
+		break;
+	    case MGR_RELEASE | INDICATION:
+		if (channel == 2) {
+			release_card(card);
+		} else {
+			w6692.refcnt--;
+		}
+		break;
+	    case MGR_SETSTACK | INDICATION:
+		if ((channel!=2) && (inst->pid.global == 2)) {
+			if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
+				0, 0, NULL, 0))) {
+				if (w6692_l2l1(inst, skb))
+					dev_kfree_skb(skb);
+			}
+			if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
+					0, 0, NULL, 0);
+			else
+				mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
+					0, 0, NULL, 0);
+		}
+		break;
+	    case MGR_GLOBALOPT | REQUEST:
+		if (arg) {
+			/* FIXME: detect cards with HEADSET */
+			u_int *gopt = arg;
+			*gopt =	GLOBALOPT_INTERNAL_CTRL |
+				GLOBALOPT_EXTERNAL_EQUIPMENT |
+				GLOBALOPT_HANDSET;
+		} else
+			return(-EINVAL);
+		break;
+	    case MGR_SELCHANNEL | REQUEST:
+		/* no special procedure */
+		return(-EINVAL);
+	    PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+	    default:
+		printk(KERN_WARNING "%s: prim %x not handled\n",
+			__FUNCTION__, prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+static int setup_instance(w6692pci *card)
+{
+	int		i, err;
+	mISDN_pid_t	pid;
+	u_long		flags;
+	
+	spin_lock_irqsave(&w6692.lock, flags);
+	list_add_tail(&card->list, &w6692.ilist);
+	spin_unlock_irqrestore(&w6692.lock, flags);
+	card->dch.debug = debug;
+	spin_lock_init(&card->lock);
+	card->dch.inst.hwlock = &card->lock;
+	card->dch.inst.class_dev.dev = &card->pdev->dev;
+	card->dch.inst.pid.layermask = ISDN_LAYER(0);
+	card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
+	mISDN_init_instance(&card->dch.inst, &w6692, card, w6692_l2l1);
+	sprintf(card->dch.inst.name, "W6692_%d", w6692_cnt+1);
+	mISDN_set_dchannel_pid(&pid, protocol[w6692_cnt], layermask[w6692_cnt]);
+	mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
+	card->dch.hw = card;
+	for (i=0; i<2; i++) {
+		card->bch[i].channel = i;
+		mISDN_init_instance(&card->bch[i].inst, &w6692, card, w6692_l2l1);
+		card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
+		card->bch[i].inst.hwlock = &card->lock;
+		card->bch[i].inst.class_dev.dev = &card->pdev->dev;
+		card->bch[i].debug = debug;
+		sprintf(card->bch[i].inst.name, "%s B%d", card->dch.inst.name, i+1);
+		mISDN_initchannel(&card->bch[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM);
+		card->bch[i].hw = &card->wbc[i];
+	}
+	if (debug)
+		printk(KERN_DEBUG "w6692 card %p dch %p bch1 %p bch2 %p\n",
+			card, &card->dch, &card->bch[0], &card->bch[1]);
+	err = setup_w6692(card);
+	if (err) {
+		mISDN_freechannel(&card->dch);
+		mISDN_freechannel(&card->bch[1]);
+		mISDN_freechannel(&card->bch[0]);
+		list_del(&card->list);
+		kfree(card);
+		return(err);
+	}
+	card->pots = pots[w6692_cnt];
+	card->led = led[w6692_cnt];
+	w6692_cnt++;
+	err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &card->dch.inst);
+	if (err) {
+		release_card(card);
+		return(err);
+	}
+	for (i=0; i<2; i++) {
+		err = mISDN_ctrl(card->dch.inst.st, MGR_NEWSTACK | REQUEST, &card->bch[i].inst);
+		if (err) {
+			printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
+			mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+			return(err);
+		}
+	}
+	err = mISDN_ctrl(card->dch.inst.st, MGR_SETSTACK | REQUEST, &pid);
+	if (err) {
+		printk(KERN_ERR  "MGR_SETSTACK REQUEST dch err(%d)\n", err);
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return(err);
+	}
+	err = init_card(card);
+	if (err) {
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+		return(err);
+	}
+	mISDN_ctrl(card->dch.inst.st, MGR_CTRLREADY | INDICATION, NULL);
+	printk(KERN_INFO "w6692 %d cards installed\n", w6692_cnt);
+	return(0);
+}
+
+static int __devinit w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int		err = -ENOMEM;
+	w6692pci	*card;
+	w6692_map_t	*m = (w6692_map_t *)ent->driver_data;	
+
+	if (!(card = kmalloc(sizeof(w6692pci), GFP_ATOMIC))) {
+		printk(KERN_ERR "No kmem for w6692 card\n");
+		return(err);
+	}
+	memset(card, 0, sizeof(w6692pci));
+	card->pdev = pdev;
+	card->subtype = m->subtype;
+	err = pci_enable_device(pdev);
+	if (err) {
+		kfree(card);
+		return(err);
+	}
+
+	printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n",
+	       m->name, pci_name(pdev));
+
+	card->addr = pci_resource_start(pdev, 1);
+	card->irq = pdev->irq;
+	pci_set_drvdata(pdev, card);
+	err = setup_instance(card);
+	return(err);
+}
+
+static void __devexit w6692_remove_pci(struct pci_dev *pdev)
+{
+	w6692pci	*card = pci_get_drvdata(pdev);
+
+	if (card)
+		mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
+	else
+		printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__);
+}
+
+static struct pci_device_id w6692_ids[] = {
+	{ PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, PCI_ANY_ID, PCI_ANY_ID,
+	  0, 0, (unsigned long) &w6692_map[0] },
+	{ PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, PCI_VENDOR_ID_USR2, PCI_DEVICE_ID_USR2_6692,
+	  0, 0, (unsigned long) &w6692_map[2] },
+	{ PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, PCI_ANY_ID, PCI_ANY_ID,
+	  0, 0, (unsigned long) &w6692_map[1] },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, w6692_ids);
+
+static struct pci_driver w6692_driver = {
+	name:     "w6692",
+	probe:    w6692_probe,
+	remove:   __devexit_p(w6692_remove_pci),
+	id_table: w6692_ids,
+};
+
+
+static char W6692Name[] = "W6692";
+
+static int __init w6692_init(void)
+{
+	int	err;
+
+	printk(KERN_INFO "Winbond W6692 PCI driver Rev. %s\n", mISDN_getrev(w6692_rev));
+
+#ifdef MODULE
+	w6692.owner = THIS_MODULE;
+#endif
+	spin_lock_init(&w6692.lock);
+	INIT_LIST_HEAD(&w6692.ilist);
+	w6692.name = W6692Name;
+	w6692.own_ctrl = w6692_manager;
+	w6692.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0;
+	w6692.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS |
+				    ISDN_PID_L1_B_64HDLC;
+	w6692.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS;
+	if ((err = mISDN_register(&w6692))) {
+		printk(KERN_ERR "Can't register Winbond W6692 PCI error(%d)\n", err);
+		return(err);
+	}
+	err = pci_register_driver(&w6692_driver);
+	if (err < 0)
+		goto out;
+
+#ifdef OLD_PCI_REGISTER_DRIVER
+	if (err == 0) {
+		err = -ENODEV;
+		pci_unregister_driver(&w6692_driver);
+		goto out;
+	}
+#endif
+
+	mISDN_module_register(THIS_MODULE);
+
+	return 0;
+
+ out:
+ 	mISDN_unregister(&w6692);
+ 	return err;
+}
+
+static void __exit w6692_cleanup(void)
+{
+	int		err;
+	w6692pci	*card, *next;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if ((err = mISDN_unregister(&w6692))) {
+		printk(KERN_ERR "Can't unregister Winbond W6692 PCI error(%d)\n", err);
+	}
+	list_for_each_entry_safe(card, next, &w6692.ilist, list) {
+		printk(KERN_ERR "Winbond W6692 PCI card struct not empty refs %d\n",
+			w6692.refcnt);
+		release_card(card);
+	}
+	pci_unregister_driver(&w6692_driver);
+}
+
+module_init(w6692_init);
+module_exit(w6692_cleanup);


Property changes on: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/w6692.c
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/w6692.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/w6692.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/w6692.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,179 @@
+/* $Id: w6692.h,v 1.1 2003/11/09 09:33:22 keil Exp $
+ *
+ * Winbond W6692 specific defines
+ *
+ * Author      Karsten Keil <kkeil at suse.de>
+ *             based on the w6692 I4L driver from Petr Novak <petr.novak at i.cz>
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+/* Specifications of W6692 registers */
+
+#define W_D_RFIFO	0x00	/* R */
+#define W_D_XFIFO	0x04	/* W */
+#define W_D_CMDR	0x08	/* W */
+#define W_D_MODE	0x0c	/* R/W */
+#define W_D_TIMR	0x10	/* R/W */
+#define W_ISTA		0x14	/* R_clr */
+#define W_IMASK		0x18	/* R/W */
+#define W_D_EXIR	0x1c	/* R_clr */
+#define W_D_EXIM	0x20	/* R/W */
+#define W_D_STAR	0x24	/* R */
+#define W_D_RSTA	0x28	/* R */
+#define W_D_SAM		0x2c	/* R/W */
+#define W_D_SAP1	0x30	/* R/W */
+#define W_D_SAP2	0x34	/* R/W */
+#define W_D_TAM		0x38	/* R/W */
+#define W_D_TEI1	0x3c	/* R/W */
+#define W_D_TEI2	0x40	/* R/W */
+#define W_D_RBCH	0x44	/* R */
+#define W_D_RBCL	0x48	/* R */
+#define W_TIMR2		0x4c	/* W */
+#define W_L1_RC		0x50	/* R/W */
+#define W_D_CTL		0x54	/* R/W */
+#define W_CIR		0x58	/* R */
+#define W_CIX		0x5c	/* W */
+#define W_SQR		0x60	/* R */
+#define W_SQX		0x64	/* W */
+#define W_PCTL		0x68	/* R/W */
+#define W_MOR		0x6c	/* R */
+#define W_MOX		0x70	/* R/W */
+#define W_MOSR		0x74	/* R_clr */
+#define W_MOCR		0x78	/* R/W */
+#define W_GCR		0x7c	/* R/W */
+
+#define	W_B_RFIFO	0x80	/* R */
+#define	W_B_XFIFO	0x84	/* W */
+#define	W_B_CMDR	0x88	/* W */
+#define	W_B_MODE	0x8c	/* R/W */
+#define	W_B_EXIR	0x90	/* R_clr */
+#define	W_B_EXIM	0x94	/* R/W */
+#define	W_B_STAR	0x98	/* R */
+#define	W_B_ADM1	0x9c	/* R/W */
+#define	W_B_ADM2	0xa0	/* R/W */
+#define	W_B_ADR1	0xa4	/* R/W */
+#define	W_B_ADR2	0xa8	/* R/W */
+#define	W_B_RBCL	0xac	/* R */
+#define	W_B_RBCH	0xb0	/* R */
+
+#define W_XADDR		0xf4	/* R/W */
+#define W_XDATA		0xf8	/* R/W */
+#define W_EPCTL		0xfc	/* W */
+
+/* W6692 register bits */
+
+#define	W_D_CMDR_XRST	0x01
+#define	W_D_CMDR_XME	0x02
+#define	W_D_CMDR_XMS	0x08
+#define	W_D_CMDR_STT	0x10
+#define	W_D_CMDR_RRST	0x40
+#define	W_D_CMDR_RACK	0x80
+
+#define	W_D_MODE_RLP	0x01
+#define	W_D_MODE_DLP	0x02
+#define	W_D_MODE_MFD	0x04
+#define	W_D_MODE_TEE	0x08
+#define	W_D_MODE_TMS	0x10
+#define	W_D_MODE_RACT	0x40
+#define	W_D_MODE_MMS	0x80
+
+#define W_INT_B2_EXI	0x01
+#define W_INT_B1_EXI	0x02
+#define W_INT_D_EXI	0x04
+#define W_INT_XINT0	0x08
+#define W_INT_XINT1	0x10
+#define W_INT_D_XFR	0x20
+#define W_INT_D_RME	0x40
+#define W_INT_D_RMR	0x80
+
+#define W_D_EXI_WEXP	0x01
+#define W_D_EXI_TEXP	0x02
+#define W_D_EXI_ISC	0x04
+#define W_D_EXI_MOC	0x08
+#define W_D_EXI_TIN2	0x10
+#define W_D_EXI_XCOL	0x20
+#define W_D_EXI_XDUN	0x40
+#define W_D_EXI_RDOV	0x80
+
+#define	W_D_STAR_DRDY	0x10
+#define	W_D_STAR_XBZ	0x20
+#define	W_D_STAR_XDOW	0x80
+
+#define W_D_RSTA_RMB	0x10
+#define W_D_RSTA_CRCE	0x20
+#define W_D_RSTA_RDOV	0x40
+
+#define W_D_CTL_SRST	0x20
+
+#define W_CIR_SCC	0x80
+#define W_CIR_ICC	0x40
+#define W_CIR_COD_MASK	0x0f
+
+#define W_PCTL_PCX	0x01
+#define W_PCTL_XMODE	0x02
+#define W_PCTL_OE0	0x04
+#define W_PCTL_OE1	0x08
+#define W_PCTL_OE2	0x10
+#define W_PCTL_OE3	0x20
+#define W_PCTL_OE4	0x40
+#define W_PCTL_OE5	0x80
+
+#define	W_B_CMDR_XRST	0x01
+#define	W_B_CMDR_XME	0x02
+#define	W_B_CMDR_XMS	0x04
+#define	W_B_CMDR_RACT	0x20
+#define	W_B_CMDR_RRST	0x40
+#define	W_B_CMDR_RACK	0x80
+
+#define	W_B_MODE_FTS0	0x01
+#define	W_B_MODE_FTS1	0x02
+#define	W_B_MODE_SW56	0x04
+#define	W_B_MODE_BSW0	0x08
+#define	W_B_MODE_BSW1	0x10
+#define	W_B_MODE_EPCM	0x20
+#define	W_B_MODE_ITF	0x40
+#define	W_B_MODE_MMS	0x80
+
+#define	W_B_EXI_XDUN	0x01
+#define	W_B_EXI_XFR	0x02
+#define	W_B_EXI_RDOV	0x10
+#define	W_B_EXI_RME	0x20
+#define	W_B_EXI_RMR	0x40
+
+#define	W_B_STAR_XBZ	0x01
+#define	W_B_STAR_XDOW	0x04
+#define	W_B_STAR_RMB	0x10
+#define	W_B_STAR_CRCE	0x20
+#define	W_B_STAR_RDOV	0x40
+
+#define	W_B_RBCH_LOV	0x20
+
+/* W6692 Layer1 commands */
+
+#define	W_L1CMD_ECK	0x00
+#define W_L1CMD_RST	0x01
+#define W_L1CMD_SCP	0x04
+#define W_L1CMD_SSP	0x02
+#define W_L1CMD_AR8	0x08
+#define W_L1CMD_AR10	0x09
+#define W_L1CMD_EAL	0x0a
+#define W_L1CMD_DRC	0x0f
+
+/* W6692 Layer1 indications */
+
+#define W_L1IND_CE	0x07
+#define W_L1IND_DRD	0x00
+#define W_L1IND_LD	0x04
+#define W_L1IND_ARD	0x08
+#define W_L1IND_TI	0x0a
+#define W_L1IND_ATI	0x0b
+#define W_L1IND_AI8	0x0c
+#define W_L1IND_AI10	0x0d
+#define W_L1IND_CD	0x0f
+
+/* FIFO thresholds */
+#define W_D_FIFO_THRESH	64
+#define W_B_FIFO_THRESH	64

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_dte.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_dte.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_dte.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1400 @@
+/* $Id: x25_dte.c,v 1.13 2007/02/13 10:43:45 crich Exp $
+ *
+ * Linux modular ISDN subsystem, mISDN
+ * X.25/X.31 Layer3 for DTE mode
+ *
+ * Author	Karsten Keil (kkeil at suse.de)
+ *
+ * Copyright 2003 by Karsten Keil (kkeil at suse.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include <linux/module.h>
+#include "core.h"
+#include "x25_l3.h"
+#include "helper.h"
+#include "debug.h"
+
+static int debug = 0;
+
+static mISDNobject_t x25dte_obj;
+
+static char *mISDN_dte_revision = "$Revision: 1.13 $";
+
+/* local prototypes */
+static x25_channel_t *	dte_create_channel(x25_l3_t *, int, u_char, __u16, int, u_char *);
+
+
+/* X.25 Restart state machine */
+static struct Fsm dte_rfsm = {NULL, 0, 0, NULL, NULL};
+
+/* X.25 connection state machine */
+static struct Fsm dte_pfsm = {NULL, 0, 0, NULL, NULL};
+
+/* X.25 Flowcontrol state machine */
+static struct Fsm dte_dfsm = {NULL, 0, 0, NULL, NULL};
+
+
+/* X.25 Restart state machine implementation */
+
+static void
+r_llready(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t *l3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_R1);
+	if (test_and_clear_bit(X25_STATE_ESTABLISH, &l3->state)) {
+		mISDN_FsmEvent(&l3->x25r, EV_L3_RESTART_REQ, NULL);
+	}
+}
+
+static void
+r_r0_restart_l3(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t	*l3 = fi->userdata;
+
+	if (arg)
+		memcpy(l3->cause, arg, 2);
+	else
+		memset(l3->cause, 0, 2);
+	test_and_set_bit(X25_STATE_ESTABLISH, &l3->state);
+	mISDN_FsmEvent(&l3->l2l3m, EV_L3_ESTABLISH_REQ, NULL);
+}
+
+static void
+r_restart_l3(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t	*l3 = fi->userdata;
+
+	if (arg)
+		memcpy(l3->cause, arg, 2);
+	mISDN_FsmChangeState(fi, ST_R2);
+	l3->TRval = T20_VALUE;
+	l3->TRrep = R20_VALUE;
+	X25sendL3frame(NULL, l3, X25_PTYPE_RESTART, 2, l3->cause);
+	mISDN_FsmAddTimer(&l3->TR, l3->TRval, EV_L3_RESTART_TOUT, NULL, 0);
+}
+
+static void
+r_restart_ind(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t	*l3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_R3);
+	X25sendL3frame(NULL, l3, X25_PTYPE_RESTART_CNF, 0, NULL);
+	mISDN_FsmChangeState(fi, ST_R1);
+	mISDN_FsmDelTimer(&l3->TR, 0);
+	X25_restart(l3);
+}
+
+static void
+r_restart_cnf(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t	*l3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_R1);
+	mISDN_FsmDelTimer(&l3->TR, 0);
+	X25_restart(l3);
+}
+
+static void
+r_restart_cnf_err(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t	*l3 = fi->userdata;
+	u_char		cause[2] = {0, 17};
+
+	if (fi->state == ST_R3)
+		cause[1] = 19;
+	mISDN_FsmEvent(&l3->x25r, EV_L3_RESTART_REQ, cause);
+}
+
+static void
+r_timeout(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t	*l3 = fi->userdata;
+
+	if (l3->TRrep) {
+		X25sendL3frame(NULL, l3, X25_PTYPE_RESTART, 2, l3->cause);
+		mISDN_FsmRestartTimer(&l3->TR, l3->TRval, EV_L3_RESTART_TOUT, NULL, 0);
+		l3->TRrep--;
+	} else {
+		mISDN_FsmDelTimer(&l3->TR, 0);
+		mISDN_FsmChangeState(fi, ST_R1);
+		/* signal failure */
+	}
+}
+
+/* *INDENT-OFF* */
+static struct FsmNode RFnList[] =
+{
+	{ST_R0,	EV_LL_READY,		r_llready},
+	{ST_R0,	EV_L3_RESTART_REQ,	r_r0_restart_l3},
+	{ST_R1,	EV_LL_READY,		r_llready},
+	{ST_R1,	EV_L3_RESTART_REQ,	r_restart_l3},
+	{ST_R1,	EV_L2_RESTART,		r_restart_ind},
+	{ST_R1,	EV_L2_RESTART_CNF,	r_restart_cnf_err},
+	{ST_R2,	EV_L3_RESTART_REQ,	r_restart_l3},
+	{ST_R2,	EV_L2_RESTART,		r_restart_cnf},
+	{ST_R2,	EV_L2_RESTART_CNF,	r_restart_cnf},
+	{ST_R2,	EV_L3_RESTART_TOUT,	r_timeout},
+	{ST_R2,	EV_LL_READY,		r_llready},
+	{ST_R3,	EV_L3_RESTART_REQ,	r_restart_l3},
+	{ST_R3,	EV_L2_RESTART_CNF,	r_restart_cnf_err},
+	{ST_R3,	EV_LL_READY,		r_llready},
+};
+/* *INDENT-ON* */
+
+#define R_FN_COUNT (sizeof(RFnList)/sizeof(struct FsmNode))
+
+/* X.25 connection state machine */
+
+static void
+p_p0_ready(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+
+	if (test_bit(X25_STATE_PERMANENT, &l3c->state)) {
+		mISDN_FsmChangeState(fi, ST_P4);
+		/* connect */
+		mISDN_FsmEvent(&l3c->x25d, EV_L3_CONNECT, NULL);
+	} else {
+		mISDN_FsmChangeState(fi, ST_P1);
+		if (test_bit(X25_STATE_ORGINATE, &l3c->state))
+			mISDN_FsmEvent(fi, EV_L3_OUTGOING_CALL, NULL);
+	}
+}
+
+static void
+X25_clear_connection(x25_channel_t *l3c, struct sk_buff *skb, int reason)
+{
+	if (skb) {
+		if (test_bit(X25_STATE_DBIT, &l3c->state))
+			reason |= 0x10000;
+		X25sendL4frame(l3c, l3c->l3, CAPI_DISCONNECT_B3_IND, reason, skb->len, skb->data);
+	} else
+		X25sendL4frame(l3c, l3c->l3, CAPI_DISCONNECT_B3_IND, reason, 0, NULL);
+}
+
+static void
+p_p0_outgoing(struct FsmInst *fi, int event, void *arg)
+{
+}
+
+static void
+p_ready(struct FsmInst *fi, int event, void *arg)
+{
+//	x25_channel_t	*l3c = fi->userdata;
+}
+
+static void
+p_outgoing(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	mISDN_FsmChangeState(fi, ST_P2);
+	if (skb)
+		X25sendL3frame(l3c, l3c->l3, X25_PTYPE_CALL, skb->len, skb->data);
+	else
+		X25sendL3frame(l3c, l3c->l3, X25_PTYPE_CALL, l3c->ncpi_len, l3c->ncpi_data);
+	mISDN_FsmAddTimer(&l3c->TP, T21_VALUE, EV_L3_CALL_TOUT, NULL, 0);
+}
+
+static void
+p_incoming(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+	int		flg = 0;
+
+	if (test_bit(X25_STATE_DBIT, &l3c->state))
+		flg = 0x10000;
+	mISDN_FsmChangeState(fi, ST_P3);
+	X25sendL4frame(l3c, l3c->l3, CAPI_CONNECT_B3_IND, flg, l3c->ncpi_len, l3c->ncpi_data);
+}
+
+static void
+p_call_accept(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	if (skb)
+		X25sendL3frame(l3c, l3c->l3, X25_PTYPE_CALL_CNF, skb->len, skb->data);
+	else
+		X25sendL3frame(l3c, l3c->l3, X25_PTYPE_CALL_CNF, 0, NULL);
+	mISDN_FsmChangeState(fi, ST_P4);
+	mISDN_FsmEvent(&l3c->x25d, EV_L3_CONNECT, NULL);
+	X25sendL4frame(l3c, l3c->l3, CAPI_CONNECT_B3_ACTIVE_IND, 0, 0, NULL);
+}
+
+static void
+p_collision(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_P5);
+}
+
+static void
+p_connect(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+	struct sk_buff	*skb = arg;
+	int		flg = 0;
+
+	mISDN_FsmDelTimer(&l3c->TP, 0);
+	mISDN_FsmChangeState(fi, ST_P4);
+	if (test_bit(X25_STATE_DBIT, &l3c->state))
+		flg = 0x10000;
+	mISDN_FsmEvent(&l3c->x25d, EV_L3_CONNECT, NULL);
+	if (skb)
+		X25sendL4frame(l3c, l3c->l3, CAPI_CONNECT_B3_ACTIVE_IND, flg, skb->len, skb->data);
+	else
+		X25sendL4frame(l3c, l3c->l3, CAPI_CONNECT_B3_ACTIVE_IND, flg, 0, NULL);
+}
+
+static void
+p_call_timeout(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_P6);
+	l3c->cause[0] = 0;
+	l3c->cause[1] = 49;
+	l3c->TPval = T23_VALUE;
+	l3c->TPrep = R23_VALUE;
+	mISDN_FsmAddTimer(&l3c->TP, l3c->TPval, EV_L3_CLEAR_TOUT, NULL, 0);
+	X25sendL3frame(l3c, l3c->l3, X25_PTYPE_CLEAR, 2, l3c->cause);
+}
+
+static void
+p_clear_ind(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_P7);
+	mISDN_FsmDelTimer(&l3c->TP, 0);
+	X25sendL3frame(l3c, l3c->l3, X25_PTYPE_CLEAR_CNF, 0, NULL);
+	mISDN_FsmChangeState(fi, ST_P1);
+	X25_clear_connection(l3c, arg, 0);
+}
+
+static void
+p_clear_cnf(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_P1);
+	mISDN_FsmDelTimer(&l3c->TP, 0);
+	X25_clear_connection(l3c, arg, 0);
+}
+
+static void
+p_clear_timeout(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+
+	if (l3c->TPrep) {
+		mISDN_FsmAddTimer(&l3c->TP, l3c->TPval, EV_L3_CLEAR_TOUT, NULL, 0);
+		X25sendL3frame(l3c, l3c->l3, X25_PTYPE_CLEAR, 2, l3c->cause);
+	} else {
+		l3c->cause[0] = 0;
+		l3c->cause[0] = 50;
+		mISDN_FsmChangeState(fi, ST_P1);
+		X25_clear_connection(l3c, NULL, 0x3303);
+	}
+}
+
+static void
+p_clearing_req(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	mISDN_FsmChangeState(fi, ST_P6);
+	l3c->TPval = T23_VALUE;
+	l3c->TPrep = R23_VALUE;
+	mISDN_FsmAddTimer(&l3c->TP, l3c->TPval, EV_L3_CLEAR_TOUT, NULL, 0);
+	if (skb) {
+		if (skb->len >= 2) {
+			memcpy(l3c->cause, skb->data, 2);
+			X25sendL3frame(l3c, l3c->l3, X25_PTYPE_CLEAR, skb->len, skb->data);
+			return;
+		}
+		l3c->cause[0] = 0;
+		l3c->cause[1] = 0;
+	}
+	X25sendL3frame(l3c, l3c->l3, X25_PTYPE_CLEAR, 2, l3c->cause);
+}
+
+static void
+p_invalid_pkt(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+
+	l3c->cause[0] = 0;
+	switch(fi->state) {
+		case ST_P1:
+			l3c->cause[1] = 20;
+			break;
+		case ST_P2:
+			l3c->cause[1] = 21;
+			break;
+		case ST_P3:
+			l3c->cause[1] = 22;
+			break;
+		case ST_P4:
+			l3c->cause[1] = 23;
+			break;
+		case ST_P5:
+			l3c->cause[1] = 24;
+			break;
+		case ST_P6:
+			l3c->cause[1] = 25;
+			break;
+		case ST_P7:
+			l3c->cause[1] = 26;
+			break;
+		default:
+			l3c->cause[1] = 16;
+			break;
+	}
+	X25sendL3frame(l3c, l3c->l3, X25_PTYPE_CLEAR, 2, l3c->cause);
+}
+
+/* *INDENT-OFF* */
+static struct FsmNode PFnList[] =
+{
+	{ST_P0,	EV_L3_READY,		p_p0_ready},
+	{ST_P0,	EV_L3_OUTGOING_CALL,	p_p0_outgoing},
+	{ST_P0, EV_L3_CLEARING,		p_clearing_req},
+	{ST_P1,	EV_L3_READY,		p_ready},
+	{ST_P1,	EV_L3_OUTGOING_CALL,	p_outgoing},
+	{ST_P1,	EV_L2_INCOMING_CALL,	p_incoming},
+	{ST_P1,	EV_L2_CLEAR,		p_clear_ind},
+	{ST_P1,	EV_L2_CALL_CNF,		p_invalid_pkt},
+	{ST_P1,	EV_L2_CLEAR_CNF,	p_invalid_pkt},
+	{ST_P1,	EV_L2_INVALPKT,		p_invalid_pkt},
+	{ST_P1, EV_L3_CLEARING,		p_clearing_req},
+	{ST_P2,	EV_L2_INCOMING_CALL,	p_collision},
+	{ST_P2,	EV_L2_CALL_CNF,		p_connect},
+	{ST_P2,	EV_L2_CLEAR,		p_clear_ind},
+	{ST_P2,	EV_L3_CALL_TOUT,	p_call_timeout},
+	{ST_P2,	EV_L2_CLEAR_CNF,	p_invalid_pkt},
+	{ST_P2,	EV_L2_INVALPKT,		p_invalid_pkt},
+	{ST_P2, EV_L3_CLEARING,		p_clearing_req},
+	{ST_P3, EV_L3_CALL_ACCEPT,	p_call_accept},
+ 	{ST_P3,	EV_L2_CLEAR,		p_clear_ind},
+	{ST_P3,	EV_L2_INCOMING_CALL,	p_invalid_pkt},
+	{ST_P3,	EV_L2_CALL_CNF,		p_invalid_pkt},
+	{ST_P3,	EV_L2_CLEAR_CNF,	p_invalid_pkt},
+	{ST_P3,	EV_L2_INVALPKT,		p_invalid_pkt},
+	{ST_P3, EV_L3_CLEARING,		p_clearing_req},
+	{ST_P4,	EV_L2_CLEAR,		p_clear_ind},
+	{ST_P4,	EV_L2_INCOMING_CALL,	p_invalid_pkt},
+	{ST_P4,	EV_L2_CALL_CNF,		p_invalid_pkt},
+	{ST_P4,	EV_L2_CLEAR_CNF,	p_invalid_pkt},
+	{ST_P4, EV_L3_CLEARING,		p_clearing_req},
+	{ST_P5,	EV_L2_CALL_CNF,		p_connect},
+	{ST_P5, EV_L3_CALL_ACCEPT,	p_call_accept},
+	{ST_P5,	EV_L2_CLEAR,		p_clear_ind},
+	{ST_P5,	EV_L3_CALL_TOUT,	p_call_timeout},
+	{ST_P5,	EV_L2_INCOMING_CALL,	p_invalid_pkt},
+	{ST_P5,	EV_L2_CLEAR_CNF,	p_invalid_pkt},
+	{ST_P5,	EV_L2_INVALPKT,		p_invalid_pkt},
+	{ST_P5, EV_L3_CLEARING,		p_clearing_req},
+	{ST_P6,	EV_L2_CLEAR_CNF,	p_clear_cnf},
+	{ST_P6,	EV_L3_CLEAR_TOUT,	p_clear_timeout},
+	{ST_P6, EV_L3_CLEARING,		p_clearing_req},
+	{ST_P7,	EV_L2_INCOMING_CALL,	p_invalid_pkt},
+	{ST_P7,	EV_L2_CALL_CNF,		p_invalid_pkt},
+	{ST_P7,	EV_L2_CLEAR_CNF,	p_invalid_pkt},
+	{ST_P7,	EV_L2_INVALPKT,		p_invalid_pkt},
+};
+/* *INDENT-ON* */
+
+#define P_FN_COUNT (sizeof(PFnList)/sizeof(struct FsmNode))
+
+static void
+d_connect(struct FsmInst *fi, int event, void *arg)
+{
+	mISDN_FsmChangeState(fi, ST_D1);
+}
+
+static void
+d_reset_req(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+	struct sk_buff	*skb = arg;
+
+	mISDN_FsmChangeState(fi, ST_D2);
+	l3c->TDval = T22_VALUE;
+	l3c->TDrep = R22_VALUE;
+	mISDN_FsmAddTimer(&l3c->TD, l3c->TDval, EV_L3_RESET_TOUT, NULL, 0);
+	if (skb) {
+		if (skb->len >= 2) {
+			memcpy(l3c->cause, skb->data, 2);
+			X25sendL3frame(l3c, l3c->l3, X25_PTYPE_RESET, skb->len, skb->data);
+			return;
+		}
+		l3c->cause[0] = 0;
+		l3c->cause[1] = 0;
+	}
+	X25sendL3frame(l3c, l3c->l3, X25_PTYPE_RESET, 2, l3c->cause);
+}
+
+static void
+d_reset_ind(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_D3);
+	X25_reset_channel(l3c, arg);
+	mISDN_FsmChangeState(fi, ST_D1);
+	/* TODO normal operation trigger */
+}
+
+static void
+d_reset_cnf(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+
+	mISDN_FsmDelTimer(&l3c->TD, 0);
+	X25_reset_channel(l3c, NULL);
+	/* TODO normal opration trigger */
+	mISDN_FsmChangeState(fi, ST_D1);
+}
+
+static void
+d_reset_cnf_err(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+
+	if (arg)
+		memcpy(l3c->cause, arg, 2);
+	mISDN_FsmChangeState(fi, ST_D2);
+	l3c->TDval = T22_VALUE;
+	l3c->TDrep = R22_VALUE;
+	X25sendL3frame(l3c, l3c->l3, X25_PTYPE_RESET, 2, l3c->cause);
+	mISDN_FsmAddTimer(&l3c->TD, l3c->TDval, EV_L3_RESET_TOUT, NULL, 0);
+}
+
+static void
+d_reset_timeout(struct FsmInst *fi, int event, void *arg)
+{
+	x25_channel_t	*l3c = fi->userdata;
+
+	if (l3c->TDrep) {
+		X25sendL3frame(l3c, l3c->l3, X25_PTYPE_RESET, 2, l3c->cause);
+		l3c->TDrep--;
+	} else {
+		l3c->cause[0] = 0;
+		l3c->cause[1] = 51;
+		mISDN_FsmChangeState(fi, ST_D0);
+		if (test_bit(X25_STATE_PERMANENT, &l3c->state))
+			X25_clear_connection(l3c, NULL, 0x3303);
+		else
+			mISDN_FsmEvent(&l3c->x25p, EV_L3_CLEARING, NULL);
+	}
+}
+
+/* *INDENT-OFF* */
+static struct FsmNode DFnList[] =
+{
+	{ST_D0,	EV_L3_CONNECT,		d_connect},
+	{ST_D1,	EV_L2_RESET,		d_reset_ind},
+	{ST_D1,	EV_L2_RESET_CNF,        d_reset_cnf_err},
+	{ST_D1,	EV_L3_RESETING,		d_reset_req},
+	{ST_D2,	EV_L2_RESET,		d_reset_cnf},
+	{ST_D2,	EV_L2_RESET_CNF,        d_reset_cnf},
+	{ST_D3,	EV_L2_RESET_CNF,        d_reset_cnf_err},
+	{ST_D3,	EV_L3_RESETING,		d_reset_req},
+	{ST_D1, EV_L3_RESET_TOUT,	d_reset_timeout},
+};
+/* *INDENT-ON* */
+
+#define D_FN_COUNT (sizeof(DFnList)/sizeof(struct FsmNode))
+
+static int
+got_diagnositic(x25_l3_t *l3, struct sk_buff *skb, u_char gfi, __u16 channel)
+{
+	/* not implemented yet */
+	return(X25_ERRCODE_DISCARD);
+}
+
+static int
+got_register(x25_l3_t *l3, struct sk_buff *skb, u_char gfi, __u16 channel)
+{
+	/* not implemented yet */
+	return(X25_ERRCODE_DISCARD);
+}
+
+static int
+got_register_cnf(x25_l3_t *l3, struct sk_buff *skb, u_char gfi, __u16 channel)
+{
+	/* not implemented yet */
+	return(X25_ERRCODE_DISCARD);
+}
+
+static int
+dte_data_ind_d(x25_channel_t *chan, struct sk_buff *skb, u_char gfi, u_char ptype)
+{
+	int	pr_m, ps, event;
+	u_char  ptype_s = ptype;
+
+	if ((ptype & 1) == 0)
+		ptype = X25_PTYPE_DATA;
+	else {
+		if ((!test_bit(X25_STATE_MOD128, &chan->state)) &&
+			!test_bit(X25_STATE_MOD32768, &chan->state))
+			ptype = ptype & 0x1f;
+		if ((ptype != X25_PTYPE_RR) &&
+			(ptype != X25_PTYPE_RNR) &&
+			(ptype != X25_PTYPE_REJ))
+			ptype = ptype_s;
+	}
+	switch (ptype) {
+		case X25_PTYPE_RESET:
+			event = EV_L2_RESET;
+			break;
+		case X25_PTYPE_RESET_CNF:
+			event = EV_L2_RESET_CNF;
+			break;
+		case X25_PTYPE_NOTYPE:
+			chan->cause[0] = 0;
+			chan->cause[1] = 38;
+			event = EV_L3_RESETING;
+			break;
+		case X25_PTYPE_RESTART:
+		case X25_PTYPE_RESTART_CNF:
+			chan->cause[0] = 0;
+			chan->cause[1] = 41;
+			event = EV_L3_RESETING;
+			break;
+		case X25_PTYPE_INTERRUPT:
+		case X25_PTYPE_INTERRUPT_CNF:
+		case X25_PTYPE_DATA:
+		case X25_PTYPE_RR:
+		case X25_PTYPE_RNR:
+		case X25_PTYPE_REJ:
+			if (chan->x25d.state == ST_D2)
+				return(X25_ERRCODE_DISCARD);
+			else if (chan->x25d.state == ST_D3) {
+				chan->cause[0] = 0;
+				chan->cause[1] = 29;
+				event = EV_L3_RESETING;
+			} else
+				event = -1;
+			break;
+		default:
+			/* unknown paket type */
+			chan->cause[0] = 0;
+			chan->cause[1] = 33;
+			event = EV_L3_RESETING;
+			break;
+	}
+	if (event != -1) {
+		if (event == EV_L3_RESETING)
+			mISDN_FsmEvent(&chan->x25d, event, NULL);
+		else
+			mISDN_FsmEvent(&chan->x25d, event, skb);
+		return(X25_ERRCODE_DISCARD);
+	}
+	switch (ptype) {
+		case X25_PTYPE_INTERRUPT:
+			if (test_and_set_bit(X25_STATE_DXE_INTSENT, &chan->state)) {
+				chan->cause[0] = 0;
+				chan->cause[1] = 44;
+				mISDN_FsmEvent(&chan->x25d, EV_L3_RESETING, NULL);
+			} else {
+				// X25_got_interrupt(chan, skb);
+			}
+			break;
+		case X25_PTYPE_INTERRUPT_CNF:
+			if (!test_and_clear_bit(X25_STATE_DTE_INTSENT, &chan->state)) {
+				chan->cause[0] = 0;
+				chan->cause[1] = 43;
+				mISDN_FsmEvent(&chan->x25d, EV_L3_RESETING, NULL);
+			}
+			break;
+		case X25_PTYPE_RR:
+		case X25_PTYPE_RNR:
+		case X25_PTYPE_REJ:
+			pr_m = X25_get_and_test_pr(chan, ptype_s, skb);
+			if (pr_m < 0) {
+				chan->cause[0] = 0;
+				chan->cause[1] = -pr_m;
+				mISDN_FsmEvent(&chan->x25d, EV_L3_RESETING, NULL);
+			} else if (skb->len) {
+				chan->cause[0] = 0;
+				chan->cause[1] = 39;
+				mISDN_FsmEvent(&chan->x25d, EV_L3_RESETING, NULL);
+			} else {
+				if (ptype == X25_PTYPE_RR) {
+					test_and_clear_bit(X25_STATE_DXE_RNR, &chan->state);
+					if (X25_cansend(chan))
+						X25_invoke_sending(chan);
+				} else if (ptype == X25_PTYPE_RNR) {
+					if (!test_and_set_bit(X25_STATE_DXE_RNR, &chan->state)) {
+						/* action for DXE RNR */
+					}
+				} else {
+					/* TODO REJ */
+				}
+			}
+			break;
+		case X25_PTYPE_DATA:
+			ps = X25_get_and_test_ps(chan, ptype_s, skb);
+			if (ps == -38)
+				pr_m = ps;
+			else
+				pr_m = X25_get_and_test_pr(chan, ptype_s, skb);
+			if (pr_m < 0) {
+				chan->cause[0] = 0;
+				chan->cause[1] = -pr_m;
+				mISDN_FsmEvent(&chan->x25d, EV_L3_RESETING, NULL);
+			} else if (ps < 0) {
+				chan->cause[0] = 0;
+				chan->cause[1] = -ps;
+				mISDN_FsmEvent(&chan->x25d, EV_L3_RESETING, NULL);
+			} else {
+				int flag = (pr_m & 1) ? CAPI_FLAG_MOREDATA : 0;
+
+				if (gfi & X25_GFI_QBIT)
+					flag |= CAPI_FLAG_QUALIFIER;
+				if (gfi & X25_GFI_DBIT)
+					flag |= CAPI_FLAG_DELIVERCONF;
+				return(X25_receive_data(chan, ps, flag, skb));
+			}
+			break;
+	}
+	return(X25_ERRCODE_DISCARD);
+}
+
+static int
+dte_data_ind_p(x25_l3_t *l3, struct sk_buff *skb, u_char gfi, __u16 channel, u_char ptype)
+{
+	x25_channel_t	*chan = X25_get_channel(l3, channel);
+	int		event, ret = X25_ERRCODE_DISCARD;
+
+	if (ptype == X25_PTYPE_CALL) {
+		if (!chan)
+			chan = dte_create_channel(l3, X25_CHANNEL_INCOMING, gfi, channel, skb->len, skb->data);
+		if (chan) {
+			mISDN_FsmEvent(&chan->x25p, EV_L2_INCOMING_CALL, skb);
+		} else {
+			ret = 36; /* unassigned channel */
+		}
+		return(ret);
+	}
+	if (!chan)
+		return(36); /* unassigned channel */
+	switch (ptype) {
+		case X25_PTYPE_CALL_CNF:
+			event = EV_L2_CALL_CNF;
+			break;
+		case X25_PTYPE_CLEAR:
+			event = EV_L2_CLEAR;
+			break;
+		case X25_PTYPE_CLEAR_CNF:
+			event = EV_L2_CLEAR_CNF;
+			break;
+		case X25_PTYPE_NOTYPE:
+			chan->cause[0] = 0;
+			chan->cause[1] = 38;
+			event = EV_L3_CLEARING;
+			break;
+		case X25_PTYPE_RESTART:
+		case X25_PTYPE_RESTART_CNF:
+			chan->cause[0] = 0;
+			chan->cause[1] = 41;
+			event = EV_L3_CLEARING;
+			break;
+		case X25_PTYPE_RESET:
+		case X25_PTYPE_RESET_CNF:
+		case X25_PTYPE_INTERRUPT:
+		case X25_PTYPE_INTERRUPT_CNF:
+			event = EV_L2_INVALPKT;
+			break;
+		default:
+			if ((ptype & 1) == 0) {
+				event = EV_L2_INVALPKT;
+				break;
+			}
+			if (!test_bit(X25_STATE_MOD128, &chan->state) &&
+				!test_bit(X25_STATE_MOD32768, &chan->state))
+				event = ptype & 0x1f;
+			else
+				event = ptype;
+			if ((event == X25_PTYPE_RR) ||
+				(event == X25_PTYPE_RNR) ||
+				(event == X25_PTYPE_REJ)) {
+				event = EV_L2_INVALPKT;
+				break;
+			}
+			/* unknown paket type */
+			chan->cause[0] = 0;
+			chan->cause[1] = 33;
+			event = EV_L3_CLEARING;
+			break;
+	}
+	if (chan->x25p.state == ST_P4) {
+		if ((event == EV_L2_INVALPKT) || (event == EV_L3_CLEARING))
+			return(dte_data_ind_d(chan, skb, gfi, ptype));
+	}
+	if (event == EV_L3_CLEARING)
+		mISDN_FsmEvent(&chan->x25p, event, NULL);
+	else
+		mISDN_FsmEvent(&chan->x25p, event, skb);
+	return(ret);
+}
+
+static int
+dte_data_ind_r(x25_l3_t *l3, struct sk_buff *skb, u_char gfi, __u16 channel, u_char ptype)
+{
+	int	ret = X25_ERRCODE_DISCARD;
+
+
+	if (ptype == X25_PTYPE_NOTYPE) {
+		if (channel) {
+			if (l3->x25r.state == ST_R1)
+				return(dte_data_ind_p(l3, skb, gfi, channel, ptype));
+			if (l3->x25r.state == ST_R2) {
+				l3->cause[0] = 0;
+				l3->cause[1] = 38;
+				mISDN_FsmEvent(&l3->x25r, EV_L3_RESTART_REQ, NULL);
+			}
+		} else {
+			if (l3->x25r.state == ST_R1)
+				ret = 38; // packet too short
+			else if (l3->x25r.state == ST_R3) {
+				l3->cause[0] = 0;
+				l3->cause[1] = 38;
+				mISDN_FsmEvent(&l3->x25r, EV_L3_RESTART_REQ, NULL);
+			}
+		}
+		return(ret);
+	}
+	if ((ptype == X25_PTYPE_RESTART) || (ptype == X25_PTYPE_RESTART_CNF)) {
+		if (channel) {
+			if (l3->x25r.state == ST_R1)
+				return(dte_data_ind_p(l3, skb, gfi, channel, ptype));
+			else if (l3->x25r.state == ST_R3) {
+				l3->cause[0] = 0;
+				l3->cause[1] = 41;
+				mISDN_FsmEvent(&l3->x25r, EV_L3_RESTART_REQ, NULL);
+			}
+			return(ret);
+		}
+		if (ptype == X25_PTYPE_RESTART)
+			mISDN_FsmEvent(&l3->x25r, EV_L2_RESTART, skb);
+		else
+			mISDN_FsmEvent(&l3->x25r, EV_L2_RESTART_CNF, skb);
+	} else {
+		if (l3->x25r.state == ST_R1)
+			return(dte_data_ind_p(l3, skb, gfi, channel, ptype));
+		if (l3->x25r.state == ST_R3) {
+			l3->cause[0] = 0;
+			l3->cause[1] = 19;
+			mISDN_FsmEvent(&l3->x25r, EV_L3_RESTART_REQ, NULL);
+		}
+	}
+	return(ret);
+}
+
+static int
+dte_dl_data_ind(x25_l3_t *l3, struct sk_buff *skb)
+{
+	int	ret;
+	__u16	channel;
+	u_char	gfi, ptype = 0;
+
+	ret = X25_get_header(l3, skb, &gfi, &channel, &ptype);
+	if (ret && (ptype != X25_PTYPE_NOTYPE)) {
+		if (test_bit(X25_STATE_DTEDTE, &l3->state))
+			X25_send_diagnostic(l3, skb, ret, channel);
+		dev_kfree_skb(skb);
+		return(0);
+	}
+	switch(ptype) {
+		case X25_PTYPE_DIAGNOSTIC:
+			ret = got_diagnositic(l3, skb, gfi, channel);
+			break;
+		case X25_PTYPE_REGISTER:
+			ret = got_register(l3, skb, gfi, channel);
+			break;
+		case X25_PTYPE_REGISTER_CNF:
+			ret = got_register_cnf(l3, skb, gfi, channel);
+			break;
+		default:
+			ret = dte_data_ind_r(l3, skb, gfi, channel, ptype);
+			break;
+	}
+	if (ret == X25_ERRCODE_DISCARD) {
+		dev_kfree_skb(skb);
+		ret = 0;
+	} else if (ret) {
+		if (test_bit(X25_STATE_DTEDTE, &l3->state)) {
+			if (ptype != X25_PTYPE_NOTYPE) {
+				if (test_bit(X25_STATE_MOD32768, &l3->state))
+					skb_push(skb, 4);
+				else
+					skb_push(skb, 3);
+			}
+			X25_send_diagnostic(l3, skb, ret, channel);
+		}
+		dev_kfree_skb(skb);
+		ret = 0;
+	}
+	return(ret);
+}
+
+static int
+dte_from_down(x25_l3_t *l3, struct sk_buff *skb, mISDN_head_t *hh)
+{
+	int	ret = -EINVAL;
+
+	if (l3->debug)
+		printk(KERN_DEBUG "%s: prim(%x) dinfo(%x)\n", __FUNCTION__, hh->prim, hh->dinfo);
+	switch(hh->prim) {
+		case DL_DATA_IND:
+			ret = dte_dl_data_ind(l3, skb);
+			break;
+		case DL_DATA | CONFIRM:
+			break;
+		case DL_ESTABLISH_CNF:
+			ret = mISDN_FsmEvent(&l3->l2l3m, EV_LL_ESTABLISH_CNF, NULL);
+			if (ret) {
+				int_error();
+			}
+			ret = 0;
+			dev_kfree_skb(skb);
+			break;
+		case DL_ESTABLISH_IND:
+			ret = mISDN_FsmEvent(&l3->l2l3m, EV_LL_ESTABLISH_IND, NULL);
+			if (ret) {
+				int_error();
+			}
+			ret = 0;
+			dev_kfree_skb(skb);
+			break;
+		case DL_RELEASE_CNF:
+			ret = mISDN_FsmEvent(&l3->l2l3m, EV_LL_RELEASE_CNF, NULL);
+			if (ret) {
+				int_error();
+			}
+			ret = 0;
+			dev_kfree_skb(skb);
+			break;
+		case DL_RELEASE_IND:
+			ret = mISDN_FsmEvent(&l3->l2l3m, EV_LL_RELEASE_IND, NULL);
+			if (ret) {
+				int_error();
+			}
+			ret = 0;
+			dev_kfree_skb(skb);
+			break;
+		default:
+			int_error();
+			break;
+	}
+	return(ret);
+}
+
+static x25_channel_t *
+dte_create_channel(x25_l3_t *l3, int typ, u_char flag, __u16 ch, int len, u_char *data)
+{
+	x25_channel_t	*l3c;
+	__u16		nch = ch;
+	int		ret;
+
+	if (typ == X25_CHANNEL_OUTGOING) {
+		if (ch == 0) {
+			/* first search for allready created channels in P1 state */
+			if (l3->B3cfg.HOC) {
+				for (nch = l3->B3cfg.HOC; (nch && (nch >= l3->B3cfg.LOC)); nch--) {
+					l3c = X25_get_channel(l3, nch);
+					if (l3c && (l3c->x25p.state == ST_P1)) {
+						X25_realloc_ncpi_data(l3c, len, data);
+						return(l3c);
+					}
+				}
+			}
+			if (l3->B3cfg.HTC) {
+				for (nch = l3->B3cfg.HTC; (nch && (nch >= l3->B3cfg.LTC)); nch--) {
+					l3c = X25_get_channel(l3, nch);
+					if (l3c && (l3c->x25p.state == ST_P1)) {
+						X25_realloc_ncpi_data(l3c, len, data);
+						return(l3c);
+					}
+				}
+			}
+			/* now search for still unused channels */
+			nch = 0;
+			if (l3->B3cfg.HOC) {
+				l3c = (x25_channel_t *)1; /* if loop is not executed */
+				for (nch = l3->B3cfg.HOC; (nch && (nch >= l3->B3cfg.LOC)); nch--) {
+					l3c = X25_get_channel(l3, nch);
+					if (!l3c)
+						break;
+				}
+				if (l3c)
+					nch = 0;
+			}
+			if ((nch == 0) && l3->B3cfg.HTC) {
+				l3c = (x25_channel_t *)1; /* if loop is not executed */
+				for (nch = l3->B3cfg.HTC; (nch && (nch >= l3->B3cfg.LTC)); nch--) {
+					l3c = X25_get_channel(l3, nch);
+					if (!l3c)
+						break;
+				}
+				if (l3c)
+					nch = 0;
+			}
+		} else {
+			if (ch >= l3->B3cfg.LIC) /* not a permanent channel */
+				return(NULL);
+			l3c = X25_get_channel(l3, nch);
+			if (l3c) {
+				if (test_bit(X25_STATE_PERMANENT, &l3c->state)) {
+					if (l3c->ncci) /* allready in use */
+						return(NULL);
+					else {
+						X25_realloc_ncpi_data(l3c, len, data);
+						return(l3c);
+					}
+				}
+			}
+			nch = ch;
+		}
+		if (flag & 1)
+			flag = X25_GFI_DBIT;
+	} else {
+		if (!ch) /* not Reference Number procedure implemented */
+			return(NULL);
+		if (l3->B3cfg.HTC) {
+			if (ch > l3->B3cfg.HTC)
+				return(NULL);
+		} else if (l3->B3cfg.HIC) {
+			if (ch > l3->B3cfg.HIC)
+				return(NULL);
+		}
+		nch = ch;
+		if (l3->B3cfg.LIC && ch < l3->B3cfg.LIC) /* permanent channel */
+			nch = ch;
+		else {
+			nch = ch;
+			ch = 0;
+		}
+	}
+	if (!nch)
+		return(NULL);
+	ret = new_x25_channel(l3, &l3c, nch, len, data);
+	if (ret)
+		return(NULL);
+	l3c->x25p.fsm = &dte_pfsm;
+	l3c->x25d.fsm = &dte_dfsm;
+	if (ch) {
+		test_and_set_bit(X25_STATE_PERMANENT, &l3c->state);
+		if (l3c->l3->x25r.state == ST_R1) {
+			l3c->x25p.state = ST_P4;
+			l3c->x25d.state = ST_D1;
+		} else {
+			l3c->x25p.state = ST_P0;
+			l3c->x25d.state = ST_D0;
+		}
+	} else {
+		test_and_clear_bit(X25_STATE_PERMANENT, &l3c->state);
+		if (l3c->l3->x25r.state == ST_R1) {
+			l3c->x25p.state = ST_P1;
+			l3c->x25d.state = ST_D0;
+		} else {
+			l3c->x25p.state = ST_P0;
+			l3c->x25d.state = ST_D0;
+		}
+	}
+	if (flag & X25_GFI_DBIT)
+		test_and_set_bit(X25_STATE_DBIT, &l3c->state);
+	else
+		test_and_clear_bit(X25_STATE_DBIT, &l3c->state);
+	if (flag & X25_GFI_ABIT)
+		test_and_set_bit(X25_STATE_ABIT, &l3c->state);
+	else
+		test_and_clear_bit(X25_STATE_DBIT, &l3c->state);
+	return(l3c);
+}
+
+static int
+dte_from_up(x25_l3_t *l3, struct sk_buff *skb, mISDN_head_t *hh)
+{
+	x25_channel_t   *l3c;
+	__u32		addr;
+	__u16		info = 0;
+	int		err = 0;
+
+	if (skb->len < 4) {
+		printk(KERN_WARNING "%s: skb too short (%d)\n", __FUNCTION__, skb->len);
+		return(-EINVAL);
+	} else {
+		addr = CAPIMSG_U32(skb->data, 0);
+		skb_pull(skb, 4);
+	}
+	if (l3->debug)
+		printk(KERN_DEBUG "%s: addr(%x)\n", __FUNCTION__, addr);
+	l3c = X25_get_channel4NCCI(l3, addr);
+	switch(hh->prim) {
+		case CAPI_DATA_B3_REQ:
+			info = x25_data_b3_req(l3c, hh->dinfo, skb);
+			if (info) {
+				if (info == CAPI_SENDQUEUEFULL) {
+					err = -EXFULL;
+					break;
+				}
+				skb_trim(skb, 0);
+				memcpy(skb_put(skb, 2), &info, 2);
+				err = X25sendL4skb(l3c, l3, addr, CAPI_RESET_B3_CONF, hh->dinfo, skb);
+			} else
+				err = 0;
+			break;
+		case CAPI_DATA_B3_RESP:
+			return(x25_data_b3_resp(l3c, hh->dinfo, skb));
+		case CAPI_CONNECT_B3_REQ:
+			if (!l3c) {
+				x25_ncpi_t	*ncpi;
+				if (skb->len <= 4) { // default NCPI
+					u_char	a = 0;
+					l3c = dte_create_channel(l3, X25_CHANNEL_OUTGOING, 0, 0, 1, &a);
+				} else {
+					ncpi = (x25_ncpi_t *)skb->data;
+					l3c = dte_create_channel(l3, X25_CHANNEL_OUTGOING, ncpi->Flags,
+						(ncpi->Group<<8) | ncpi->Channel,
+						ncpi->len - 3, &ncpi->Contens[0]);
+				}
+				if (l3c)
+					l3c->ncci = addr | (l3c->lchan << 16);
+			}
+			if (l3c) {
+				err = 0;
+				if (l3->x25r.state == ST_R0)
+					mISDN_FsmEvent(&l3->x25r, EV_L3_RESTART_REQ, "\000\000");
+				else
+					err = mISDN_FsmEvent(&l3c->x25p, EV_L3_OUTGOING_CALL, NULL);
+				if (err)
+					info = 0x2001; /* wrong state */
+				else
+					info = 0;
+			} else
+				info = 0x2004; /* no NCCI available */
+			skb_trim(skb, 0);
+			memcpy(skb_put(skb, 2), &info, 2);
+			err = X25sendL4skb(l3c, l3, addr, CAPI_CONNECT_B3_CONF, hh->dinfo, skb);
+			break;
+		case CAPI_RESET_B3_REQ:
+			if (l3c) {
+				if (!(l3c->ncci & 0xffff))
+					l3c->ncci = addr;
+				if (skb->len <= 4) { // default NCPI
+					l3c->cause[0] = 0;
+					l3c->cause[1] = 0;
+					err = mISDN_FsmEvent(&l3c->x25d, EV_L3_RESETING, NULL);
+				} else {
+					skb_pull(skb, 4);
+					err = mISDN_FsmEvent(&l3c->x25d, EV_L3_RESETING, skb);
+					skb_push(skb, 4);
+				}
+				if (err)
+					info = 0x2001;
+				else
+					info = 0;
+			} else
+				info = 0x2002;
+			skb_trim(skb, 0);
+			memcpy(skb_put(skb, 2), &info, 2);
+			err = X25sendL4skb(l3c, l3, addr, CAPI_RESET_B3_CONF, hh->dinfo, skb);
+			break;
+		case CAPI_DISCONNECT_B3_REQ:
+			if (l3c) {
+				if (!(l3c->ncci & 0xffff))
+					l3c->ncci = addr;
+				if (skb->len <= 4) { // default NCPI
+					l3c->cause[0] = 0;
+					l3c->cause[1] = 0;
+					err = mISDN_FsmEvent(&l3c->x25p, EV_L3_CLEARING, NULL);
+				} else {
+					skb_pull(skb, 4);
+					err = mISDN_FsmEvent(&l3c->x25p, EV_L3_CLEARING, skb);
+					skb_push(skb, 4);
+				}
+				if (err)
+					info = 0x2001;
+				else
+					info = 0;
+			} else
+				info = 0x2002;
+
+			skb_trim(skb, 0);
+			memcpy(skb_put(skb, 2), &info, 2);
+			err = X25sendL4skb(l3c, l3, addr, CAPI_DISCONNECT_B3_CONF, hh->dinfo, skb);
+			break;
+		case CAPI_CONNECT_B3_RESP:
+			if (l3c) {
+				int event = EV_L3_CLEARING;
+
+				l3c->ncci = addr;
+				if (skb->len <= 2) {
+					printk(KERN_WARNING "%s: CAPI_CONNECT_B3_RESP skb too short (%d)\n",
+						__FUNCTION__, skb->len);
+					skb_push(skb, 4);
+					return(-EINVAL);
+				}
+				info = CAPIMSG_U16(skb->data, 0);
+				skb_pull(skb, 2);
+				if (info == 0)
+					event = EV_L3_CALL_ACCEPT;
+				if (skb->len <= 4) { // default NCPI
+					l3c->cause[0] = 0;
+					l3c->cause[1] = 0;
+					err = mISDN_FsmEvent(&l3c->x25p, event, NULL);
+				} else {
+					skb_pull(skb, 4);
+					err = mISDN_FsmEvent(&l3c->x25p, event, skb);
+				}
+			} else {
+				skb_push(skb, 4);
+				printk(KERN_WARNING "%s: CAPI_CONNECT_B3_RESP no channel found\n",
+					__FUNCTION__);
+				return(-ENODEV);
+			}
+			dev_kfree_skb(skb);
+			err = 0;
+			break;
+		case CAPI_CONNECT_B3_ACTIVE_RESP:
+		case CAPI_RESET_B3_RESP:
+			if (!l3c) {
+				skb_push(skb, 4);
+				printk(KERN_WARNING "%s: prim %x dinfo %x no channel found\n",
+					__FUNCTION__, hh->prim, hh->dinfo);
+				return(-ENODEV);
+			}
+			dev_kfree_skb(skb);
+			err = 0;
+			break;
+		case CAPI_DISCONNECT_B3_RESP:
+			if (l3c) {
+				l3c->ncci = 0;
+				// TODO release NCCI
+			} else {
+				skb_push(skb, 4);
+				printk(KERN_WARNING "%s: CAPI_DISCONNECT_B3_RESP no channel found\n",
+					__FUNCTION__);
+				return(-ENODEV);
+			}
+			dev_kfree_skb(skb);
+			err = 0;
+			break;
+		default:
+			printk(KERN_WARNING "%s: unknown prim %x dinfo %x\n",
+				__FUNCTION__, hh->prim, hh->dinfo);
+			err = -EINVAL;
+	}
+	return(err);
+}
+
+static int
+dte_function(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	x25_l3_t	*l3;
+	mISDN_head_t	*hh;
+	int		ret = -EINVAL;
+
+	l3 = inst->privat;
+	hh = mISDN_HEAD_P(skb);
+	if (l3->debug)
+		printk(KERN_DEBUG "%s: addr(%08x) prim(%x) dinfo(%x) len(%d)\n", __FUNCTION__,
+			hh->addr, hh->prim, hh->dinfo, skb->len);
+	if (debug)
+		printk(KERN_DEBUG  "%s: addr(%08x) prim(%x)\n", __FUNCTION__,  hh->addr, hh->prim);
+	if (!l3)
+		return(ret);
+
+	switch(hh->addr & MSG_DIR_MASK) {
+		case FLG_MSG_DOWN:
+			ret = dte_from_up(l3, skb, hh);
+			break;
+		case FLG_MSG_UP:
+		case MSG_BROADCAST:  // we define broaadcast comes from down below
+			ret = dte_from_down(l3, skb, hh);
+			break;
+		case MSG_TO_OWNER:
+			/* FIXME: must be handled depending on type */
+			int_errtxt("not implemented yet");
+			break;
+		default:
+			/* FIXME: must be handled depending on type */
+			int_errtxt("not implemented yet");
+			break;
+	}
+	return(ret);
+}
+
+static int
+new_l3(mISDNstack_t *st, mISDN_pid_t *pid) {
+	x25_l3_t	*n_l3;
+	int		err;
+
+	err = new_x25_l3(&n_l3, st, pid, &x25dte_obj, debug, dte_function);
+	if (err)
+		return(err);
+	n_l3->x25r.fsm = &dte_rfsm;
+	n_l3->x25r.state = ST_R0;
+	return(0);
+}
+
+
+static char MName[] = "X25_DTE";
+
+#ifdef MODULE
+MODULE_AUTHOR("Karsten Keil");
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+#endif
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#endif
+
+static int
+dte_manager(void *data, u_int prim, void *arg) {
+	mISDNinstance_t	*inst = data;
+	x25_l3_t	*l3_l;
+	int		err = -EINVAL;
+	u_long		flags;
+
+	if (debug & DEBUG_L3X25_MGR)
+		printk(KERN_DEBUG "l3x25_manager data:%p prim:%x arg:%p\n", data, prim, arg);
+	if (!data)
+		return(err);
+	spin_lock_irqsave(&x25dte_obj.lock, flags);
+	list_for_each_entry(l3_l, &x25dte_obj.ilist, list) {
+		if (&l3_l->inst == inst) {
+			err = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&x25dte_obj.lock, flags);
+	if (prim == (MGR_NEWLAYER | REQUEST))
+		return(new_l3(data, arg));
+	if (err) {
+		printk(KERN_WARNING "l3x25_manager prim(%x) no instance\n", prim);
+		return(err);
+	}
+	switch(prim) {
+	    case MGR_NEWENTITY | CONFIRM:
+		l3_l->entity = (u_long)arg & 0xffffffff;
+		break;
+	    case MGR_ADDSTPARA | INDICATION:
+		{
+			mISDN_stPara_t *stp = arg;
+
+			if (stp->down_headerlen)
+				l3_l->down_headerlen = stp->down_headerlen;
+			if (stp->up_headerlen)
+				l3_l->up_headerlen = stp->up_headerlen;
+			printk(KERN_DEBUG "MGR_ADDSTPARA: (%d/%d/%d)\n",
+				stp->maxdatalen, stp->down_headerlen, stp->up_headerlen);
+	    	}
+	    	break;
+	    case MGR_CLRSTPARA | INDICATION:
+#ifdef OBSOLETE
+	    case MGR_CLONELAYER | REQUEST:
+		break;
+	    case MGR_CONNECT | REQUEST:
+		return(mISDN_ConnectIF(inst, arg));
+	    case MGR_SETIF | REQUEST:
+	    case MGR_SETIF | INDICATION:
+		return(mISDN_SetIF(inst, arg, prim, dte_from_up, dte_from_down, l3_l));
+	    case MGR_DISCONNECT | REQUEST:
+	    case MGR_DISCONNECT | INDICATION:
+		return(mISDN_DisConnectIF(inst, arg));
+#endif
+	    case MGR_UNREGLAYER | REQUEST:
+	    case MGR_RELEASE | INDICATION:
+		if (debug & DEBUG_L3X25_MGR)
+			printk(KERN_DEBUG "X25_release_l3 id %x\n", l3_l->inst.st->id);
+		X25_release_l3(l3_l);
+		break;
+//	    case MGR_STATUS | REQUEST:
+//		return(l3x25_status(l3x25_l, arg));
+	    default:
+		if (debug & DEBUG_L3X25_MGR)
+			printk(KERN_WARNING "l3x25_manager prim %x not handled\n", prim);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+static int
+x25_dte_init(void)
+{
+	int err;
+
+	printk(KERN_INFO "X25 DTE modul version %s\n", mISDN_getrev(mISDN_dte_revision));
+#ifdef MODULE
+	x25dte_obj.owner = THIS_MODULE;
+#endif
+	x25dte_obj.name = MName;
+	x25dte_obj.BPROTO.protocol[3] = ISDN_PID_L3_B_X25DTE;
+	x25dte_obj.own_ctrl = dte_manager;
+	spin_lock_init(&x25dte_obj.lock);
+	INIT_LIST_HEAD(&x25dte_obj.ilist);
+	if ((err = mISDN_register(&x25dte_obj))) {
+		printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
+	} else {
+		X25_l3_init();
+		dte_rfsm.state_count = R_STATE_COUNT;
+		dte_rfsm.event_count = R_EVENT_COUNT;
+		dte_rfsm.strEvent = X25strREvent;
+		dte_rfsm.strState = X25strRState;
+		mISDN_FsmNew(&dte_rfsm, RFnList, R_FN_COUNT);
+		dte_pfsm.state_count = P_STATE_COUNT;
+		dte_pfsm.event_count = P_EVENT_COUNT;
+		dte_pfsm.strEvent = X25strPEvent;
+		dte_pfsm.strState = X25strPState;
+		mISDN_FsmNew(&dte_pfsm, PFnList, P_FN_COUNT);
+		dte_dfsm.state_count = D_STATE_COUNT;
+		dte_dfsm.event_count = D_EVENT_COUNT;
+		dte_dfsm.strEvent = X25strDEvent;
+		dte_dfsm.strState = X25strDState;
+		mISDN_FsmNew(&dte_dfsm, DFnList, D_FN_COUNT);
+		mISDN_module_register(THIS_MODULE);
+	}
+	return(err);
+}
+
+static void
+x25_dte_cleanup(void)
+{
+	x25_l3_t	*l3, *nl3;
+	int		err;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+	if ((err = mISDN_unregister(&x25dte_obj))) {
+		printk(KERN_ERR "Can't unregister l3x25 error(%d)\n", err);
+	}
+	if(!list_empty(&x25dte_obj.ilist)) {
+		printk(KERN_WARNING "l3x25 inst list not empty\n");
+		list_for_each_entry_safe(l3, nl3, &x25dte_obj.ilist, list)
+			X25_release_l3(l3);
+	}
+	X25_l3_cleanup();
+	mISDN_FsmFree(&dte_rfsm);
+	mISDN_FsmFree(&dte_pfsm);
+	mISDN_FsmFree(&dte_dfsm);
+}
+
+module_init(x25_dte_init);
+module_exit(x25_dte_cleanup);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_l3.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_l3.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_l3.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,1171 @@
+/* $Id: x25_l3.c,v 1.10 2007/02/13 10:43:45 crich Exp $
+ *
+ * Linux modular ISDN subsystem, mISDN
+ * X.25/X.31 common Layer3 functions 
+ *
+ * Author	Karsten Keil (kkeil at suse.de)
+ *
+ * Copyright 2003 by Karsten Keil (kkeil at suse.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include <linux/module.h>
+#include "x25_l3.h"
+#include "helper.h"
+#include "debug.h"
+
+/* LinkLayer (L2) maintained by L3 statemachine */
+
+static struct Fsm llfsm = {NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_LL_REL,
+	ST_LL_ESTAB_WAIT,
+	ST_LL_REL_WAIT,
+	ST_LL_ESTAB,
+};
+
+#define LL_STATE_COUNT	(ST_LL_ESTAB+1)
+
+static char *strLLState[] =
+{
+	"ST_LL_REL",
+	"ST_LL_ESTAB_WAIT",
+	"ST_LL_REL_WAIT",
+	"ST_LL_ESTAB",
+};
+
+static char *strLLEvent[] =
+{
+	"EV_L3_ESTABLISH_REQ",
+	"EV_LL_ESTABLISH_IND",
+	"EV_LL_ESTABLISH_CNF",
+	"EV_L3_RELEASE_REQ",
+	"EV_LL_RELEASE_CNF",
+	"EV_LL_RELEASE_IND",
+};
+
+/* X.25 Restart state machine */
+
+char *X25strRState[] =
+{
+	"ST_R0",
+	"ST_R1",
+	"ST_R2",
+	"ST_R3",
+};
+
+char *X25strREvent[] =
+{
+	"EV_LL_READY",
+ 	"EV_L3_RESTART_REQ",
+	"EV_L2_RESTART",
+	"EV_L2_RESTART_CNF",
+	"EV_L3_RESTART_TOUT",
+};
+
+/* X.25 connection state machine */
+
+char *X25strPState[] =
+{
+	"ST_P0",
+	"ST_P1",
+	"ST_P2",
+	"ST_P3",
+	"ST_P4",
+	"ST_P5",
+	"ST_P6",
+	"ST_P7",
+};
+
+char *X25strPEvent[] =
+{
+	"EV_L3_READY",
+	"EV_L3_OUTGOING_CALL",
+	"EV_L2_INCOMING_CALL",
+	"EV_L2_CALL_CNF",
+	"EV_L3_CALL_ACCEPT",
+	"EV_L3_CLEARING",
+	"EV_L2_CLEAR",
+	"EV_L2_CLEAR_CNF",
+	"EV_L2_INVALPKT",
+	"EV_L3_CALL_TOUT",
+	"EV_L3_CLEAR_TOUT",
+};
+
+/* X.25 Flowcontrol state machine */
+
+char *X25strDState[] =
+{
+	"ST_D0",
+	"ST_D1",
+	"ST_D2",
+	"ST_D3",
+};
+
+char *X25strDEvent[] =
+{
+	"EV_L3_CONNECT",
+ 	"EV_L2_RESETING",
+	"EV_L2_RESET",
+	"EV_L2_RESET_CNF",
+	"EV_L3_RESET_TOUT",
+};
+
+static void
+l3m_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	x25_l3_t	*l3 = fi->userdata;
+	logdata_t	log;
+
+	va_start(log.args, fmt);
+	log.fmt = fmt;
+	log.head = l3->inst.name;
+	mISDN_ctrl(&l3->inst, MGR_DEBUGDATA | REQUEST, &log);
+	va_end(log.args);
+}
+
+/* LinkLayer (L2) maintained by L3 statemachine */
+
+static void
+ll_activate(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t *l3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_LL_ESTAB_WAIT);
+	X25_l3down(l3, DL_ESTABLISH | REQUEST, 0, NULL);
+}
+
+static void
+ll_connect(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t *l3 = fi->userdata;
+	struct sk_buff *skb;
+	int dequeued = 0;
+
+	mISDN_FsmChangeState(fi, ST_LL_ESTAB);
+	mISDN_FsmEvent(&l3->x25r, EV_LL_READY, NULL);
+	while ((skb = skb_dequeue(&l3->downq))) {
+		mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+		if (X25_l3down(l3, hh->prim, hh->dinfo, skb))
+			dev_kfree_skb(skb);
+		dequeued++;
+	}
+}
+
+static void
+ll_connected(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t *l3 = fi->userdata;
+	struct sk_buff *skb;
+	int dequeued = 0;
+
+	mISDN_FsmChangeState(fi, ST_LL_ESTAB);
+	mISDN_FsmEvent(&l3->x25r, EV_LL_READY, NULL);
+	while ((skb = skb_dequeue(&l3->downq))) {
+		mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+		if (X25_l3down(l3, hh->prim, hh->dinfo, skb))
+			dev_kfree_skb(skb);
+		dequeued++;
+	}
+}
+
+static void
+ll_release_req(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t *l3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_LL_REL_WAIT);
+	X25_l3down(l3, DL_RELEASE | REQUEST, 0, NULL);
+}
+
+static void
+ll_release_ind(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t *l3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_LL_REL);
+	discard_queue(&l3->downq);
+}
+
+static void
+ll_release_cnf(struct FsmInst *fi, int event, void *arg)
+{
+	x25_l3_t *l3 = fi->userdata;
+
+	mISDN_FsmChangeState(fi, ST_LL_REL);
+	discard_queue(&l3->downq);
+}
+
+
+/* *INDENT-OFF* */
+static struct FsmNode LLFnList[] =
+{
+	{ST_LL_REL,		EV_L3_ESTABLISH_REQ,	ll_activate},
+	{ST_LL_REL,		EV_LL_ESTABLISH_IND,	ll_connect},
+	{ST_LL_REL,		EV_LL_ESTABLISH_CNF,	ll_connect},
+	{ST_LL_ESTAB_WAIT,	EV_LL_ESTABLISH_CNF,	ll_connected},
+	{ST_LL_ESTAB_WAIT,	EV_L3_RELEASE_REQ,	ll_release_req},
+	{ST_LL_ESTAB_WAIT,	EV_LL_RELEASE_IND,	ll_release_ind},
+	{ST_LL_ESTAB,		EV_LL_RELEASE_IND,	ll_release_ind},
+	{ST_LL_ESTAB,		EV_L3_RELEASE_REQ,	ll_release_req},
+	{ST_LL_REL_WAIT,	EV_LL_RELEASE_CNF,	ll_release_cnf},
+	{ST_LL_REL_WAIT,	EV_L3_ESTABLISH_REQ,	ll_activate},
+};
+/* *INDENT-ON* */
+
+#define LL_FN_COUNT (sizeof(LLFnList)/sizeof(struct FsmNode))
+
+static void
+l3c_debug(struct FsmInst *fi, char *fmt, ...)
+{
+	x25_channel_t	*l3c = fi->userdata;
+	logdata_t	log;
+
+	va_start(log.args, fmt);
+	log.fmt = fmt;
+	log.head = l3c->l3->inst.name;
+	mISDN_ctrl(&l3c->l3->inst, MGR_DEBUGDATA | REQUEST, &log);
+	va_end(log.args);
+}
+
+static void
+discard_confq(x25_channel_t *l3c)
+{
+	int		i;
+	x25_ConfQueue_t	*cq = l3c->confq;
+
+	for (i = 0; i < l3c->lwin; i++) {
+		if (cq->PktId) {
+			dev_kfree_skb(cq->skb);
+			cq->PktId = 0;
+		}
+		cq++;
+	}
+}
+
+int
+X25_reset_channel(x25_channel_t *l3c, struct sk_buff *skb)
+{
+	discard_confq(l3c);
+	l3c->pr = 0;
+	l3c->ps = 0;
+	l3c->rps = 0;
+	// TODO requeue outstanding pakets
+	// TODO timers ???
+	if (skb) {
+		if (skb->len == 2)
+			memcpy(l3c->cause, skb->data, 2);
+		else
+			printk(KERN_DEBUG "%s: skb len not 2 (%d)\n", __FUNCTION__, skb->len);
+	}
+	if (ST_P4 == l3c->x25p.state) {
+		X25sendL4frame(l3c, l3c->l3, CAPI_RESET_B3_IND, 0, 2, l3c->cause);
+		// invoke send ???
+	}
+	return(0);
+}
+
+int
+X25_restart(x25_l3_t *l3)
+{
+	x25_channel_t	*l3c;
+
+	list_for_each_entry(l3c, &l3->channellist, list) {
+		memcpy(l3c->cause, l3->cause, 2);
+		X25_reset_channel(l3c, NULL);
+		mISDN_FsmEvent(&l3c->x25p, EV_L3_READY, NULL);
+	}
+	return(0);
+}
+
+int
+X25_next_id(x25_l3_t *l3)
+{
+	int	id;
+
+	id = l3->next_id++;
+	if (id == 0x0fff)
+		l3->next_id = 1;
+	id |= (l3->entity << 16);
+	return(id);
+}
+
+int
+X25_get_header(x25_l3_t *l3, struct sk_buff *skb, u_char *gfi, __u16 *channel, u_char *ptype)
+{
+	u_char	*p = skb->data;
+	int	l = 3;
+
+	if (skb->len < 2)
+		return(38); // packet too short
+	if ((*p & 0x30) == 0x30) {
+		if (*p != 0x30)
+			return(40); // invalid GFI
+		p++;
+		l++;
+		if (skb->len < 3)
+			return(38); // packet too short
+		if ((*p & 0x30)!= 0x30)
+			return(40); // invalid GFI
+		if (!test_bit(X25_STATE_MOD32768, &l3->state))
+			return(40); // invalid GFI
+	}
+	*gfi = (*p & 0xf0);
+	if (!(*gfi & 0x30))
+		return(40); // invalid GFI
+	if (((*gfi & 0x30) == 0x20) && !test_bit(X25_STATE_MOD128, &l3->state)) 
+		return(40); // invalid GFI
+	*channel = (*p & 0xf) << 8;
+	p++;
+	*channel |= *p++;
+	if (skb->len < l) {
+		*ptype = X25_PTYPE_NOTYPE;
+		return(38);
+	}
+	*ptype = *p;
+	skb_pull(skb, l);
+	return(0);
+}
+
+int
+X25_cansend(x25_channel_t *chan)
+{
+	u_int	m = 7;
+
+	if (test_bit(X25_STATE_MOD128, &chan->state))
+		m = 0x7f;
+	else if (test_bit(X25_STATE_MOD32768, &chan->state))
+		m = 0x7fff;
+	
+	return((((chan->ps - chan->pr) & m) < chan->lwin) &&
+		!test_bit(X25_STATE_DTE_RNR, &chan->state) && (chan->x25d.state == ST_D1));
+}
+
+void
+X25_confirmed(x25_channel_t *chan)
+{
+	int		i, ret;
+	x25_ConfQueue_t	*cq = chan->confq;
+	struct sk_buff	*skb;
+
+	for (i = 0; i < chan->lwin; i++) {
+		if ((cq->PktId & 0x7fff) == chan->pr)
+			break;
+		cq++;
+	}
+	if (i == chan->lwin) {
+		int_error();
+		return;
+	}
+	skb = cq->skb;
+	cq->skb = NULL;
+	if (!skb) {
+		return;
+	}
+	skb_push(skb, 8);
+	skb_trim(skb, 0);
+	capimsg_setu32(skb_put(skb, 4), 0, chan->ncci);
+	capimsg_setu16(skb_put(skb, 2), 0, cq->DataHandle);
+	capimsg_setu16(skb_put(skb, 2), 0, 0);
+	i = cq->MsgId;
+	/* free entry */
+	cq->PktId = 0;
+	ret = mISDN_queueup_newhead(&chan->l3->inst, 0, CAPI_DATA_B3_CONF, i, skb);
+	if (ret) {
+		printk(KERN_WARNING "%s: up error %d\n", __FUNCTION__, ret);
+		dev_kfree_skb(skb);
+	}
+	return;
+}
+
+void
+X25_confirm_pr(x25_channel_t *chan, u_int pr)
+{
+	u_int	mod = 8;
+
+	if (test_bit(X25_STATE_MOD128, &chan->state))
+		mod = 128;
+	else if (test_bit(X25_STATE_MOD32768, &chan->state))
+		mod = 32768;
+	while (chan->pr != pr) {
+		X25_confirmed(chan);
+		chan->pr++;
+		if (chan->pr >= mod)
+			chan->pr = 0;
+	}
+}
+
+int
+X25_receive_data(x25_channel_t *chan, int ps, int flag, struct sk_buff *skb)
+{
+	int		l, i, m = 8;
+	u_char		*p = skb->data;
+	struct sk_buff	*nskb;
+	
+	if (test_bit(X25_STATE_DTE_RNR, &chan->state))
+		return(X25_ERRCODE_DISCARD);
+	for (i = 0; i < CAPI_MAXDATAWINDOW; i++) {
+		if (chan->recv_handles[i] == 0)
+			break;
+	}
+
+	if (i == CAPI_MAXDATAWINDOW) {
+		test_and_set_bit(X25_STATE_DTE_RNR, &chan->state);
+		printk(KERN_DEBUG "%s: frame %d dropped\n", __FUNCTION__, skb->len);
+		return(X25_ERRCODE_DISCARD);
+	}
+
+	if (skb_headroom(skb) < CAPI_B3_DATA_IND_HEADER_SIZE) {
+		printk(KERN_DEBUG "%s: only %d bytes headroom, need %d",
+			__FUNCTION__, skb_headroom(skb), CAPI_B3_DATA_IND_HEADER_SIZE);
+		nskb = skb_realloc_headroom(skb, CAPI_B3_DATA_IND_HEADER_SIZE);
+		dev_kfree_skb(skb);
+		if (!nskb) {
+			int_error();
+			return(0);
+		}
+      	} else { 
+		nskb = skb;
+	}
+	chan->recv_handles[i] = 0x100 | flag;
+	l = skb->len;
+	skb_push(nskb, CAPI_B3_DATA_IND_HEADER_SIZE - CAPIMSG_BASELEN);
+	capimsg_setu32(nskb->data, 0, chan->ncci);
+	if (sizeof(nskb) == 4) {
+		capimsg_setu32(nskb->data, 4, (u_long)p);
+		capimsg_setu32(nskb->data, 14, 0);
+		capimsg_setu32(nskb->data, 18, 0);
+		
+	} else {
+		capimsg_setu32(nskb->data, 4, 0);
+		capimsg_setu32(nskb->data, 14, ((u_long)p) & 0xffffffff);
+		capimsg_setu32(nskb->data, 18, (((__u64)((u_long)p)) >> 32) & 0xffffffff);
+	}
+	capimsg_setu16(nskb->data, 8, l);
+	capimsg_setu16(nskb->data, 10, i);
+	capimsg_setu16(nskb->data, 12, flag);
+
+	if (mISDN_queueup_newhead(&chan->l3->inst, 0, CAPI_DATA_B3_IND, 0, nskb)) {
+		chan->recv_handles[i] = 0;
+		return(X25_ERRCODE_DISCARD);
+	}
+	if (!(flag & CAPI_FLAG_DELIVERCONF)) {
+		if (test_bit(X25_STATE_MOD32768, &chan->state))
+			m = 32768;
+		else if (test_bit(X25_STATE_MOD128, &chan->state))
+			m = 128;
+		chan->rps++;
+		if (chan->rps >= m)
+			chan->rps = 0;
+		if (X25_cansend(chan) && skb_queue_len(&chan->dataq))
+			X25_invoke_sending(chan);
+		else {
+			if (test_bit(X25_STATE_DTE_RNR, &chan->state))
+				X25sendL3frame(chan, chan->l3, X25_PTYPE_RNR, 0, NULL);
+			else
+				X25sendL3frame(chan, chan->l3, X25_PTYPE_RR, 0, NULL);
+		}
+	}
+	return(0);
+}
+
+int
+X25_get_and_test_pr(x25_channel_t *chan, u_char ptype, struct sk_buff *skb)
+{
+	u_char	*p = skb->data;
+	u_int	pr_m, pr, m = 7;
+
+	if (test_bit(X25_STATE_MOD128, &chan->state)) {
+		if (skb->len < 1)
+			return(-38);
+		pr_m = *p;
+		skb_pull(skb, 1);
+		m = 0x7f;
+	} else if (test_bit(X25_STATE_MOD32768, &chan->state)) {
+		if (skb->len < 2)
+			return(-38);
+		pr_m = *p++;
+		pr_m |= (*p << 8);
+		skb_pull(skb, 2);
+		m = 0x7fff;
+	} else {
+		pr_m = ptype >> 4; 
+	}
+	pr = pr_m >> 1;
+	if (chan->debug)
+		printk(KERN_DEBUG "%s: pr(%d) chan: pr(%d) ps(%d)\n",
+			__FUNCTION__, pr, chan->pr, chan->ps);
+	if (((pr - chan->pr) & m) <= ((chan->ps - chan->pr) & m)) {
+		if (chan->pr != pr)
+			X25_confirm_pr(chan, pr);
+		return(pr_m);
+	} else
+		return(-1);
+}
+
+int
+X25_get_and_test_ps(x25_channel_t *chan, u_char ptype, struct sk_buff *skb)
+{
+	u_char	*p = skb->data;
+	int	m = 128, ps = ptype >> 1;
+
+	if (test_bit(X25_STATE_MOD32768, &chan->state)) {
+		if (skb->len < 1)
+			return(-38);
+		ps |= (*p << 7);
+		skb_pull(skb, 1);
+		m = 32768;
+	} else if (!test_bit(X25_STATE_MOD128, &chan->state)) {
+		ps &= 7;
+		m = 8;
+	}
+	if (chan->debug)
+		printk(KERN_DEBUG "%s: ps(%d) chan: rps(%d)\n",
+			__FUNCTION__, ps, chan->rps);
+	if (ps != chan->rps)
+		return(-2);
+	return(ps);
+}
+
+void
+X25_release_channel(x25_channel_t *l3c)
+{
+	list_del(&l3c->list);
+	kfree(l3c->ncpi_data);
+	l3c->ncpi_data = NULL;
+	l3c->ncpi_len = 0;
+	discard_queue(&l3c->dataq);
+	mISDN_FsmDelTimer(&l3c->TP, 1);
+	mISDN_FsmDelTimer(&l3c->TD, 2);
+	discard_queue(&l3c->dataq);
+	discard_confq(l3c);
+	kfree(l3c->confq);
+	kfree(l3c);
+}
+
+void
+X25_release_l3(x25_l3_t *l3) {
+	mISDNinstance_t	*inst = &l3->inst;
+	x25_channel_t	*ch, *nch;
+
+#ifdef OBSOLETE
+	if (inst->up.peer) {
+		inst->up.peer->obj->ctrl(inst->up.peer,
+			MGR_DISCONNECT | REQUEST, &inst->up);
+	}
+	if (inst->down.peer) {
+		inst->down.peer->obj->ctrl(inst->down.peer,
+			MGR_DISCONNECT | REQUEST, &inst->down);
+	}
+#endif
+	if (inst->obj) {
+		u_long	flags;
+		spin_lock_irqsave(&inst->obj->lock, flags);
+		list_del_init(&l3->list);
+		spin_unlock_irqrestore(&inst->obj->lock, flags);
+	}
+	discard_queue(&l3->downq);
+	list_for_each_entry_safe(ch, nch, &l3->channellist, list)
+		X25_release_channel(ch);
+	mISDN_FsmDelTimer(&l3->TR, 3);
+	if (inst->obj) {
+		if (l3->entity != MISDN_ENTITY_NONE)
+			mISDN_ctrl(inst, MGR_DELENTITY | REQUEST,
+				(void *)((u_long)l3->entity));
+		mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+	}
+	kfree(l3);
+}
+
+int
+X25_realloc_ncpi_data(x25_channel_t *l3c, int len, u_char *data)
+{
+	if (len) {
+		if (len > l3c->ncpi_len) {
+			kfree(l3c->ncpi_data);
+			l3c->ncpi_data = kmalloc(len, GFP_ATOMIC);
+			if (!l3c->ncpi_data) {
+				l3c->ncpi_len = 0;
+				return(-ENOMEM);
+			}
+		}
+		memcpy(l3c->ncpi_data, data, len);
+	} else {
+		kfree(l3c->ncpi_data);
+		l3c->ncpi_data = NULL;
+	}
+	l3c->ncpi_len = len;
+	return(0);
+}
+
+int
+new_x25_channel(x25_l3_t *l3, x25_channel_t **ch_p, __u16 ch, int dlen, u_char *data)
+{
+	x25_channel_t	*l3c;
+
+	l3c = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC);
+	if (!l3c) {
+		printk(KERN_ERR "kmalloc x25_channel_t failed\n");
+		return(-ENOMEM);
+	}
+	memset(l3c, 0, sizeof(x25_channel_t));
+	if (X25_realloc_ncpi_data(l3c, dlen, data)) {
+		printk(KERN_ERR "kmalloc ncpi_data (%d) failed\n", dlen);
+		kfree(l3c);
+		return(-ENOMEM);
+	}
+	l3c->lwin = l3->B3cfg.winsize;
+	l3c->rwin = l3->B3cfg.winsize;
+	l3c->datasize = l3->maxdatalen;
+	l3c->lchan = ch;
+	l3c->ncci = ch << 16;
+	l3c->confq = kmalloc(l3c->lwin * sizeof(x25_ConfQueue_t), GFP_ATOMIC);
+	if (!l3c->confq) {
+		printk(KERN_ERR "kmalloc confq %d entries failed\n", l3c->lwin);
+		kfree(l3c->ncpi_data);
+		kfree(l3c);
+		return(-ENOMEM);
+	}
+	memset(l3c->confq, 0, l3c->lwin * sizeof(x25_ConfQueue_t));
+	l3c->l3 = l3;
+	l3c->debug = l3->debug;
+	l3c->state = l3->state;
+
+	l3c->x25p.debug = l3->debug;
+	l3c->x25p.userdata = l3c;
+	l3c->x25p.userint = 0;
+	l3c->x25p.printdebug = l3c_debug;
+	mISDN_FsmInitTimer(&l3c->x25p, &l3c->TP);
+
+	l3c->x25d.debug = l3->debug;
+	l3c->x25d.userdata = l3c;
+	l3c->x25d.userint = 0;
+	l3c->x25d.printdebug = l3c_debug;
+	mISDN_FsmInitTimer(&l3c->x25d, &l3c->TD);
+	skb_queue_head_init(&l3c->dataq);
+
+	list_add_tail(&l3c->list, &l3->channellist);
+	*ch_p = l3c;
+	return(0);
+}
+
+int
+new_x25_l3(x25_l3_t **l3_p, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *obj, int debug, if_func_t *function) {
+	x25_l3_t	*n_l3;
+	int		err;
+	u_long		flags;
+
+	if (!st || !pid)
+		return(-EINVAL);
+	if (!(n_l3 = kmalloc(sizeof(x25_l3_t), GFP_ATOMIC))) {
+		printk(KERN_ERR "kmalloc x25_l3_t failed\n");
+		return(-ENOMEM);
+	}
+	memset(n_l3, 0, sizeof(x25_l3_t));
+	INIT_LIST_HEAD(&n_l3->channellist);
+	n_l3->entity = MISDN_ENTITY_NONE;
+	n_l3->next_id = 1;
+	memcpy(&n_l3->inst.pid, pid, sizeof(mISDN_pid_t));
+	mISDN_init_instance(&n_l3->inst, obj, n_l3, function);
+	if (!mISDN_SetHandledPID(obj, &n_l3->inst.pid)) {
+		int_error();
+		kfree(n_l3);
+		return(-ENOPROTOOPT);
+	}
+	n_l3->debug = debug;
+	n_l3->B3cfg = (x25_B3_cfg_t)DEFAULT_X25_B3_CFG;
+	if (pid->param[3] && pid->pbuf) {
+		u_char	*p = pid->pbuf + pid->param[3];
+		memcpy(&n_l3->B3cfg, &p[1], p[0]);
+	}
+	if (n_l3->B3cfg.modulo == 128)
+		test_and_set_bit(X25_STATE_MOD128, &n_l3->state);
+	if (n_l3->inst.pid.global == 1)
+		test_and_set_bit(X25_STATE_ORGINATE, &n_l3->state);
+
+	n_l3->l2l3m.fsm = &llfsm;
+	n_l3->l2l3m.state = ST_LL_REL;
+	n_l3->l2l3m.debug = debug;
+	n_l3->l2l3m.userdata = n_l3;
+	n_l3->l2l3m.userint = 0;
+	n_l3->l2l3m.printdebug = l3m_debug;
+
+	n_l3->x25r.debug = debug;
+	n_l3->x25r.userdata = n_l3;
+	n_l3->x25r.userint = 0;
+	n_l3->x25r.printdebug = l3m_debug;
+	mISDN_FsmInitTimer(&n_l3->x25r, &n_l3->TR);
+	skb_queue_head_init(&n_l3->downq);
+	spin_lock_irqsave(&obj->lock, flags);
+	list_add_tail(&n_l3->list, &obj->ilist);
+	spin_unlock_irqrestore(&obj->lock, flags);
+	err = mISDN_ctrl(&n_l3->inst, MGR_NEWENTITY | REQUEST, NULL);
+	if (err) {
+		printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%d)\n",
+			__FUNCTION__, err);
+	}
+	err = mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &n_l3->inst);
+	if (err) {
+		list_del(&n_l3->list);
+		kfree(n_l3);
+		n_l3 = NULL;
+	} else {
+		if (st->para.maxdatalen)
+			n_l3->maxdatalen = st->para.maxdatalen;
+		if (st->para.up_headerlen)
+			n_l3->up_headerlen = st->para.up_headerlen;
+		if (st->para.down_headerlen)
+			n_l3->down_headerlen = st->para.down_headerlen;
+		if (debug)
+			printk(KERN_DEBUG "%s:mlen(%d) hup(%d) hdown(%d)\n", __FUNCTION__,
+				n_l3->maxdatalen, n_l3->up_headerlen, n_l3->down_headerlen);
+	}
+	*l3_p = n_l3;
+	return(err);
+}
+
+int
+X25_add_header(x25_channel_t *l3c, x25_l3_t *l3, u_char pt, u_char *head, u_char flag)
+{
+	u_char	*p = head;
+
+	if (test_bit(X25_STATE_MOD32768, &l3->state)) {
+		*p++ = 0x30;
+		*p = 0x30;
+	} else if (test_bit(X25_STATE_MOD128, &l3->state))
+		*p = 0x20;
+	else
+		*p = 0x10;
+	switch (pt) {
+		case X25_PTYPE_RESTART:
+		case X25_PTYPE_RESTART_CNF:
+		case X25_PTYPE_REGISTER:
+		case X25_PTYPE_REGISTER_CNF:
+		case X25_PTYPE_DIAGNOSTIC:
+			p++;
+			*p++ = 0;
+			*p++ = pt;
+			break;
+		case X25_PTYPE_RESET:
+		case X25_PTYPE_RESET_CNF:
+		case X25_PTYPE_INTERRUPT:
+		case X25_PTYPE_INTERRUPT_CNF:
+			*p++ |= (((l3c->lchan) >> 8) & 0xf);
+			*p++ = l3c->lchan & 0xff;
+			*p++ = pt;
+			break;
+		case X25_PTYPE_CALL:
+		case X25_PTYPE_CLEAR:
+			if (test_bit(X25_STATE_DBIT, &l3c->state))
+				*p |= X25_GFI_DBIT;
+		case X25_PTYPE_CALL_CNF:
+		case X25_PTYPE_CLEAR_CNF:
+			if (test_bit(X25_STATE_ABIT, &l3c->state))
+				*p |= X25_GFI_ABIT;
+			*p++ |= (((l3c->lchan) >> 8) & 0xf);
+			*p++ = l3c->lchan & 0xff;
+			*p++ = pt;
+			break;
+		case X25_PTYPE_RR:
+		case X25_PTYPE_RNR:
+		case X25_PTYPE_REJ:
+			if (*p == 0x10)
+				pt |= (l3c->rps << 5);
+			*p++ |= (((l3c->lchan) >> 8) & 0xf);
+			*p++ = l3c->lchan & 0xff;
+			*p++ = pt;
+			if (test_bit(X25_STATE_MOD128, &l3->state))
+				*p++ = l3c->rps << 1;
+			else if (test_bit(X25_STATE_MOD32768, &l3->state)) {
+				*p++ = (0x7f & l3c->rps) << 1;
+				*p++ = l3c->rps >> 7;
+			}
+			break;
+		case X25_PTYPE_DATA:
+			if (*p == 0x10) {
+				*p |= (flag & (X25_GFI_DBIT | X25_GFI_QBIT));
+				*p++ |= (((l3c->lchan) >> 8) & 0xf);
+				*p++ = l3c->lchan & 0xff;
+				if (flag & X25_MBIT)
+					pt |= X25_MBIT_MOD8;
+				pt |= (l3c->rps << 5);
+				pt |= (l3c->ps << 1);
+				*p++ = pt;
+				l3c->ps++;
+				if (l3c->ps > 7)
+					l3c->ps = 0;
+			} else if (*p == 0x20) {
+				*p |= (flag & (X25_GFI_DBIT | X25_GFI_QBIT));
+				*p++ |= (((l3c->lchan) >> 8) & 0xf);
+				*p++ = l3c->lchan & 0xff;
+				*p++ = (l3c->ps << 1);
+				*p = (flag & X25_MBIT) ? 1 : 0; 
+				*p++ |= (l3c->rps << 1);
+				l3c->ps++;
+				if (l3c->ps > 0x7f)
+					l3c->ps = 0;
+			} else {
+				*p |= (flag & (X25_GFI_DBIT | X25_GFI_QBIT));
+				*p++ |= (((l3c->lchan) >> 8) & 0xf);
+				*p++ = l3c->lchan & 0xff;
+				*p++ = ((l3c->ps & 0x7f) << 1);
+				*p++ = (l3c->ps >> 7);
+				*p = (flag & X25_MBIT) ? 1 : 0;
+				*p++ = ((l3c->rps & 0x7f) << 1);
+				*p++ = (l3c->rps >> 7);
+				l3c->ps++;
+				if (l3c->ps > 0x7fff)
+					l3c->ps = 0;
+			}
+			break;
+		default:
+			return(-EINVAL);
+	}
+	return(p - head);
+}
+
+int
+X25sendL3frame(x25_channel_t *l3c, x25_l3_t *l3, u_char pt, int len, void *arg)
+{
+	struct sk_buff	*skb;
+	int		ret;
+
+	skb = alloc_stack_skb(len + X25_MINSIZE, l3->down_headerlen);
+	if (!skb)
+		return(-ENOMEM);
+	ret = X25_add_header(l3c, l3, pt, skb->tail, 0);
+	if (ret<0) {
+		int_error();
+		dev_kfree_skb(skb);
+		return(ret);
+	}
+	skb_put(skb, ret);
+	if (arg && len)
+		memcpy(skb_put(skb, len), arg, len);
+
+	mISDN_sethead(DL_DATA_REQ, X25_next_id(l3), skb);
+
+	if (l3->l2l3m.state == ST_LL_ESTAB) {
+		ret = mISDN_queue_message(&l3->inst, FLG_MSG_DOWN, skb);
+		if (ret) {
+			dev_kfree_skb(skb);
+		}
+	} else {
+		skb_queue_tail(&l3->downq, skb);
+		ret = 0;
+	}
+	return(ret);
+}
+
+int
+X25_l3down(x25_l3_t *l3, u_int prim, u_int dinfo, struct sk_buff *skb)
+{
+	int		ret;
+
+	if (!skb) {
+		if (!(skb = alloc_stack_skb(0, l3->down_headerlen)))
+			return(-ENOMEM);
+	}
+	ret = mISDN_queuedown_newhead(&l3->inst, 0, prim, dinfo, skb);
+	if (ret) {
+		dev_kfree_skb(skb);
+	}
+	return(0);
+}
+
+void
+X25_send_diagnostic(x25_l3_t *l3, struct sk_buff *skb, int err, int channel)
+{
+	u_char	diagp[8], *p;
+	u_int	i,l = 3;
+
+	p = diagp;
+	*p++ = err & 0xff;
+	if (test_bit(X25_STATE_MOD32768, &l3->state)) {
+		*p++ = 0x30;
+		l++;
+	}
+	if (skb) {
+		if (skb->len < l)
+			l = skb->len;
+		for (i = 0; i < l; i++)
+			*p++ = skb->data[i];
+	} else {
+		if ((err & 0xf0) == 0x30) { /* Timer Expired */
+			if (test_bit(X25_STATE_MOD32768, &l3->state))
+				*p = 0x30;
+			else if (test_bit(X25_STATE_MOD128, &l3->state))
+				*p = 0x20;
+			else
+				*p = 0x10;
+			if (err == 0x34)
+				channel = 0; 
+			*p |= ((channel >> 8) & 0x0f);
+			p++;
+			*p++ = channel & 0xff;
+		}
+	}
+	X25sendL3frame(NULL, l3, X25_PTYPE_DIAGNOSTIC, p - diagp, diagp);
+}
+
+x25_channel_t *
+X25_get_channel(x25_l3_t *l3, __u16 ch)
+{
+	x25_channel_t	*l3c;
+
+	list_for_each_entry(l3c, &l3->channellist, list) {
+		if (l3c->lchan == ch)
+			return(l3c);
+	}
+	return(NULL);
+}
+
+x25_channel_t *
+X25_get_channel4NCCI(x25_l3_t *l3, __u32 addr)
+{
+	x25_channel_t	*l3c;
+
+	list_for_each_entry(l3c, &l3->channellist, list) {
+		if ((l3c->ncci & 0xffff0000) == (addr & 0xffff0000))
+			return(l3c);
+	}
+	return(NULL);
+}
+
+int
+X25sendL4skb(x25_channel_t *l3c, x25_l3_t *l3, __u32 addr, int prim, int dinfo, struct sk_buff *skb)
+{
+	skb_push(skb, 4);
+	if (l3c)
+		capimsg_setu32(skb->data, 0, l3c->ncci);
+	else
+		capimsg_setu32(skb->data, 0, addr);
+	return(mISDN_queueup_newhead(&l3->inst, 0, prim, dinfo, skb));		 
+}
+
+int
+X25sendL4frame(x25_channel_t *l3c, x25_l3_t *l3, int prim, int flags, int len, void *arg)
+{
+	struct sk_buff	*skb;
+	u_char		*p;
+	int		ret;
+
+	skb = alloc_stack_skb(len + X25_MINSIZE + 2, l3->up_headerlen);
+	if (!skb)
+		return(-ENOMEM);
+
+	capimsg_setu32(skb_put(skb, 4), 0, l3c->ncci);
+	switch(prim) {
+		case CAPI_DISCONNECT_B3_IND:
+			capimsg_setu16(skb_put(skb, 2), 0, flags & 0xffff);
+		case CAPI_CONNECT_B3_IND:
+		case CAPI_CONNECT_B3_ACTIVE_IND:
+		case CAPI_RESET_B3_IND:
+			if (len) {
+				p = skb_put(skb, len + 4);
+				*p++ = len +3;
+				if (flags & 0x10000)
+					*p++ = 1;
+				else
+					*p++ = 0;
+				*p++ = l3c->lchan >> 8;
+				*p++ = l3c->lchan & 0xff;
+				memcpy(p, arg, len);
+			} else {
+				p = skb_put(skb, 1);
+				*p = 0;
+			}
+			break;
+		default:
+			dev_kfree_skb(skb);
+			return(-EINVAL);
+	}
+	ret = mISDN_queueup_newhead(&l3->inst, 0, prim, 0, skb);
+	if (ret) {
+		printk(KERN_WARNING "%s: up error %d\n", __FUNCTION__, ret);
+		dev_kfree_skb(skb);
+	}
+	return(ret);
+}
+
+static int
+confq_len(x25_channel_t *l3c)
+{
+	int		i,n = 0;
+	x25_ConfQueue_t	*cq = l3c->confq;
+
+	for (i = 0; i < l3c->lwin; i++)
+		if (cq[i].PktId)
+			n++;
+	return(n);
+}
+
+static inline x25_ConfQueue_t *
+get_free_confentry(x25_channel_t *l3c)
+{
+	int		i;
+	x25_ConfQueue_t	*cq = l3c->confq;
+
+	for (i = 0; i < l3c->lwin; i++) {
+		if (!cq->PktId)
+			break;
+		cq++;
+	}
+	if (i == l3c->lwin)
+		return(NULL);
+	return(cq);
+}
+
+int
+X25_invoke_sending(x25_channel_t *l3c)
+{
+	int		l,n = 0;
+	x25_ConfQueue_t	*cq;
+	struct sk_buff	*skb, *nskb;
+	u_char		flg;
+
+	if (!X25_cansend(l3c))
+		return(0);
+	cq = get_free_confentry(l3c);
+	skb = skb_dequeue(&l3c->dataq);
+	while(cq && skb) {
+		mISDN_head_t    *hh = mISDN_HEAD_P(skb);
+
+		cq->MsgId = hh->dinfo;
+		hh++;
+		cq->DataHandle = hh->prim;
+		nskb = skb_clone(skb, GFP_ATOMIC);
+		if (!nskb) {
+			skb_queue_head(&l3c->dataq, skb);
+			break;
+		}
+		cq->skb = skb;
+		cq->PktId = 0x10000 | l3c->ps;
+		flg = (hh->dinfo & CAPI_FLAG_DELIVERCONF) ? X25_GFI_DBIT : 0;
+		if (hh->dinfo & CAPI_FLAG_QUALIFIER)
+			flg |= X25_GFI_QBIT;
+		if (hh->dinfo & CAPI_FLAG_MOREDATA)
+			flg |= X25_MBIT;
+		l = 3;
+		if (test_bit(X25_STATE_MOD128, &l3c->state))
+			l++;
+		else if (test_bit(X25_STATE_MOD32768, &l3c->state))
+			l += 4;
+		skb_push(nskb, l);
+		if (l != X25_add_header(l3c, l3c->l3, X25_PTYPE_DATA, nskb->data, flg))
+			int_error();
+		if (l3c->l3->l2l3m.state == ST_LL_ESTAB)
+			X25_l3down(l3c->l3, DL_DATA_REQ, X25_next_id(l3c->l3), nskb);
+		else {
+			mISDN_sethead(DL_DATA_REQ, X25_next_id(l3c->l3), nskb);	
+			skb_queue_tail(&l3c->l3->downq, nskb);
+			break;
+		}
+		cq = get_free_confentry(l3c);
+		skb = skb_dequeue(&l3c->dataq);
+		n++;
+	}
+	return(n);
+}
+
+__u16
+x25_data_b3_req(x25_channel_t *l3c, int dinfo, struct sk_buff *skb)
+{
+	__u16		size;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+
+	if (!l3c)
+		return(0x2002);
+	if (skb->len < 10)
+		return(0x2007);
+	if ((confq_len(l3c) + skb_queue_len(&l3c->dataq)) > 7)
+		return(CAPI_SENDQUEUEFULL);
+	if ((l3c->x25p.state != ST_P4) && (l3c->x25d.state != ST_D1))
+		return(0x2001);
+
+	size =  CAPIMSG_U16(skb->data, 4);
+
+	/* we save DataHandle and Flags in a area after normal mISDN_HEAD */ 
+	hh++;
+	hh->prim = CAPIMSG_U16(skb->data, 6);
+	hh->dinfo = CAPIMSG_U16(skb->data, 8);
+	/* the data begins behind the header, we don't use Data32/Data64 here */
+	if ((skb->len - size) == 18)
+		skb_pull(skb, 18);
+	else if ((skb->len - size) == 10) // old format
+		skb_pull(skb, 10);
+	else
+		return(0x2007);
+	if (hh->dinfo & CAPI_FLAG_EXPEDITED) { // TODO Interrupt packet
+	}
+
+	skb_queue_tail(&l3c->dataq, skb);
+	X25_invoke_sending(l3c);
+	return(0);
+}
+
+int
+x25_data_b3_resp(x25_channel_t *l3c, int dinfo, struct sk_buff *skb)
+{
+	int		i, m = 8;
+
+	if (!l3c)
+		return(-ENODEV);
+
+	i = CAPIMSG_U16(skb->data, 0);
+	dev_kfree_skb(skb);
+	if (i >= CAPI_MAXDATAWINDOW) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (l3c->recv_handles[i] == 0) {
+		int_error();
+		return(-EINVAL);
+	}
+	if (l3c->recv_handles[i] & CAPI_FLAG_DELIVERCONF) {
+		if (test_bit(X25_STATE_MOD32768, &l3c->state))
+			m = 32768;
+		else if (test_bit(X25_STATE_MOD128, &l3c->state))
+			m = 128;
+		l3c->rps++;
+		if (l3c->rps >= m)
+			l3c->rps = 0;
+		l3c->recv_handles[i] = 0;
+		i = 0;
+		if (X25_cansend(l3c) && skb_queue_len(&l3c->dataq))
+			X25_invoke_sending(l3c);
+		else {
+			i = 1;
+			X25sendL3frame(l3c, l3c->l3, X25_PTYPE_RR, 0, NULL);
+		}
+	} else {
+		l3c->recv_handles[i] = 0;
+		i = 0;
+	}
+	if (test_and_clear_bit(X25_STATE_DTE_RNR, &l3c->state)) {
+		if (!i)
+			X25sendL3frame(l3c, l3c->l3, X25_PTYPE_RR, 0, NULL);
+	}	
+	return(0);
+}
+
+int
+X25_l3_init(void)
+{
+	llfsm.state_count = LL_STATE_COUNT;
+	llfsm.event_count = LL_EVENT_COUNT;
+	llfsm.strEvent = strLLEvent;
+	llfsm.strState = strLLState;
+	mISDN_FsmNew(&llfsm, LLFnList, LL_FN_COUNT);
+	return(0);
+}
+
+void
+X25_l3_cleanup(void)
+{
+	mISDN_FsmFree(&llfsm);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_l3.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_l3.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/x25_l3.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,281 @@
+/* $Id: x25_l3.h,v 1.6 2006/03/22 18:28:33 keil Exp $
+ *
+ * Layer 3 X.25 defines
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+#ifndef _L3_X25_H
+#define _L3_X25_H
+#include "m_capi.h"
+
+typedef struct _x25_l3		x25_l3_t;
+typedef struct _x25_channel	x25_channel_t;
+typedef struct _x25_B3_cfg	x25_B3_cfg_t;
+typedef struct _x25_ncpi	x25_ncpi_t;
+typedef struct _x25_ConfQueue	x25_ConfQueue_t;
+
+#define DEBUG_L3X25_WARN	0x0001
+#define	DEBUG_L3X25_MGR		0x1000
+
+struct _x25_B3_cfg {
+	__u16	LIC;
+	__u16	HIC;
+	__u16	LTC;
+	__u16	HTC;
+	__u16	LOC;
+	__u16	HOC;
+	__u16	modulo;
+	__u16	winsize;
+};
+
+#define DEFAULT_X25_B3_CFG	{0, 0, 1, 1, 0, 0, 8, 2}
+
+struct _x25_ncpi {
+	__u8	len;
+	__u8	Flags;
+	__u8	Group;
+	__u8	Channel;
+	__u8	Contens[4]; /* Note this can be less/more bytes in use */ 
+} __attribute__((packed));
+
+struct _x25_ConfQueue { 
+	__u32		PktId; 
+	__u16		DataHandle;
+	__u16		MsgId; 
+	struct sk_buff	*skb;
+};
+
+struct _x25_l3 {
+	struct list_head	list;
+	mISDNinstance_t		inst;
+	struct list_head	channellist;
+	struct FsmInst		l2l3m;
+	struct FsmInst		x25r;
+	struct FsmTimer		TR;
+	int			TRval;
+	int			TRrep;
+	int			entity;
+	int			next_id;
+	struct sk_buff_head	downq;
+	int			down_headerlen;
+	int			up_headerlen;
+	int			maxdatalen;
+	x25_B3_cfg_t		B3cfg;
+	u_long			state;
+	u_int			debug;
+	u_char			cause[2];
+};
+
+struct _x25_channel {
+	struct list_head	list;
+	x25_l3_t		*l3;
+	struct FsmInst		x25p;
+	struct FsmInst		x25d;
+	struct FsmTimer		TP;
+	int			TPval;
+	int			TPrep;
+	struct FsmTimer		TD;
+	int			TDval;
+	int			TDrep;
+	__u32			ncci;
+	u_char			*ncpi_data;
+	u_int			ncpi_len;
+	u_long			state;
+	u_int			debug;
+	u_int			pr;
+	u_int			ps;
+	u_int			rps;
+	u_int			lwin;
+	u_int			rwin;
+	u_int			datasize;
+	struct sk_buff_head	dataq;
+	x25_ConfQueue_t		*confq;
+	u_int			recv_handles[CAPI_MAXDATAWINDOW];
+	__u16			lchan;
+	u_char			cause[2];
+};
+
+#define X25_CHANNEL_INCOMING	1
+#define X25_CHANNEL_OUTGOING	2
+
+#define X25_STATE_ORGINATE	0
+#define X25_STATE_DCE		1
+#define X25_STATE_DTEDTE	2
+#define X25_STATE_PERMANENT	3
+#define X25_STATE_MOD128	4
+#define X25_STATE_MOD32768	5
+#define X25_STATE_ABIT		6
+#define X25_STATE_DBIT		7
+#define X25_STATE_ESTABLISH	16
+#define X25_STATE_DXE_INTSENT	17
+#define X25_STATE_DTE_INTSENT   18
+#define X25_STATE_DXE_RNR	19
+#define X25_STATE_DTE_RNR	20
+
+#define X25_MINSIZE		8
+
+#define X25_GFI_ABIT		0x80
+#define X25_GFI_DBIT		0x40
+#define X25_GFI_QBIT		0x80
+
+#define X25_MBIT		0x01
+#define X25_MBIT_MOD8		0x10
+
+#define CAPI_FLAG_QUALIFIER	0x01
+#define CAPI_FLAG_MOREDATA	0x02
+#define CAPI_FLAG_DELIVERCONF	0x04
+#define CAPI_FLAG_EXPEDITED	0x08
+
+#define X25_PTYPE_CALL		0x0b
+#define X25_PTYPE_CALL_CNF	0x0f
+#define X25_PTYPE_CLEAR		0x13
+#define X25_PTYPE_CLEAR_CNF	0x17
+#define X25_PTYPE_INTERRUPT	0x23
+#define X25_PTYPE_INTERRUPT_CNF	0x27
+#define X25_PTYPE_DATA		0x00
+#define X25_PTYPE_RR		0x01
+#define X25_PTYPE_RNR		0x05
+#define X25_PTYPE_REJ		0x09
+#define X25_PTYPE_RESET		0x1f
+#define X25_PTYPE_RESET_CNF	0x1b
+#define X25_PTYPE_RESTART	0xfb
+#define X25_PTYPE_RESTART_CNF	0xff
+#define X25_PTYPE_REGISTER	0xf3
+#define X25_PTYPE_REGISTER_CNF	0xf7
+#define X25_PTYPE_DIAGNOSTIC	0xf1
+#define X25_PTYPE_NOTYPE	0x7F
+
+#define	T10_VALUE		60000
+#define T11_VALUE		180000
+#define	T12_VALUE		60000
+#define T13_VALUE		60000
+#define	T20_VALUE		180000
+#define T21_VALUE		200000
+#define	T22_VALUE		180000
+#define T23_VALUE		180000
+#define T24_VALUE		60000
+#define T25_VALUE		200000
+#define T26_VALUE		180000
+#define T27_VALUE		60000
+#define T28_VALUE		300000
+
+
+#define R20_VALUE		1
+#define R22_VALUE		1
+#define R23_VALUE		1
+#define R25_VALUE		0
+#define R27_VALUE		0
+#define R28_VALUE		1
+
+#define X25_ERRCODE_DISCARD	0x0100
+
+/* LinkLayer (L2) maintained by L3 statemachine */
+enum {
+	EV_L3_ESTABLISH_REQ,
+	EV_LL_ESTABLISH_IND,
+	EV_LL_ESTABLISH_CNF,
+	EV_L3_RELEASE_REQ,
+	EV_LL_RELEASE_CNF,
+	EV_LL_RELEASE_IND,
+};
+#define LL_EVENT_COUNT	(EV_LL_RELEASE_IND+1)
+
+/* X.25 Restart state machine */
+enum {
+	ST_R0,
+	ST_R1,
+	ST_R2,
+	ST_R3,
+};
+#define R_STATE_COUNT	(ST_R3+1)
+extern char *X25strRState[];
+
+enum {
+	EV_LL_READY,
+	EV_L3_RESTART_REQ,
+ 	EV_L2_RESTART,
+	EV_L2_RESTART_CNF,
+	EV_L3_RESTART_TOUT,
+};
+#define R_EVENT_COUNT	(EV_L3_RESTART_TOUT+1)
+extern char *X25strREvent[];
+
+/* X.25 connection state machine */
+enum {
+	ST_P0,
+	ST_P1,
+	ST_P2,
+	ST_P3,
+	ST_P4,
+	ST_P5,
+	ST_P6,
+	ST_P7,
+};
+#define P_STATE_COUNT	(ST_P7+1)
+extern char *X25strPState[];
+
+enum {
+	EV_L3_READY,
+	EV_L3_OUTGOING_CALL,
+	EV_L2_INCOMING_CALL,
+	EV_L2_CALL_CNF,
+	EV_L3_CALL_ACCEPT,
+	EV_L3_CLEARING,
+	EV_L2_CLEAR,
+	EV_L2_CLEAR_CNF,
+	EV_L2_INVALPKT,
+	EV_L3_CALL_TOUT,
+	EV_L3_CLEAR_TOUT,
+};
+#define P_EVENT_COUNT	(EV_L3_CLEAR_TOUT+1)
+extern char *X25strPEvent[];
+
+/* X.25 Flowcontrol state machine */
+enum {
+	ST_D0,
+	ST_D1,
+	ST_D2,
+	ST_D3,
+};
+#define D_STATE_COUNT	(ST_D3+1)
+extern char *X25strDState[];
+
+enum {
+	EV_L3_CONNECT,
+ 	EV_L3_RESETING,
+	EV_L2_RESET,
+	EV_L2_RESET_CNF,
+	EV_L3_RESET_TOUT,
+};
+#define D_EVENT_COUNT	(EV_L3_RESET_TOUT+1)
+extern char *X25strDEvent[];
+
+extern x25_channel_t	*X25_get_channel(x25_l3_t *, __u16);
+extern x25_channel_t	*X25_get_channel4NCCI(x25_l3_t *, __u32);
+extern int		X25_reset_channel(x25_channel_t *, struct sk_buff *);
+extern int		X25_restart(x25_l3_t *);
+extern int		X25_get_header(x25_l3_t *, struct sk_buff *, u_char *, __u16 *, u_char *);
+extern void		X25_release_channel(x25_channel_t *);
+extern void		X25_release_l3(x25_l3_t *);
+extern int		X25_realloc_ncpi_data(x25_channel_t *, int, u_char *);
+extern int		new_x25_channel(x25_l3_t *, x25_channel_t **, __u16, int, u_char *);
+extern int		new_x25_l3(x25_l3_t **, mISDNstack_t *, mISDN_pid_t *, mISDNobject_t *, int, if_func_t *);
+extern int		X25_next_id(x25_l3_t *);
+extern int		X25_add_header(x25_channel_t *, x25_l3_t *, u_char , u_char *, u_char);
+extern int		X25sendL3frame(x25_channel_t *, x25_l3_t *, u_char, int, void *);
+extern int		X25sendL4frame(x25_channel_t *, x25_l3_t *, int, int, int, void *);
+extern int		X25sendL4skb(x25_channel_t *, x25_l3_t *, __u32, int, int, struct sk_buff *);
+extern void		X25_send_diagnostic(x25_l3_t *, struct sk_buff *, int, int);
+extern int		X25_l3down(x25_l3_t *, u_int, u_int, struct sk_buff *);
+extern int		X25_l3_init(void);
+extern void		X25_l3_cleanup(void);
+extern int		X25_get_and_test_pr(x25_channel_t *, u_char, struct sk_buff *);
+extern int		X25_get_and_test_ps(x25_channel_t *, u_char, struct sk_buff *);
+extern int		X25_cansend(x25_channel_t *);
+extern __u16		x25_data_b3_req(x25_channel_t *, int, struct sk_buff *);
+extern int		x25_data_b3_resp(x25_channel_t *, int, struct sk_buff *);
+extern int		X25_invoke_sending(x25_channel_t *);
+extern int		X25_receive_data(x25_channel_t *, int, int, struct sk_buff *);
+
+#endif

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc24succ.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc24succ.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc24succ.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,2126 @@
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/*  (C) Copyright Cologne Chip AG, 2006                                              */
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+
+/*                                                                                   */
+/*  File name:     xhfc24succ.h                                                      */
+/*  File content:  This file contains the XHFC-2S4U / XHFC-4SU register definitions. */
+/*  Creation date: 22.02.2006 13:14                                                  */
+/*  Creator:       Genero 3.4                                                        */
+/*  Data base:     HFC XML 1.6 for XHFC-1SU, XHFC-2SU, XHFC-2S4U and XHFC-4SU        */
+/*  Address range: 0x00 - 0xFF                                                       */
+/*                                                                                   */
+/*  The information presented can not be considered as assured characteristics.      */
+/*  Data can change without notice. Please check version numbers in case of doubt.   */
+/*                                                                                   */
+/*  For further information or questions please contact support at CologneChip.com      */
+/*                                                                                   */
+/*                                                                                   */
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/*  WARNING: This file has been generated automatically and should not be            */
+/*           changed to maintain compatibility with later versions.                  */
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+
+
+#ifndef _XHFC24SUCC_H_
+#define _XHFC24SUCC_H_
+
+
+typedef unsigned char BYTE;
+
+typedef BYTE REGWORD;       // maximum register length (standard)
+typedef BYTE REGADDR;       // address width
+
+
+
+typedef enum {no=0, yes} REGBOOL;
+
+
+typedef enum
+{
+	// register and bitmap access modes:
+	writeonly=0,		// write only
+	readonly,		// read only
+	readwrite,		// read/write
+	// following modes only for mixed mode registers:
+	readwrite_write,	// read/write and write only
+	readwrite_read,		// read/write and read only
+	write_read,		// write only and read only
+	readwrite_write_read	// read/write, write only and read only
+} ACCESSMODE;
+
+
+
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/* common chip information:                                                          */
+/*___________________________________________________________________________________*/
+
+	#define CHIP_NAME_2S4U		"XHFC-2S4U"
+	#define CHIP_NAME_4SU		"XHFC-4SU"
+	#define CHIP_TITLE_2S4U		"ISDN HDLC FIFO controller 2 S/T interfaces combined with 4 Up interfaces (Universal ISDN Ports)"
+	#define CHIP_TITLE_4SU		"ISDN HDLC FIFO controller with 4 S/T interfaces combined with 4 Up interfaces (Universal ISDN Ports)"
+	#define CHIP_MANUFACTURER	"Cologne Chip"
+	#define CHIP_ID_2S4U		0x62
+	#define CHIP_ID_4SU		0x63
+	#define CHIP_REGISTER_COUNT	122
+	#define CHIP_DATABASE		"Version HFC-XMLHFC XML 1.6 for XHFC-1SU, XHFC-2SU, XHFC-2S4U and XHFC-4SU - GeneroGenero 3.4 "
+
+// This register file can also be used for XHFC-2SU and XHFC-1SU programming.
+// For this reason these chip names, IDs and titles are defined here as well:
+
+	#define CHIP_NAME_2SU		"XHFC-2SU"
+	#define CHIP_TITLE_2SU		"ISDN HDLC FIFO controller with 2 combined S/T and Up Interfaces"
+	#define CHIP_ID_2SU		0x61
+
+	#define CHIP_NAME_1SU		"XHFC-1SU"
+	#define CHIP_TITLE_1SU		"ISDN HDLC FIFO controller with a combined S/T and Up Interface"
+	#define CHIP_ID_1SU		0x60
+
+
+
+
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/*  Begin of XHFC-2S4U / XHFC-4SU register definitions.                              */
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+
+#define R_CIRM 0x00 // register access
+	#define M_CLK_OFF 0x01 // bitmap mask (1bit)
+	#define M_WAIT_PROC 0x02 // bitmap mask (1bit)
+	#define M_WAIT_REG 0x04 // bitmap mask (1bit)
+	#define M_SRES 0x08 // bitmap mask (1bit)
+	#define M_HFC_RES 0x10 // bitmap mask (1bit)
+	#define M_PCM_RES 0x20 // bitmap mask (1bit)
+	#define M_SU_RES 0x40 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_clk_off:1;
+		REGWORD v_wait_proc:1;
+		REGWORD v_wait_reg:1;
+		REGWORD v_sres:1;
+		REGWORD v_hfc_res:1;
+		REGWORD v_pcm_res:1;
+		REGWORD v_su_res:1;
+		REGWORD reserved_0:1;
+	} bit_r_cirm; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_cirm bit;} reg_r_cirm; // register and bitmap access
+
+
+#define R_CTRL 0x01 // register access
+	#define M_FIFO_LPRIO 0x02 // bitmap mask (1bit)
+	#define M_NT_SYNC 0x08 // bitmap mask (1bit)
+	#define M_OSC_OFF 0x20 // bitmap mask (1bit)
+	#define M_SU_CLK 0xC0 // bitmap mask (2bit)
+		#define M1_SU_CLK 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_1:1;
+		REGWORD v_fifo_lprio:1;
+		REGWORD reserved_2:1;
+		REGWORD v_nt_sync:1;
+		REGWORD reserved_3:1;
+		REGWORD v_osc_off:1;
+		REGWORD v_su_clk:2;
+	} bit_r_ctrl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ctrl bit;} reg_r_ctrl; // register and bitmap access
+
+
+#define R_CLK_CFG 0x02 // register access
+	#define M_CLK_PLL 0x01 // bitmap mask (1bit)
+	#define M_CLKO_HI 0x02 // bitmap mask (1bit)
+	#define M_CLKO_PLL 0x04 // bitmap mask (1bit)
+	#define M_PCM_CLK 0x20 // bitmap mask (1bit)
+	#define M_CLKO_OFF 0x40 // bitmap mask (1bit)
+	#define M_CLK_F1 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_clk_pll:1;
+		REGWORD v_clko_hi:1;
+		REGWORD v_clko_pll:1;
+		REGWORD reserved_4:2;
+		REGWORD v_pcm_clk:1;
+		REGWORD v_clko_off:1;
+		REGWORD v_clk_f1:1;
+	} bit_r_clk_cfg; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_clk_cfg bit;} reg_r_clk_cfg; // register and bitmap access
+
+
+#define A_Z1 0x04 // register access
+	#define M_Z1 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_z1:8;
+	} bit_a_z1; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_z1 bit;} reg_a_z1; // register and bitmap access
+
+
+#define A_Z2 0x06 // register access
+	#define M_Z2 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_z2:8;
+	} bit_a_z2; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_z2 bit;} reg_a_z2; // register and bitmap access
+
+
+#define R_RAM_ADDR 0x08 // register access
+	#define M_RAM_ADDR0 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ram_addr0:8;
+	} bit_r_ram_addr; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ram_addr bit;} reg_r_ram_addr; // register and bitmap access
+
+
+#define R_RAM_CTRL 0x09 // register access
+	#define M_RAM_ADDR1 0x0F // bitmap mask (4bit)
+		#define M1_RAM_ADDR1 0x01
+	#define M_ADDR_RES 0x40 // bitmap mask (1bit)
+	#define M_ADDR_INC 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ram_addr1:4;
+		REGWORD reserved_5:2;
+		REGWORD v_addr_res:1;
+		REGWORD v_addr_inc:1;
+	} bit_r_ram_ctrl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ram_ctrl bit;} reg_r_ram_ctrl; // register and bitmap access
+
+
+#define R_FIRST_FIFO 0x0B // register access
+	#define M_FIRST_FIFO_DIR 0x01 // bitmap mask (1bit)
+	#define M_FIRST_FIFO_NUM 0x1E // bitmap mask (4bit)
+		#define M1_FIRST_FIFO_NUM 0x02
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_first_fifo_dir:1;
+		REGWORD v_first_fifo_num:4;
+		REGWORD reserved_6:3;
+	} bit_r_first_fifo; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_first_fifo bit;} reg_r_first_fifo; // register and bitmap access
+
+
+#define R_FIFO_THRES 0x0C // register access
+	#define M_THRES_TX 0x0F // bitmap mask (4bit)
+		#define M1_THRES_TX 0x01
+	#define M_THRES_RX 0xF0 // bitmap mask (4bit)
+		#define M1_THRES_RX 0x10
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_thres_tx:4;
+		REGWORD v_thres_rx:4;
+	} bit_r_fifo_thres; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo_thres bit;} reg_r_fifo_thres; // register and bitmap access
+
+
+#define A_F1 0x0C // register access
+	#define M_F1 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_f1:8;
+	} bit_a_f1; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_f1 bit;} reg_a_f1; // register and bitmap access
+
+
+#define R_FIFO_MD 0x0D // register access
+	#define M_FIFO_MD 0x03 // bitmap mask (2bit)
+		#define M1_FIFO_MD 0x01
+	#define M_DF_MD 0x0C // bitmap mask (2bit)
+		#define M1_DF_MD 0x04
+	#define M_UNIDIR_MD 0x10 // bitmap mask (1bit)
+	#define M_UNIDIR_RX 0x20 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_md:2;
+		REGWORD v_df_md:2;
+		REGWORD v_unidir_md:1;
+		REGWORD v_unidir_rx:1;
+		REGWORD reserved_7:2;
+	} bit_r_fifo_md; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo_md bit;} reg_r_fifo_md; // register and bitmap access
+
+
+#define A_F2 0x0D // register access
+	#define M_F2 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_f2:8;
+	} bit_a_f2; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_f2 bit;} reg_a_f2; // register and bitmap access
+
+
+#define A_INC_RES_FIFO 0x0E // register access
+	#define M_INC_F 0x01 // bitmap mask (1bit)
+	#define M_RES_FIFO 0x02 // bitmap mask (1bit)
+	#define M_RES_LOST 0x04 // bitmap mask (1bit)
+	#define M_RES_FIFO_ERR 0x08 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_inc_f:1;
+		REGWORD v_res_fifo:1;
+		REGWORD v_res_lost:1;
+		REGWORD v_res_fifo_err:1;
+		REGWORD reserved_8:4;
+	} bit_a_inc_res_fifo; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_inc_res_fifo bit;} reg_a_inc_res_fifo; // register and bitmap access
+
+
+#define A_FIFO_STA 0x0E // register access
+	#define M_FIFO_ERR 0x01 // bitmap mask (1bit)
+	#define M_ABO_DONE 0x10 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_err:1;
+		REGWORD reserved_11:3;
+		REGWORD v_abo_done:1;
+		REGWORD reserved_12:3;
+	} bit_a_fifo_sta; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_fifo_sta bit;} reg_a_fifo_sta; // register and bitmap access
+
+
+#define R_FSM_IDX 0x0F // register access
+	#define M_IDX 0x1F // bitmap mask (5bit)
+		#define M1_IDX 0x01
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_idx:5;
+		REGWORD reserved_10:3;
+	} bit_r_fsm_idx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fsm_idx bit;} reg_r_fsm_idx; // register and bitmap access
+	#define IDX_FSM_IDX 0x01 // index value selecting this multi-register
+
+
+#define R_FIFO 0x0F // register access
+	#define M_FIFO_DIR 0x01 // bitmap mask (1bit)
+	#define M_FIFO_NUM 0x1E // bitmap mask (4bit)
+		#define M1_FIFO_NUM 0x02
+	#define M_REV 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_dir:1;
+		REGWORD v_fifo_num:4;
+		REGWORD reserved_9:2;
+		REGWORD v_rev:1;
+	} bit_r_fifo; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo bit;} reg_r_fifo; // register and bitmap access
+	#define IDX_FIFO 0x00 // index value selecting this multi-register
+
+
+#define R_SLOT 0x10 // register access
+	#define M_SL_DIR 0x01 // bitmap mask (1bit)
+	#define M_SL_NUM 0xFE // bitmap mask (7bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sl_dir:1;
+		REGWORD v_sl_num:7;
+	} bit_r_slot; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_slot bit;} reg_r_slot; // register and bitmap access
+
+
+#define R_IRQ_OVIEW 0x10 // register access
+	#define M_FIFO_BL0_IRQ 0x01 // bitmap mask (1bit)
+	#define M_FIFO_BL1_IRQ 0x02 // bitmap mask (1bit)
+	#define M_FIFO_BL2_IRQ 0x04 // bitmap mask (1bit)
+	#define M_FIFO_BL3_IRQ 0x08 // bitmap mask (1bit)
+	#define M_MISC_IRQ 0x10 // bitmap mask (1bit)
+	#define M_CH_IRQ 0x20 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_bl0_irq:1;
+		REGWORD v_fifo_bl1_irq:1;
+		REGWORD v_fifo_bl2_irq:1;
+		REGWORD v_fifo_bl3_irq:1;
+		REGWORD v_misc_irq:1;
+		REGWORD v_ch_irq:1;
+		REGWORD reserved_19:2;
+	} bit_r_irq_oview; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_irq_oview bit;} reg_r_irq_oview; // register and bitmap access
+
+
+#define R_MISC_IRQMSK 0x11 // register access
+	#define M_SLIP_IRQMSK 0x01 // bitmap mask (1bit)
+	#define M_TI_IRQMSK 0x02 // bitmap mask (1bit)
+	#define M_PROC_IRQMSK 0x04 // bitmap mask (1bit)
+	#define M_CI_IRQMSK 0x10 // bitmap mask (1bit)
+	#define M_WAK_IRQMSK 0x20 // bitmap mask (1bit)
+	#define M_MON_TX_IRQMSK 0x40 // bitmap mask (1bit)
+	#define M_MON_RX_IRQMSK 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_slip_irqmsk:1;
+		REGWORD v_ti_irqmsk:1;
+		REGWORD v_proc_irqmsk:1;
+		REGWORD reserved_13:1;
+		REGWORD v_ci_irqmsk:1;
+		REGWORD v_wak_irqmsk:1;
+		REGWORD v_mon_tx_irqmsk:1;
+		REGWORD v_mon_rx_irqmsk:1;
+	} bit_r_misc_irqmsk; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_misc_irqmsk bit;} reg_r_misc_irqmsk; // register and bitmap access
+
+
+#define R_MISC_IRQ 0x11 // register access
+	#define M_SLIP_IRQ 0x01 // bitmap mask (1bit)
+	#define M_TI_IRQ 0x02 // bitmap mask (1bit)
+	#define M_PROC_IRQ 0x04 // bitmap mask (1bit)
+	#define M_CI_IRQ 0x10 // bitmap mask (1bit)
+	#define M_WAK_IRQ 0x20 // bitmap mask (1bit)
+	#define M_MON_TX_IRQ 0x40 // bitmap mask (1bit)
+	#define M_MON_RX_IRQ 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_slip_irq:1;
+		REGWORD v_ti_irq:1;
+		REGWORD v_proc_irq:1;
+		REGWORD reserved_20:1;
+		REGWORD v_ci_irq:1;
+		REGWORD v_wak_irq:1;
+		REGWORD v_mon_tx_irq:1;
+		REGWORD v_mon_rx_irq:1;
+	} bit_r_misc_irq; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_misc_irq bit;} reg_r_misc_irq; // register and bitmap access
+
+
+#define R_SU_IRQ 0x12 // register access
+	#define M_SU0_IRQ 0x01 // bitmap mask (1bit)
+	#define M_SU1_IRQ 0x02 // bitmap mask (1bit)
+	#define M_SU2_IRQ 0x04 // bitmap mask (1bit)
+	#define M_SU3_IRQ 0x08 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_su0_irq:1;
+		REGWORD v_su1_irq:1;
+		REGWORD v_su2_irq:1;
+		REGWORD v_su3_irq:1;
+		REGWORD reserved_27:4;
+	} bit_r_su_irq; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_su_irq bit;} reg_r_su_irq; // register and bitmap access
+
+
+#define R_SU_IRQMSK 0x12 // register access
+	#define M_SU0_IRQMSK 0x01 // bitmap mask (1bit)
+	#define M_SU1_IRQMSK 0x02 // bitmap mask (1bit)
+	#define M_SU2_IRQMSK 0x04 // bitmap mask (1bit)
+	#define M_SU3_IRQMSK 0x08 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_su0_irqmsk:1;
+		REGWORD v_su1_irqmsk:1;
+		REGWORD v_su2_irqmsk:1;
+		REGWORD v_su3_irqmsk:1;
+		REGWORD reserved_29:4;
+	} bit_r_su_irqmsk; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_su_irqmsk bit;} reg_r_su_irqmsk; // register and bitmap access
+
+
+#define R_AF0_OVIEW 0x13 // register access
+	#define M_SU0_AF0 0x01 // bitmap mask (1bit)
+	#define M_SU1_AF0 0x02 // bitmap mask (1bit)
+	#define M_SU2_AF0 0x04 // bitmap mask (1bit)
+	#define M_SU3_AF0 0x08 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_su0_af0:1;
+		REGWORD v_su1_af0:1;
+		REGWORD v_su2_af0:1;
+		REGWORD v_su3_af0:1;
+		REGWORD reserved_28:4;
+	} bit_r_af0_oview; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_af0_oview bit;} reg_r_af0_oview; // register and bitmap access
+
+
+#define R_IRQ_CTRL 0x13 // register access
+	#define M_FIFO_IRQ_EN 0x01 // bitmap mask (1bit)
+	#define M_GLOB_IRQ_EN 0x08 // bitmap mask (1bit)
+	#define M_IRQ_POL 0x10 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_irq_en:1;
+		REGWORD reserved_14:2;
+		REGWORD v_glob_irq_en:1;
+		REGWORD v_irq_pol:1;
+		REGWORD reserved_15:3;
+	} bit_r_irq_ctrl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_irq_ctrl bit;} reg_r_irq_ctrl; // register and bitmap access
+
+
+#define A_USAGE 0x14 // register access
+	#define M_USAGE 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_usage:8;
+	} bit_a_usage; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_usage bit;} reg_a_usage; // register and bitmap access
+
+
+#define R_PCM_MD0 0x14 // register access
+	#define M_PCM_MD 0x01 // bitmap mask (1bit)
+	#define M_C4_POL 0x02 // bitmap mask (1bit)
+	#define M_F0_NEG 0x04 // bitmap mask (1bit)
+	#define M_F0_LEN 0x08 // bitmap mask (1bit)
+	#define M_PCM_IDX 0xF0 // bitmap mask (4bit)
+		#define M1_PCM_IDX 0x10
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_pcm_md:1;
+		REGWORD v_c4_pol:1;
+		REGWORD v_f0_neg:1;
+		REGWORD v_f0_len:1;
+		REGWORD v_pcm_idx:4;
+	} bit_r_pcm_md0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pcm_md0 bit;} reg_r_pcm_md0; // register and bitmap access
+
+
+#define R_SL_SEL0 0x15 // register access
+	#define M_SL_SEL0 0x7F // bitmap mask (7bit)
+	#define M_SH_SEL0 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sl_sel0:7;
+		REGWORD v_sh_sel0:1;
+	} bit_r_sl_sel0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_sl_sel0 bit;} reg_r_sl_sel0; // register and bitmap access
+	#define IDX_SL_SEL0 0x00 // index value selecting this multi-register
+
+
+#define R_SL_SEL1 0x15 // register access
+	#define M_SL_SEL1 0x7F // bitmap mask (7bit)
+	#define M_SH_SEL1 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sl_sel1:7;
+		REGWORD v_sh_sel1:1;
+	} bit_r_sl_sel1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_sl_sel1 bit;} reg_r_sl_sel1; // register and bitmap access
+	#define IDX_SL_SEL1 0x01 // index value selecting this multi-register
+
+
+#define R_SL_SEL7 0x15 // register access
+	#define M_SL_SEL7 0x7F // bitmap mask (7bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sl_sel7:7;
+		REGWORD reserved_30:1;
+	} bit_r_sl_sel7; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_sl_sel7 bit;} reg_r_sl_sel7; // register and bitmap access
+	#define IDX_SL_SEL7 0x07 // index value selecting this multi-register
+
+
+#define R_MSS0 0x15 // register access
+	#define M_MSS_MOD 0x01 // bitmap mask (1bit)
+	#define M_MSS_MOD_REP 0x02 // bitmap mask (1bit)
+	#define M_MSS_SRC_EN 0x04 // bitmap mask (1bit)
+	#define M_MSS_SRC_GRD 0x08 // bitmap mask (1bit)
+	#define M_MSS_OUT_EN 0x10 // bitmap mask (1bit)
+	#define M_MSS_OUT_REP 0x20 // bitmap mask (1bit)
+	#define M_MSS_SRC 0xC0 // bitmap mask (2bit)
+		#define M1_MSS_SRC 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mss_mod:1;
+		REGWORD v_mss_mod_rep:1;
+		REGWORD v_mss_src_en:1;
+		REGWORD v_mss_src_grd:1;
+		REGWORD v_mss_out_en:1;
+		REGWORD v_mss_out_rep:1;
+		REGWORD v_mss_src:2;
+	} bit_r_mss0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_mss0 bit;} reg_r_mss0; // register and bitmap access
+	#define IDX_MSS0 0x08 // index value selecting this multi-register
+
+
+#define R_PCM_MD1 0x15 // register access
+	#define M_PCM_OD 0x02 // bitmap mask (1bit)
+	#define M_PLL_ADJ 0x0C // bitmap mask (2bit)
+		#define M1_PLL_ADJ 0x04
+	#define M_PCM_DR 0x30 // bitmap mask (2bit)
+		#define M1_PCM_DR 0x10
+	#define M_PCM_LOOP 0x40 // bitmap mask (1bit)
+	#define M_PCM_SMPL 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_31:1;
+		REGWORD v_pcm_od:1;
+		REGWORD v_pll_adj:2;
+		REGWORD v_pcm_dr:2;
+		REGWORD v_pcm_loop:1;
+		REGWORD v_pcm_smpl:1;
+	} bit_r_pcm_md1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pcm_md1 bit;} reg_r_pcm_md1; // register and bitmap access
+	#define IDX_PCM_MD1 0x09 // index value selecting this multi-register
+
+
+#define R_PCM_MD2 0x15 // register access
+	#define M_SYNC_OUT1 0x02 // bitmap mask (1bit)
+	#define M_SYNC_SRC 0x04 // bitmap mask (1bit)
+	#define M_SYNC_OUT2 0x08 // bitmap mask (1bit)
+	#define M_C2O_EN 0x10 // bitmap mask (1bit)
+	#define M_C2I_EN 0x20 // bitmap mask (1bit)
+	#define M_PLL_ICR 0x40 // bitmap mask (1bit)
+	#define M_PLL_MAN 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_32:1;
+		REGWORD v_sync_out1:1;
+		REGWORD v_sync_src:1;
+		REGWORD v_sync_out2:1;
+		REGWORD v_c2o_en:1;
+		REGWORD v_c2i_en:1;
+		REGWORD v_pll_icr:1;
+		REGWORD v_pll_man:1;
+	} bit_r_pcm_md2; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pcm_md2 bit;} reg_r_pcm_md2; // register and bitmap access
+	#define IDX_PCM_MD2 0x0A // index value selecting this multi-register
+
+
+#define R_MSS1 0x15 // register access
+	#define M_MSS_OFFS 0x07 // bitmap mask (3bit)
+		#define M1_MSS_OFFS 0x01
+	#define M_MS_SSYNC1 0x08 // bitmap mask (1bit)
+	#define M_MSS_DLY 0xF0 // bitmap mask (4bit)
+		#define M1_MSS_DLY 0x10
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mss_offs:3;
+		REGWORD v_ms_ssync1:1;
+		REGWORD v_mss_dly:4;
+	} bit_r_mss1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_mss1 bit;} reg_r_mss1; // register and bitmap access
+	#define IDX_MSS1 0x0B // index value selecting this multi-register
+
+
+#define R_SH0L 0x15 // register access
+	#define M_SH0L 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sh0l:8;
+	} bit_r_sh0l; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_sh0l bit;} reg_r_sh0l; // register and bitmap access
+	#define IDX_SH0L 0x0C // index value selecting this multi-register
+
+
+#define R_SH0H 0x15 // register access
+	#define M_SH0H 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sh0h:8;
+	} bit_r_sh0h; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_sh0h bit;} reg_r_sh0h; // register and bitmap access
+	#define IDX_SH0H 0x0D // index value selecting this multi-register
+
+
+#define R_SH1L 0x15 // register access
+	#define M_SH1L 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sh1l:8;
+	} bit_r_sh1l; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_sh1l bit;} reg_r_sh1l; // register and bitmap access
+	#define IDX_SH1L 0x0E // index value selecting this multi-register
+
+
+#define R_SH1H 0x15 // register access
+	#define M_SH1H 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sh1h:8;
+	} bit_r_sh1h; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_sh1h bit;} reg_r_sh1h; // register and bitmap access
+	#define IDX_SH1H 0x0F // index value selecting this multi-register
+
+
+#define R_RAM_USE 0x15 // register access
+	#define M_SRAM_USE 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sram_use:8;
+	} bit_r_ram_use; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ram_use bit;} reg_r_ram_use; // register and bitmap access
+
+
+#define R_SU_SEL 0x16 // register access
+	#define M_SU_SEL 0x03 // bitmap mask (2bit)
+		#define M1_SU_SEL 0x01
+	#define M_MULT_SU 0x08 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_su_sel:2;
+		REGWORD reserved_25:1;
+		REGWORD v_mult_su:1;
+		REGWORD reserved_26:4;
+	} bit_r_su_sel; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_su_sel bit;} reg_r_su_sel; // register and bitmap access
+
+
+#define R_CHIP_ID 0x16 // register access
+	#define M_CHIP_ID 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_chip_id:8;
+	} bit_r_chip_id; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_chip_id bit;} reg_r_chip_id; // register and bitmap access
+
+
+#define R_SU_SYNC 0x17 // register access
+	#define M_SYNC_SEL 0x07 // bitmap mask (3bit)
+		#define M1_SYNC_SEL 0x01
+	#define M_MAN_SYNC 0x08 // bitmap mask (1bit)
+	#define M_AUTO_SYNCI 0x10 // bitmap mask (1bit)
+	#define M_D_MERGE_TX 0x20 // bitmap mask (1bit)
+	#define M_E_MERGE_RX 0x40 // bitmap mask (1bit)
+	#define M_D_MERGE_RX 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sync_sel:3;
+		REGWORD v_man_sync:1;
+		REGWORD v_auto_synci:1;
+		REGWORD v_d_merge_tx:1;
+		REGWORD v_e_merge_rx:1;
+		REGWORD v_d_merge_rx:1;
+	} bit_r_su_sync; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_su_sync bit;} reg_r_su_sync; // register and bitmap access
+
+
+#define R_BERT_STA 0x17 // register access
+	#define M_RD_SYNC_SRC 0x07 // bitmap mask (3bit)
+		#define M1_RD_SYNC_SRC 0x01
+	#define M_BERT_SYNC 0x10 // bitmap mask (1bit)
+	#define M_BERT_INV_DATA 0x20 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_rd_sync_src:3;
+		REGWORD reserved_21:1;
+		REGWORD v_bert_sync:1;
+		REGWORD v_bert_inv_data:1;
+		REGWORD reserved_22:2;
+	} bit_r_bert_sta; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_bert_sta bit;} reg_r_bert_sta; // register and bitmap access
+
+
+#define R_F0_CNTL 0x18 // register access
+	#define M_F0_CNTL 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_f0_cntl:8;
+	} bit_r_f0_cntl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_f0_cntl bit;} reg_r_f0_cntl; // register and bitmap access
+
+
+#define R_F0_CNTH 0x19 // register access
+	#define M_F0_CNTH 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_f0_cnth:8;
+	} bit_r_f0_cnth; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_f0_cnth bit;} reg_r_f0_cnth; // register and bitmap access
+
+
+#define R_BERT_ECL 0x1A // register access
+	#define M_BERT_ECL 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_bert_ecl:8;
+	} bit_r_bert_ecl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_bert_ecl bit;} reg_r_bert_ecl; // register and bitmap access
+
+
+#define R_TI_WD 0x1A // register access
+	#define M_EV_TS 0x0F // bitmap mask (4bit)
+		#define M1_EV_TS 0x01
+	#define M_WD_TS 0xF0 // bitmap mask (4bit)
+		#define M1_WD_TS 0x10
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ev_ts:4;
+		REGWORD v_wd_ts:4;
+	} bit_r_ti_wd; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ti_wd bit;} reg_r_ti_wd; // register and bitmap access
+
+
+#define R_BERT_ECH 0x1B // register access
+	#define M_BERT_ECH 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_bert_ech:8;
+	} bit_r_bert_ech; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_bert_ech bit;} reg_r_bert_ech; // register and bitmap access
+
+
+#define R_BERT_WD_MD 0x1B // register access
+	#define M_PAT_SEQ 0x07 // bitmap mask (3bit)
+		#define M1_PAT_SEQ 0x01
+	#define M_BERT_ERR 0x08 // bitmap mask (1bit)
+	#define M_AUTO_WD_RES 0x20 // bitmap mask (1bit)
+	#define M_WD_RES 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_pat_seq:3;
+		REGWORD v_bert_err:1;
+		REGWORD reserved_16:1;
+		REGWORD v_auto_wd_res:1;
+		REGWORD reserved_17:1;
+		REGWORD v_wd_res:1;
+	} bit_r_bert_wd_md; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_bert_wd_md bit;} reg_r_bert_wd_md; // register and bitmap access
+
+
+#define R_STATUS 0x1C // register access
+	#define M_BUSY 0x01 // bitmap mask (1bit)
+	#define M_PROC 0x02 // bitmap mask (1bit)
+	#define M_LOST_STA 0x08 // bitmap mask (1bit)
+	#define M_PCM_INIT 0x10 // bitmap mask (1bit)
+	#define M_WAK_STA 0x20 // bitmap mask (1bit)
+	#define M_MISC_IRQSTA 0x40 // bitmap mask (1bit)
+	#define M_FR_IRQSTA 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_busy:1;
+		REGWORD v_proc:1;
+		REGWORD reserved_23:1;
+		REGWORD v_lost_sta:1;
+		REGWORD v_pcm_init:1;
+		REGWORD v_wak_sta:1;
+		REGWORD v_misc_irqsta:1;
+		REGWORD v_fr_irqsta:1;
+	} bit_r_status; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_status bit;} reg_r_status; // register and bitmap access
+
+
+#define R_SL_MAX 0x1D // register access
+	#define M_SL_MAX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_sl_max:8;
+	} bit_r_sl_max; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_sl_max bit;} reg_r_sl_max; // register and bitmap access
+
+
+#define R_PWM_CFG 0x1E // register access
+	#define M_PWM0_16KHZ 0x10 // bitmap mask (1bit)
+	#define M_PWM1_16KHZ 0x20 // bitmap mask (1bit)
+	#define M_PWM_FRQ 0xC0 // bitmap mask (2bit)
+		#define M1_PWM_FRQ 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_18:4;
+		REGWORD v_pwm0_16khz:1;
+		REGWORD v_pwm1_16khz:1;
+		REGWORD v_pwm_frq:2;
+	} bit_r_pwm_cfg; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pwm_cfg bit;} reg_r_pwm_cfg; // register and bitmap access
+
+
+#define R_CHIP_RV 0x1F // register access
+	#define M_CHIP_RV 0x0F // bitmap mask (4bit)
+		#define M1_CHIP_RV 0x01
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_chip_rv:4;
+		REGWORD reserved_24:4;
+	} bit_r_chip_rv; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_chip_rv bit;} reg_r_chip_rv; // register and bitmap access
+
+
+#define R_FIFO_BL0_IRQ 0x20 // register access
+	#define M_FIFO0_TX_IRQ 0x01 // bitmap mask (1bit)
+	#define M_FIFO0_RX_IRQ 0x02 // bitmap mask (1bit)
+	#define M_FIFO1_TX_IRQ 0x04 // bitmap mask (1bit)
+	#define M_FIFO1_RX_IRQ 0x08 // bitmap mask (1bit)
+	#define M_FIFO2_TX_IRQ 0x10 // bitmap mask (1bit)
+	#define M_FIFO2_RX_IRQ 0x20 // bitmap mask (1bit)
+	#define M_FIFO3_TX_IRQ 0x40 // bitmap mask (1bit)
+	#define M_FIFO3_RX_IRQ 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo0_tx_irq:1;
+		REGWORD v_fifo0_rx_irq:1;
+		REGWORD v_fifo1_tx_irq:1;
+		REGWORD v_fifo1_rx_irq:1;
+		REGWORD v_fifo2_tx_irq:1;
+		REGWORD v_fifo2_rx_irq:1;
+		REGWORD v_fifo3_tx_irq:1;
+		REGWORD v_fifo3_rx_irq:1;
+	} bit_r_fifo_bl0_irq; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo_bl0_irq bit;} reg_r_fifo_bl0_irq; // register and bitmap access
+
+
+#define R_FIFO_BL1_IRQ 0x21 // register access
+	#define M_FIFO4_TX_IRQ 0x01 // bitmap mask (1bit)
+	#define M_FIFO4_RX_IRQ 0x02 // bitmap mask (1bit)
+	#define M_FIFO5_TX_IRQ 0x04 // bitmap mask (1bit)
+	#define M_FIFO5_RX_IRQ 0x08 // bitmap mask (1bit)
+	#define M_FIFO6_TX_IRQ 0x10 // bitmap mask (1bit)
+	#define M_FIFO6_RX_IRQ 0x20 // bitmap mask (1bit)
+	#define M_FIFO7_TX_IRQ 0x40 // bitmap mask (1bit)
+	#define M_FIFO7_RX_IRQ 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo4_tx_irq:1;
+		REGWORD v_fifo4_rx_irq:1;
+		REGWORD v_fifo5_tx_irq:1;
+		REGWORD v_fifo5_rx_irq:1;
+		REGWORD v_fifo6_tx_irq:1;
+		REGWORD v_fifo6_rx_irq:1;
+		REGWORD v_fifo7_tx_irq:1;
+		REGWORD v_fifo7_rx_irq:1;
+	} bit_r_fifo_bl1_irq; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo_bl1_irq bit;} reg_r_fifo_bl1_irq; // register and bitmap access
+
+
+#define R_FIFO_BL2_IRQ 0x22 // register access
+	#define M_FIFO8_TX_IRQ 0x01 // bitmap mask (1bit)
+	#define M_FIFO8_RX_IRQ 0x02 // bitmap mask (1bit)
+	#define M_FIFO9_TX_IRQ 0x04 // bitmap mask (1bit)
+	#define M_FIFO9_RX_IRQ 0x08 // bitmap mask (1bit)
+	#define M_FIFO10_TX_IRQ 0x10 // bitmap mask (1bit)
+	#define M_FIFO10_RX_IRQ 0x20 // bitmap mask (1bit)
+	#define M_FIFO11_TX_IRQ 0x40 // bitmap mask (1bit)
+	#define M_FIFO11_RX_IRQ 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo8_tx_irq:1;
+		REGWORD v_fifo8_rx_irq:1;
+		REGWORD v_fifo9_tx_irq:1;
+		REGWORD v_fifo9_rx_irq:1;
+		REGWORD v_fifo10_tx_irq:1;
+		REGWORD v_fifo10_rx_irq:1;
+		REGWORD v_fifo11_tx_irq:1;
+		REGWORD v_fifo11_rx_irq:1;
+	} bit_r_fifo_bl2_irq; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo_bl2_irq bit;} reg_r_fifo_bl2_irq; // register and bitmap access
+
+
+#define R_FIFO_BL3_IRQ 0x23 // register access
+	#define M_FIFO12_TX_IRQ 0x01 // bitmap mask (1bit)
+	#define M_FIFO12_RX_IRQ 0x02 // bitmap mask (1bit)
+	#define M_FIFO13_TX_IRQ 0x04 // bitmap mask (1bit)
+	#define M_FIFO13_RX_IRQ 0x08 // bitmap mask (1bit)
+	#define M_FIFO14_TX_IRQ 0x10 // bitmap mask (1bit)
+	#define M_FIFO14_RX_IRQ 0x20 // bitmap mask (1bit)
+	#define M_FIFO15_TX_IRQ 0x40 // bitmap mask (1bit)
+	#define M_FIFO15_RX_IRQ 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo12_tx_irq:1;
+		REGWORD v_fifo12_rx_irq:1;
+		REGWORD v_fifo13_tx_irq:1;
+		REGWORD v_fifo13_rx_irq:1;
+		REGWORD v_fifo14_tx_irq:1;
+		REGWORD v_fifo14_rx_irq:1;
+		REGWORD v_fifo15_tx_irq:1;
+		REGWORD v_fifo15_rx_irq:1;
+	} bit_r_fifo_bl3_irq; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fifo_bl3_irq bit;} reg_r_fifo_bl3_irq; // register and bitmap access
+
+
+#define R_FILL_BL0 0x24 // register access
+	#define M_FILL_FIFO0_TX 0x01 // bitmap mask (1bit)
+	#define M_FILL_FIFO0_RX 0x02 // bitmap mask (1bit)
+	#define M_FILL_FIFO1_TX 0x04 // bitmap mask (1bit)
+	#define M_FILL_FIFO1_RX 0x08 // bitmap mask (1bit)
+	#define M_FILL_FIFO2_TX 0x10 // bitmap mask (1bit)
+	#define M_FILL_FIFO2_RX 0x20 // bitmap mask (1bit)
+	#define M_FILL_FIFO3_TX 0x40 // bitmap mask (1bit)
+	#define M_FILL_FIFO3_RX 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fill_fifo0_tx:1;
+		REGWORD v_fill_fifo0_rx:1;
+		REGWORD v_fill_fifo1_tx:1;
+		REGWORD v_fill_fifo1_rx:1;
+		REGWORD v_fill_fifo2_tx:1;
+		REGWORD v_fill_fifo2_rx:1;
+		REGWORD v_fill_fifo3_tx:1;
+		REGWORD v_fill_fifo3_rx:1;
+	} bit_r_fill_bl0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fill_bl0 bit;} reg_r_fill_bl0; // register and bitmap access
+
+
+#define R_FILL_BL1 0x25 // register access
+	#define M_FILL_FIFO4_TX 0x01 // bitmap mask (1bit)
+	#define M_FILL_FIFO4_RX 0x02 // bitmap mask (1bit)
+	#define M_FILL_FIFO5_TX 0x04 // bitmap mask (1bit)
+	#define M_FILL_FIFO5_RX 0x08 // bitmap mask (1bit)
+	#define M_FILL_FIFO6_TX 0x10 // bitmap mask (1bit)
+	#define M_FILL_FIFO6_RX 0x20 // bitmap mask (1bit)
+	#define M_FILL_FIFO7_TX 0x40 // bitmap mask (1bit)
+	#define M_FILL_FIFO7_RX 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fill_fifo4_tx:1;
+		REGWORD v_fill_fifo4_rx:1;
+		REGWORD v_fill_fifo5_tx:1;
+		REGWORD v_fill_fifo5_rx:1;
+		REGWORD v_fill_fifo6_tx:1;
+		REGWORD v_fill_fifo6_rx:1;
+		REGWORD v_fill_fifo7_tx:1;
+		REGWORD v_fill_fifo7_rx:1;
+	} bit_r_fill_bl1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fill_bl1 bit;} reg_r_fill_bl1; // register and bitmap access
+
+
+#define R_FILL_BL2 0x26 // register access
+	#define M_FILL_FIFO8_TX 0x01 // bitmap mask (1bit)
+	#define M_FILL_FIFO8_RX 0x02 // bitmap mask (1bit)
+	#define M_FILL_FIFO9_TX 0x04 // bitmap mask (1bit)
+	#define M_FILL_FIFO9_RX 0x08 // bitmap mask (1bit)
+	#define M_FILL_FIFO10_TX 0x10 // bitmap mask (1bit)
+	#define M_FILL_FIFO10_RX 0x20 // bitmap mask (1bit)
+	#define M_FILL_FIFO11_TX 0x40 // bitmap mask (1bit)
+	#define M_FILL_FIFO11_RX 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fill_fifo8_tx:1;
+		REGWORD v_fill_fifo8_rx:1;
+		REGWORD v_fill_fifo9_tx:1;
+		REGWORD v_fill_fifo9_rx:1;
+		REGWORD v_fill_fifo10_tx:1;
+		REGWORD v_fill_fifo10_rx:1;
+		REGWORD v_fill_fifo11_tx:1;
+		REGWORD v_fill_fifo11_rx:1;
+	} bit_r_fill_bl2; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fill_bl2 bit;} reg_r_fill_bl2; // register and bitmap access
+
+
+#define R_FILL_BL3 0x27 // register access
+	#define M_FILL_FIFO12_TX 0x01 // bitmap mask (1bit)
+	#define M_FILL_FIFO12_RX 0x02 // bitmap mask (1bit)
+	#define M_FILL_FIFO13_TX 0x04 // bitmap mask (1bit)
+	#define M_FILL_FIFO13_RX 0x08 // bitmap mask (1bit)
+	#define M_FILL_FIFO14_TX 0x10 // bitmap mask (1bit)
+	#define M_FILL_FIFO14_RX 0x20 // bitmap mask (1bit)
+	#define M_FILL_FIFO15_TX 0x40 // bitmap mask (1bit)
+	#define M_FILL_FIFO15_RX 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fill_fifo12_tx:1;
+		REGWORD v_fill_fifo12_rx:1;
+		REGWORD v_fill_fifo13_tx:1;
+		REGWORD v_fill_fifo13_rx:1;
+		REGWORD v_fill_fifo14_tx:1;
+		REGWORD v_fill_fifo14_rx:1;
+		REGWORD v_fill_fifo15_tx:1;
+		REGWORD v_fill_fifo15_rx:1;
+	} bit_r_fill_bl3; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_fill_bl3 bit;} reg_r_fill_bl3; // register and bitmap access
+
+
+#define R_CI_TX 0x28 // register access
+	#define M_GCI_C 0x3F // bitmap mask (6bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gci_c:6;
+		REGWORD reserved_33:2;
+	} bit_r_ci_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ci_tx bit;} reg_r_ci_tx; // register and bitmap access
+
+
+#define R_CI_RX 0x28 // register access
+	#define M_GCI_I 0x3F // bitmap mask (6bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gci_i:6;
+		REGWORD reserved_35:2;
+	} bit_r_ci_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ci_rx bit;} reg_r_ci_rx; // register and bitmap access
+
+
+#define R_GCI_CFG0 0x29 // register access
+	#define M_MON_END 0x01 // bitmap mask (1bit)
+	#define M_MON_SLOW 0x02 // bitmap mask (1bit)
+	#define M_MON_DLL 0x04 // bitmap mask (1bit)
+	#define M_MON_CI6 0x08 // bitmap mask (1bit)
+	#define M_GCI_SWAP_TXHS 0x10 // bitmap mask (1bit)
+	#define M_GCI_SWAP_RXHS 0x20 // bitmap mask (1bit)
+	#define M_GCI_SWAP_STIO 0x40 // bitmap mask (1bit)
+	#define M_GCI_EN 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mon_end:1;
+		REGWORD v_mon_slow:1;
+		REGWORD v_mon_dll:1;
+		REGWORD v_mon_ci6:1;
+		REGWORD v_gci_swap_txhs:1;
+		REGWORD v_gci_swap_rxhs:1;
+		REGWORD v_gci_swap_stio:1;
+		REGWORD v_gci_en:1;
+	} bit_r_gci_cfg0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gci_cfg0 bit;} reg_r_gci_cfg0; // register and bitmap access
+
+
+#define R_GCI_STA 0x29 // register access
+	#define M_MON_RXR 0x01 // bitmap mask (1bit)
+	#define M_MON_TXR 0x02 // bitmap mask (1bit)
+	#define M_GCI_MX 0x04 // bitmap mask (1bit)
+	#define M_GCI_MR 0x08 // bitmap mask (1bit)
+	#define M_GCI_RX 0x10 // bitmap mask (1bit)
+	#define M_GCI_ABO 0x20 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mon_rxr:1;
+		REGWORD v_mon_txr:1;
+		REGWORD v_gci_mx:1;
+		REGWORD v_gci_mr:1;
+		REGWORD v_gci_rx:1;
+		REGWORD v_gci_abo:1;
+		REGWORD reserved_36:2;
+	} bit_r_gci_sta; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gci_sta bit;} reg_r_gci_sta; // register and bitmap access
+
+
+#define R_GCI_CFG1 0x2A // register access
+	#define M_GCI_SL 0x1F // bitmap mask (5bit)
+		#define M1_GCI_SL 0x01
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gci_sl:5;
+		REGWORD reserved_34:3;
+	} bit_r_gci_cfg1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gci_cfg1 bit;} reg_r_gci_cfg1; // register and bitmap access
+
+
+#define R_MON_RX 0x2A // register access
+	#define M_MON_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mon_rx:8;
+	} bit_r_mon_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_mon_rx bit;} reg_r_mon_rx; // register and bitmap access
+
+
+#define R_MON_TX 0x2B // register access
+	#define M_MON_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_mon_tx:8;
+	} bit_r_mon_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_mon_tx bit;} reg_r_mon_tx; // register and bitmap access
+
+
+#define A_SU_WR_STA 0x30 // register access
+	#define M_SU_SET_STA 0x0F // bitmap mask (4bit)
+		#define M1_SU_SET_STA 0x01
+	#define M_SU_LD_STA 0x10 // bitmap mask (1bit)
+	#define M_SU_ACT 0x60 // bitmap mask (2bit)
+		#define M1_SU_ACT 0x20
+	#define M_SU_SET_G2_G3 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_su_set_sta:4;
+		REGWORD v_su_ld_sta:1;
+		REGWORD v_su_act:2;
+		REGWORD v_su_set_g2_g3:1;
+	} bit_a_su_wr_sta; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_su_wr_sta bit;} reg_a_su_wr_sta; // register and bitmap access
+
+
+#define A_SU_RD_STA 0x30 // register access
+	#define M_SU_STA 0x0F // bitmap mask (4bit)
+		#define M1_SU_STA 0x01
+	#define M_SU_FR_SYNC 0x10 // bitmap mask (1bit)
+	#define M_SU_T2_EXP 0x20 // bitmap mask (1bit)
+	#define M_SU_INFO0 0x40 // bitmap mask (1bit)
+	#define M_G2_G3 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_su_sta:4;
+		REGWORD v_su_fr_sync:1;
+		REGWORD v_su_t2_exp:1;
+		REGWORD v_su_info0:1;
+		REGWORD v_g2_g3:1;
+	} bit_a_su_rd_sta; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_su_rd_sta bit;} reg_a_su_rd_sta; // register and bitmap access
+
+
+#define A_SU_CTRL0 0x31 // register access
+	#define M_B1_TX_EN 0x01 // bitmap mask (1bit)
+	#define M_B2_TX_EN 0x02 // bitmap mask (1bit)
+	#define M_SU_MD 0x04 // bitmap mask (1bit)
+	#define M_ST_D_LPRIO 0x08 // bitmap mask (1bit)
+	#define M_ST_SQ_EN 0x10 // bitmap mask (1bit)
+	#define M_SU_TST_SIG 0x20 // bitmap mask (1bit)
+	#define M_ST_PU_CTRL 0x40 // bitmap mask (1bit)
+	#define M_SU_STOP 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b1_tx_en:1;
+		REGWORD v_b2_tx_en:1;
+		REGWORD v_su_md:1;
+		REGWORD v_st_d_lprio:1;
+		REGWORD v_st_sq_en:1;
+		REGWORD v_su_tst_sig:1;
+		REGWORD v_st_pu_ctrl:1;
+		REGWORD v_su_stop:1;
+	} bit_a_su_ctrl0; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_su_ctrl0 bit;} reg_a_su_ctrl0; // register and bitmap access
+
+
+#define A_SU_DLYL 0x31 // register access
+	#define M_SU_DLYL 0x1F // bitmap mask (5bit)
+		#define M1_SU_DLYL 0x01
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_su_dlyl:5;
+		REGWORD reserved_46:3;
+	} bit_a_su_dlyl; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_su_dlyl bit;} reg_a_su_dlyl; // register and bitmap access
+
+
+#define A_SU_CTRL1 0x32 // register access
+	#define M_G2_G3_EN 0x01 // bitmap mask (1bit)
+	#define M_D_RES 0x04 // bitmap mask (1bit)
+	#define M_ST_E_IGNO 0x08 // bitmap mask (1bit)
+	#define M_ST_E_LO 0x10 // bitmap mask (1bit)
+	#define M_BAC_D 0x40 // bitmap mask (1bit)
+	#define M_B12_SWAP 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_g2_g3_en:1;
+		REGWORD reserved_37:1;
+		REGWORD v_d_res:1;
+		REGWORD v_st_e_igno:1;
+		REGWORD v_st_e_lo:1;
+		REGWORD reserved_38:1;
+		REGWORD v_bac_d:1;
+		REGWORD v_b12_swap:1;
+	} bit_a_su_ctrl1; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_su_ctrl1 bit;} reg_a_su_ctrl1; // register and bitmap access
+
+
+#define A_SU_DLYH 0x32 // register access
+	#define M_SU_DLYH 0x1F // bitmap mask (5bit)
+		#define M1_SU_DLYH 0x01
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_su_dlyh:5;
+		REGWORD reserved_47:3;
+	} bit_a_su_dlyh; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_su_dlyh bit;} reg_a_su_dlyh; // register and bitmap access
+
+
+#define A_SU_CTRL2 0x33 // register access
+	#define M_B1_RX_EN 0x01 // bitmap mask (1bit)
+	#define M_B2_RX_EN 0x02 // bitmap mask (1bit)
+	#define M_MS_SSYNC2 0x04 // bitmap mask (1bit)
+	#define M_BAC_S_SEL 0x08 // bitmap mask (1bit)
+	#define M_SU_SYNC_NT 0x10 // bitmap mask (1bit)
+	#define M_SU_2KHZ 0x20 // bitmap mask (1bit)
+	#define M_SU_TRI 0x40 // bitmap mask (1bit)
+	#define M_SU_EXCHG 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b1_rx_en:1;
+		REGWORD v_b2_rx_en:1;
+		REGWORD v_ms_ssync2:1;
+		REGWORD v_bac_s_sel:1;
+		REGWORD v_su_sync_nt:1;
+		REGWORD v_su_2khz:1;
+		REGWORD v_su_tri:1;
+		REGWORD v_su_exchg:1;
+	} bit_a_su_ctrl2; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_su_ctrl2 bit;} reg_a_su_ctrl2; // register and bitmap access
+
+
+#define A_MS_TX 0x34 // register access
+	#define M_MS_TX 0x0F // bitmap mask (4bit)
+		#define M1_MS_TX 0x01
+	#define M_UP_S_TX 0x40 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ms_tx:4;
+		REGWORD reserved_39:2;
+		REGWORD v_up_s_tx:1;
+		REGWORD reserved_40:1;
+	} bit_a_ms_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_ms_tx bit;} reg_a_ms_tx; // register and bitmap access
+
+
+#define A_MS_RX 0x34 // register access
+	#define M_MS_RX 0x0F // bitmap mask (4bit)
+		#define M1_MS_RX 0x01
+	#define M_MS_RX_RDY 0x10 // bitmap mask (1bit)
+	#define M_UP_S_RX 0x40 // bitmap mask (1bit)
+	#define M_MS_TX_RDY 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ms_rx:4;
+		REGWORD v_ms_rx_rdy:1;
+		REGWORD reserved_48:1;
+		REGWORD v_up_s_rx:1;
+		REGWORD v_ms_tx_rdy:1;
+	} bit_a_ms_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_ms_rx bit;} reg_a_ms_rx; // register and bitmap access
+
+
+#define A_ST_CTRL3 0x35 // register access
+	#define M_ST_SEL 0x01 // bitmap mask (1bit)
+	#define M_ST_PULSE 0xFE // bitmap mask (7bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_sel:1;
+		REGWORD v_st_pulse:7;
+	} bit_a_st_ctrl3; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_st_ctrl3 bit;} reg_a_st_ctrl3; // register and bitmap access
+	#define IDX_ST_CTRL3 0x00 // index value selecting this multi-register
+
+
+#define A_UP_CTRL3 0x35 // register access
+	#define M_UP_SEL 0x01 // bitmap mask (1bit)
+	#define M_UP_VIO 0x02 // bitmap mask (1bit)
+	#define M_UP_DC_STR 0x04 // bitmap mask (1bit)
+	#define M_UP_DC_OFF 0x08 // bitmap mask (1bit)
+	#define M_UP_RPT_PAT 0x10 // bitmap mask (1bit)
+	#define M_UP_SCRM_MD 0x20 // bitmap mask (1bit)
+	#define M_UP_SCRM_TX_OFF 0x40 // bitmap mask (1bit)
+	#define M_UP_SCRM_RX_OFF 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_up_sel:1;
+		REGWORD v_up_vio:1;
+		REGWORD v_up_dc_str:1;
+		REGWORD v_up_dc_off:1;
+		REGWORD v_up_rpt_pat:1;
+		REGWORD v_up_scrm_md:1;
+		REGWORD v_up_scrm_tx_off:1;
+		REGWORD v_up_scrm_rx_off:1;
+	} bit_a_up_ctrl3; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_up_ctrl3 bit;} reg_a_up_ctrl3; // register and bitmap access
+	#define IDX_UP_CTRL3 0x01 // index value selecting this multi-register
+
+
+#define A_SU_STA 0x35 // register access
+	#define M_ST_D_HPRIO9 0x01 // bitmap mask (1bit)
+	#define M_ST_D_LPRIO11 0x02 // bitmap mask (1bit)
+	#define M_ST_D_CONT 0x04 // bitmap mask (1bit)
+	#define M_ST_D_ACT 0x08 // bitmap mask (1bit)
+	#define M_SU_AF0 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_st_d_hprio9:1;
+		REGWORD v_st_d_lprio11:1;
+		REGWORD v_st_d_cont:1;
+		REGWORD v_st_d_act:1;
+		REGWORD reserved_49:3;
+		REGWORD v_su_af0:1;
+	} bit_a_su_sta; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_su_sta bit;} reg_a_su_sta; // register and bitmap access
+
+
+#define A_MS_DF 0x36 // register access
+	#define M_BAC_NINV 0x01 // bitmap mask (1bit)
+	#define M_SG_AB_INV 0x02 // bitmap mask (1bit)
+	#define M_SQ_T_SRC 0x04 // bitmap mask (1bit)
+	#define M_M_S_SRC 0x08 // bitmap mask (1bit)
+	#define M_SQ_T_DST 0x10 // bitmap mask (1bit)
+	#define M_SU_RX_VAL 0x20 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_bac_ninv:1;
+		REGWORD v_sg_ab_inv:1;
+		REGWORD v_sq_t_src:1;
+		REGWORD v_m_s_src:1;
+		REGWORD v_sq_t_dst:1;
+		REGWORD v_su_rx_val:1;
+		REGWORD reserved_41:2;
+	} bit_a_ms_df; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_ms_df bit;} reg_a_ms_df; // register and bitmap access
+
+
+#define A_SU_CLK_DLY 0x37 // register access
+	#define M_SU_CLK_DLY 0x0F // bitmap mask (4bit)
+		#define M1_SU_CLK_DLY 0x01
+	#define M_ST_SMPL 0x70 // bitmap mask (3bit)
+		#define M1_ST_SMPL 0x10
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_su_clk_dly:4;
+		REGWORD v_st_smpl:3;
+		REGWORD reserved_42:1;
+	} bit_a_su_clk_dly; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_su_clk_dly bit;} reg_a_su_clk_dly; // register and bitmap access
+
+
+#define R_PWM0 0x38 // register access
+	#define M_PWM0 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_pwm0:8;
+	} bit_r_pwm0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pwm0 bit;} reg_r_pwm0; // register and bitmap access
+
+
+#define R_PWM1 0x39 // register access
+	#define M_PWM1 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_pwm1:8;
+	} bit_r_pwm1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pwm1 bit;} reg_r_pwm1; // register and bitmap access
+
+
+#define A_B1_TX 0x3C // register access
+	#define M_B1_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b1_tx:8;
+	} bit_a_b1_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_b1_tx bit;} reg_a_b1_tx; // register and bitmap access
+
+
+#define A_B1_RX 0x3C // register access
+	#define M_B1_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b1_rx:8;
+	} bit_a_b1_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_b1_rx bit;} reg_a_b1_rx; // register and bitmap access
+
+
+#define A_B2_TX 0x3D // register access
+	#define M_B2_TX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b2_tx:8;
+	} bit_a_b2_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_b2_tx bit;} reg_a_b2_tx; // register and bitmap access
+
+
+#define A_B2_RX 0x3D // register access
+	#define M_B2_RX 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_b2_rx:8;
+	} bit_a_b2_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_b2_rx bit;} reg_a_b2_rx; // register and bitmap access
+
+
+#define A_D_TX 0x3E // register access
+	#define M_D_TX_S 0x01 // bitmap mask (1bit)
+	#define M_D_TX_BAC 0x20 // bitmap mask (1bit)
+	#define M_D_TX 0xC0 // bitmap mask (2bit)
+		#define M1_D_TX 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_d_tx_s:1;
+		REGWORD reserved_43:4;
+		REGWORD v_d_tx_bac:1;
+		REGWORD v_d_tx:2;
+	} bit_a_d_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_d_tx bit;} reg_a_d_tx; // register and bitmap access
+
+
+#define A_D_RX 0x3E // register access
+	#define M_D_RX_S 0x01 // bitmap mask (1bit)
+	#define M_D_RX_AB 0x10 // bitmap mask (1bit)
+	#define M_D_RX_SG 0x20 // bitmap mask (1bit)
+	#define M_D_RX 0xC0 // bitmap mask (2bit)
+		#define M1_D_RX 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_d_rx_s:1;
+		REGWORD reserved_50:3;
+		REGWORD v_d_rx_ab:1;
+		REGWORD v_d_rx_sg:1;
+		REGWORD v_d_rx:2;
+	} bit_a_d_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_d_rx bit;} reg_a_d_rx; // register and bitmap access
+
+
+#define A_E_RX 0x3F // register access
+	#define M_E_RX_S 0x01 // bitmap mask (1bit)
+	#define M_E_RX_AB 0x10 // bitmap mask (1bit)
+	#define M_E_RX_SG 0x20 // bitmap mask (1bit)
+	#define M_E_RX 0xC0 // bitmap mask (2bit)
+		#define M1_E_RX 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_e_rx_s:1;
+		REGWORD reserved_51:3;
+		REGWORD v_e_rx_ab:1;
+		REGWORD v_e_rx_sg:1;
+		REGWORD v_e_rx:2;
+	} bit_a_e_rx; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_e_rx bit;} reg_a_e_rx; // register and bitmap access
+
+
+#define A_BAC_S_TX 0x3F // register access
+	#define M_S_TX 0x01 // bitmap mask (1bit)
+	#define M_BAC_TX 0x20 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_s_tx:1;
+		REGWORD reserved_44:4;
+		REGWORD v_bac_tx:1;
+		REGWORD reserved_45:2;
+	} bit_a_bac_s_tx; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_bac_s_tx bit;} reg_a_bac_s_tx; // register and bitmap access
+
+
+#define R_GPIO_OUT1 0x40 // register access
+	#define M_GPIO_OUT8 0x01 // bitmap mask (1bit)
+	#define M_GPIO_OUT9 0x02 // bitmap mask (1bit)
+	#define M_GPIO_OUT10 0x04 // bitmap mask (1bit)
+	#define M_GPIO_OUT11 0x08 // bitmap mask (1bit)
+	#define M_GPIO_OUT12 0x10 // bitmap mask (1bit)
+	#define M_GPIO_OUT13 0x20 // bitmap mask (1bit)
+	#define M_GPIO_OUT14 0x40 // bitmap mask (1bit)
+	#define M_GPIO_OUT15 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_out8:1;
+		REGWORD v_gpio_out9:1;
+		REGWORD v_gpio_out10:1;
+		REGWORD v_gpio_out11:1;
+		REGWORD v_gpio_out12:1;
+		REGWORD v_gpio_out13:1;
+		REGWORD v_gpio_out14:1;
+		REGWORD v_gpio_out15:1;
+	} bit_r_gpio_out1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_out1 bit;} reg_r_gpio_out1; // register and bitmap access
+
+
+#define R_GPIO_IN1 0x40 // register access
+	#define M_GPIO_IN8 0x01 // bitmap mask (1bit)
+	#define M_GPIO_IN9 0x02 // bitmap mask (1bit)
+	#define M_GPIO_IN10 0x04 // bitmap mask (1bit)
+	#define M_GPIO_IN11 0x08 // bitmap mask (1bit)
+	#define M_GPIO_IN12 0x10 // bitmap mask (1bit)
+	#define M_GPIO_IN13 0x20 // bitmap mask (1bit)
+	#define M_GPIO_IN14 0x40 // bitmap mask (1bit)
+	#define M_GPIO_IN15 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_in8:1;
+		REGWORD v_gpio_in9:1;
+		REGWORD v_gpio_in10:1;
+		REGWORD v_gpio_in11:1;
+		REGWORD v_gpio_in12:1;
+		REGWORD v_gpio_in13:1;
+		REGWORD v_gpio_in14:1;
+		REGWORD v_gpio_in15:1;
+	} bit_r_gpio_in1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_in1 bit;} reg_r_gpio_in1; // register and bitmap access
+
+
+#define R_GPIO_OUT3 0x41 // register access
+	#define M_GPIO_OUT24 0x01 // bitmap mask (1bit)
+	#define M_GPIO_OUT25 0x02 // bitmap mask (1bit)
+	#define M_GPIO_OUT26 0x04 // bitmap mask (1bit)
+	#define M_GPIO_OUT27 0x08 // bitmap mask (1bit)
+	#define M_GPIO_OUT28 0x10 // bitmap mask (1bit)
+	#define M_GPIO_OUT29 0x20 // bitmap mask (1bit)
+	#define M_GPIO_OUT30 0x40 // bitmap mask (1bit)
+	#define M_GPIO_OUT31 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_out24:1;
+		REGWORD v_gpio_out25:1;
+		REGWORD v_gpio_out26:1;
+		REGWORD v_gpio_out27:1;
+		REGWORD v_gpio_out28:1;
+		REGWORD v_gpio_out29:1;
+		REGWORD v_gpio_out30:1;
+		REGWORD v_gpio_out31:1;
+	} bit_r_gpio_out3; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_out3 bit;} reg_r_gpio_out3; // register and bitmap access
+
+
+#define R_GPIO_IN3 0x41 // register access
+	#define M_GPIO_IN24 0x01 // bitmap mask (1bit)
+	#define M_GPIO_IN25 0x02 // bitmap mask (1bit)
+	#define M_GPIO_IN26 0x04 // bitmap mask (1bit)
+	#define M_GPIO_IN27 0x08 // bitmap mask (1bit)
+	#define M_GPIO_IN28 0x10 // bitmap mask (1bit)
+	#define M_GPIO_IN29 0x20 // bitmap mask (1bit)
+	#define M_GPIO_IN30 0x40 // bitmap mask (1bit)
+	#define M_GPIO_IN31 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_in24:1;
+		REGWORD v_gpio_in25:1;
+		REGWORD v_gpio_in26:1;
+		REGWORD v_gpio_in27:1;
+		REGWORD v_gpio_in28:1;
+		REGWORD v_gpio_in29:1;
+		REGWORD v_gpio_in30:1;
+		REGWORD v_gpio_in31:1;
+	} bit_r_gpio_in3; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_in3 bit;} reg_r_gpio_in3; // register and bitmap access
+
+
+#define R_GPIO_EN1 0x42 // register access
+	#define M_GPIO_EN8 0x01 // bitmap mask (1bit)
+	#define M_GPIO_EN9 0x02 // bitmap mask (1bit)
+	#define M_GPIO_EN10 0x04 // bitmap mask (1bit)
+	#define M_GPIO_EN11 0x08 // bitmap mask (1bit)
+	#define M_GPIO_EN12 0x10 // bitmap mask (1bit)
+	#define M_GPIO_EN13 0x20 // bitmap mask (1bit)
+	#define M_GPIO_EN14 0x40 // bitmap mask (1bit)
+	#define M_GPIO_EN15 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_en8:1;
+		REGWORD v_gpio_en9:1;
+		REGWORD v_gpio_en10:1;
+		REGWORD v_gpio_en11:1;
+		REGWORD v_gpio_en12:1;
+		REGWORD v_gpio_en13:1;
+		REGWORD v_gpio_en14:1;
+		REGWORD v_gpio_en15:1;
+	} bit_r_gpio_en1; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_en1 bit;} reg_r_gpio_en1; // register and bitmap access
+
+
+#define R_GPIO_EN3 0x43 // register access
+	#define M_GPIO_EN24 0x01 // bitmap mask (1bit)
+	#define M_GPIO_EN25 0x02 // bitmap mask (1bit)
+	#define M_GPIO_EN26 0x04 // bitmap mask (1bit)
+	#define M_GPIO_EN27 0x08 // bitmap mask (1bit)
+	#define M_GPIO_EN28 0x10 // bitmap mask (1bit)
+	#define M_GPIO_EN29 0x20 // bitmap mask (1bit)
+	#define M_GPIO_EN30 0x40 // bitmap mask (1bit)
+	#define M_GPIO_EN31 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_en24:1;
+		REGWORD v_gpio_en25:1;
+		REGWORD v_gpio_en26:1;
+		REGWORD v_gpio_en27:1;
+		REGWORD v_gpio_en28:1;
+		REGWORD v_gpio_en29:1;
+		REGWORD v_gpio_en30:1;
+		REGWORD v_gpio_en31:1;
+	} bit_r_gpio_en3; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_en3 bit;} reg_r_gpio_en3; // register and bitmap access
+
+
+#define R_GPIO_SEL_BL 0x44 // register access
+	#define M_GPIO_BL0 0x01 // bitmap mask (1bit)
+	#define M_GPIO_BL1 0x02 // bitmap mask (1bit)
+	#define M_GPIO_BL2 0x04 // bitmap mask (1bit)
+	#define M_GPIO_BL3 0x08 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_bl0:1;
+		REGWORD v_gpio_bl1:1;
+		REGWORD v_gpio_bl2:1;
+		REGWORD v_gpio_bl3:1;
+		REGWORD reserved_54:4;
+	} bit_r_gpio_sel_bl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_sel_bl bit;} reg_r_gpio_sel_bl; // register and bitmap access
+
+
+#define R_GPIO_OUT2 0x45 // register access
+	#define M_GPIO_OUT16 0x01 // bitmap mask (1bit)
+	#define M_GPIO_OUT17 0x02 // bitmap mask (1bit)
+	#define M_GPIO_OUT18 0x04 // bitmap mask (1bit)
+	#define M_GPIO_OUT19 0x08 // bitmap mask (1bit)
+	#define M_GPIO_OUT20 0x10 // bitmap mask (1bit)
+	#define M_GPIO_OUT21 0x20 // bitmap mask (1bit)
+	#define M_GPIO_OUT22 0x40 // bitmap mask (1bit)
+	#define M_GPIO_OUT23 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_out16:1;
+		REGWORD v_gpio_out17:1;
+		REGWORD v_gpio_out18:1;
+		REGWORD v_gpio_out19:1;
+		REGWORD v_gpio_out20:1;
+		REGWORD v_gpio_out21:1;
+		REGWORD v_gpio_out22:1;
+		REGWORD v_gpio_out23:1;
+	} bit_r_gpio_out2; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_out2 bit;} reg_r_gpio_out2; // register and bitmap access
+
+
+#define R_GPIO_IN2 0x45 // register access
+	#define M_GPIO_IN16 0x01 // bitmap mask (1bit)
+	#define M_GPIO_IN17 0x02 // bitmap mask (1bit)
+	#define M_GPIO_IN18 0x04 // bitmap mask (1bit)
+	#define M_GPIO_IN19 0x08 // bitmap mask (1bit)
+	#define M_GPIO_IN20 0x10 // bitmap mask (1bit)
+	#define M_GPIO_IN21 0x20 // bitmap mask (1bit)
+	#define M_GPIO_IN22 0x40 // bitmap mask (1bit)
+	#define M_GPIO_IN23 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_in16:1;
+		REGWORD v_gpio_in17:1;
+		REGWORD v_gpio_in18:1;
+		REGWORD v_gpio_in19:1;
+		REGWORD v_gpio_in20:1;
+		REGWORD v_gpio_in21:1;
+		REGWORD v_gpio_in22:1;
+		REGWORD v_gpio_in23:1;
+	} bit_r_gpio_in2; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_in2 bit;} reg_r_gpio_in2; // register and bitmap access
+
+
+#define R_PWM_MD 0x46 // register access
+	#define M_WAK_EN 0x02 // bitmap mask (1bit)
+	#define M_PWM0_MD 0x30 // bitmap mask (2bit)
+		#define M1_PWM0_MD 0x10
+	#define M_PWM1_MD 0xC0 // bitmap mask (2bit)
+		#define M1_PWM1_MD 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_52:1;
+		REGWORD v_wak_en:1;
+		REGWORD reserved_53:2;
+		REGWORD v_pwm0_md:2;
+		REGWORD v_pwm1_md:2;
+	} bit_r_pwm_md; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pwm_md bit;} reg_r_pwm_md; // register and bitmap access
+
+
+#define R_GPIO_EN2 0x47 // register access
+	#define M_GPIO_EN16 0x01 // bitmap mask (1bit)
+	#define M_GPIO_EN17 0x02 // bitmap mask (1bit)
+	#define M_GPIO_EN18 0x04 // bitmap mask (1bit)
+	#define M_GPIO_EN19 0x08 // bitmap mask (1bit)
+	#define M_GPIO_EN20 0x10 // bitmap mask (1bit)
+	#define M_GPIO_EN21 0x20 // bitmap mask (1bit)
+	#define M_GPIO_EN22 0x40 // bitmap mask (1bit)
+	#define M_GPIO_EN23 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_en16:1;
+		REGWORD v_gpio_en17:1;
+		REGWORD v_gpio_en18:1;
+		REGWORD v_gpio_en19:1;
+		REGWORD v_gpio_en20:1;
+		REGWORD v_gpio_en21:1;
+		REGWORD v_gpio_en22:1;
+		REGWORD v_gpio_en23:1;
+	} bit_r_gpio_en2; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_en2 bit;} reg_r_gpio_en2; // register and bitmap access
+
+
+#define R_GPIO_IN0 0x48 // register access
+	#define M_GPIO_IN0 0x01 // bitmap mask (1bit)
+	#define M_GPIO_IN1 0x02 // bitmap mask (1bit)
+	#define M_GPIO_IN2 0x04 // bitmap mask (1bit)
+	#define M_GPIO_IN3 0x08 // bitmap mask (1bit)
+	#define M_GPIO_IN4 0x10 // bitmap mask (1bit)
+	#define M_GPIO_IN5 0x20 // bitmap mask (1bit)
+	#define M_GPIO_IN6 0x40 // bitmap mask (1bit)
+	#define M_GPIO_IN7 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_in0:1;
+		REGWORD v_gpio_in1:1;
+		REGWORD v_gpio_in2:1;
+		REGWORD v_gpio_in3:1;
+		REGWORD v_gpio_in4:1;
+		REGWORD v_gpio_in5:1;
+		REGWORD v_gpio_in6:1;
+		REGWORD v_gpio_in7:1;
+	} bit_r_gpio_in0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_in0 bit;} reg_r_gpio_in0; // register and bitmap access
+
+
+#define R_GPIO_OUT0 0x48 // register access
+	#define M_GPIO_OUT0 0x01 // bitmap mask (1bit)
+	#define M_GPIO_OUT1 0x02 // bitmap mask (1bit)
+	#define M_GPIO_OUT2 0x04 // bitmap mask (1bit)
+	#define M_GPIO_OUT3 0x08 // bitmap mask (1bit)
+	#define M_GPIO_OUT4 0x10 // bitmap mask (1bit)
+	#define M_GPIO_OUT5 0x20 // bitmap mask (1bit)
+	#define M_GPIO_OUT6 0x40 // bitmap mask (1bit)
+	#define M_GPIO_OUT7 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_out0:1;
+		REGWORD v_gpio_out1:1;
+		REGWORD v_gpio_out2:1;
+		REGWORD v_gpio_out3:1;
+		REGWORD v_gpio_out4:1;
+		REGWORD v_gpio_out5:1;
+		REGWORD v_gpio_out6:1;
+		REGWORD v_gpio_out7:1;
+	} bit_r_gpio_out0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_out0 bit;} reg_r_gpio_out0; // register and bitmap access
+
+
+#define R_GPIO_EN0 0x4A // register access
+	#define M_GPIO_EN0 0x01 // bitmap mask (1bit)
+	#define M_GPIO_EN1 0x02 // bitmap mask (1bit)
+	#define M_GPIO_EN2 0x04 // bitmap mask (1bit)
+	#define M_GPIO_EN3 0x08 // bitmap mask (1bit)
+	#define M_GPIO_EN4 0x10 // bitmap mask (1bit)
+	#define M_GPIO_EN5 0x20 // bitmap mask (1bit)
+	#define M_GPIO_EN6 0x40 // bitmap mask (1bit)
+	#define M_GPIO_EN7 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_en0:1;
+		REGWORD v_gpio_en1:1;
+		REGWORD v_gpio_en2:1;
+		REGWORD v_gpio_en3:1;
+		REGWORD v_gpio_en4:1;
+		REGWORD v_gpio_en5:1;
+		REGWORD v_gpio_en6:1;
+		REGWORD v_gpio_en7:1;
+	} bit_r_gpio_en0; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_en0 bit;} reg_r_gpio_en0; // register and bitmap access
+
+
+#define R_GPIO_SEL 0x4C // register access
+	#define M_GPIO_SEL0 0x01 // bitmap mask (1bit)
+	#define M_GPIO_SEL1 0x02 // bitmap mask (1bit)
+	#define M_GPIO_SEL2 0x04 // bitmap mask (1bit)
+	#define M_GPIO_SEL3 0x08 // bitmap mask (1bit)
+	#define M_GPIO_SEL4 0x10 // bitmap mask (1bit)
+	#define M_GPIO_SEL5 0x20 // bitmap mask (1bit)
+	#define M_GPIO_SEL6 0x40 // bitmap mask (1bit)
+	#define M_GPIO_SEL7 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_gpio_sel0:1;
+		REGWORD v_gpio_sel1:1;
+		REGWORD v_gpio_sel2:1;
+		REGWORD v_gpio_sel3:1;
+		REGWORD v_gpio_sel4:1;
+		REGWORD v_gpio_sel5:1;
+		REGWORD v_gpio_sel6:1;
+		REGWORD v_gpio_sel7:1;
+	} bit_r_gpio_sel; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_gpio_sel bit;} reg_r_gpio_sel; // register and bitmap access
+
+
+#define R_PLL_STA 0x50 // register access
+	#define M_PLL_LOCK 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD reserved_56:7;
+		REGWORD v_pll_lock:1;
+	} bit_r_pll_sta; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pll_sta bit;} reg_r_pll_sta; // register and bitmap access
+
+
+#define R_PLL_CTRL 0x50 // register access
+	#define M_PLL_NRES 0x01 // bitmap mask (1bit)
+	#define M_PLL_TST 0x02 // bitmap mask (1bit)
+	#define M_PLL_FREEZE 0x20 // bitmap mask (1bit)
+	#define M_PLL_M 0xC0 // bitmap mask (2bit)
+		#define M1_PLL_M 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_pll_nres:1;
+		REGWORD v_pll_tst:1;
+		REGWORD reserved_55:3;
+		REGWORD v_pll_freeze:1;
+		REGWORD v_pll_m:2;
+	} bit_r_pll_ctrl; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pll_ctrl bit;} reg_r_pll_ctrl; // register and bitmap access
+
+
+#define R_PLL_P 0x51 // register access
+	#define M_PLL_P 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_pll_p:8;
+	} bit_r_pll_p; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pll_p bit;} reg_r_pll_p; // register and bitmap access
+
+
+#define R_PLL_N 0x52 // register access
+	#define M_PLL_N 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_pll_n:8;
+	} bit_r_pll_n; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pll_n bit;} reg_r_pll_n; // register and bitmap access
+
+
+#define R_PLL_S 0x53 // register access
+	#define M_PLL_S 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_pll_s:8;
+	} bit_r_pll_s; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_pll_s bit;} reg_r_pll_s; // register and bitmap access
+
+
+#define A_FIFO_DATA 0x80 // register access
+	#define M_FIFO_DATA 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_data:8;
+	} bit_a_fifo_data; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_fifo_data bit;} reg_a_fifo_data; // register and bitmap access
+
+
+#define A_FIFO_DATA_NOINC 0x84 // register access
+	#define M_FIFO_DATA_NOINC 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_data_noinc:8;
+	} bit_a_fifo_data_noinc; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_fifo_data_noinc bit;} reg_a_fifo_data_noinc; // register and bitmap access
+
+
+#define R_INT_DATA 0x88 // register access
+	#define M_INT_DATA 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_int_data:8;
+	} bit_r_int_data; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_int_data bit;} reg_r_int_data; // register and bitmap access
+
+
+#define R_RAM_DATA 0xC0 // register access
+	#define M_RAM_DATA 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ram_data:8;
+	} bit_r_ram_data; // register and bitmap data
+	typedef union {REGWORD reg; bit_r_ram_data bit;} reg_r_ram_data; // register and bitmap access
+
+
+#define A_SL_CFG 0xD0 // register access
+	#define M_CH_SDIR 0x01 // bitmap mask (1bit)
+	#define M_CH_SNUM 0x3E // bitmap mask (5bit)
+		#define M1_CH_SNUM 0x02
+	#define M_ROUT 0xC0 // bitmap mask (2bit)
+		#define M1_ROUT 0x40
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ch_sdir:1;
+		REGWORD v_ch_snum:5;
+		REGWORD v_rout:2;
+	} bit_a_sl_cfg; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_sl_cfg bit;} reg_a_sl_cfg; // register and bitmap access
+
+
+#define A_CH_MSK 0xF4 // register access
+	#define M_CH_MSK 0xFF // bitmap mask (8bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ch_msk:8;
+	} bit_a_ch_msk; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_ch_msk bit;} reg_a_ch_msk; // register and bitmap access
+
+
+#define A_CON_HDLC 0xFA // register access
+	#define M_IFF 0x01 // bitmap mask (1bit)
+	#define M_HDLC_TRP 0x02 // bitmap mask (1bit)
+	#define M_FIFO_IRQ 0x1C // bitmap mask (3bit)
+		#define M1_FIFO_IRQ 0x04
+	#define M_DATA_FLOW 0xE0 // bitmap mask (3bit)
+		#define M1_DATA_FLOW 0x20
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_iff:1;
+		REGWORD v_hdlc_trp:1;
+		REGWORD v_fifo_irq:3;
+		REGWORD v_data_flow:3;
+	} bit_a_con_hdlc; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_con_hdlc bit;} reg_a_con_hdlc; // register and bitmap access
+
+
+#define A_SUBCH_CFG 0xFB // register access
+	#define M_BIT_CNT 0x07 // bitmap mask (3bit)
+		#define M1_BIT_CNT 0x01
+	#define M_START_BIT 0x38 // bitmap mask (3bit)
+		#define M1_START_BIT 0x08
+	#define M_LOOP_FIFO 0x40 // bitmap mask (1bit)
+	#define M_INV_DATA 0x80 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_bit_cnt:3;
+		REGWORD v_start_bit:3;
+		REGWORD v_loop_fifo:1;
+		REGWORD v_inv_data:1;
+	} bit_a_subch_cfg; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_subch_cfg bit;} reg_a_subch_cfg; // register and bitmap access
+
+
+#define A_CHANNEL 0xFC // register access
+	#define M_CH_FDIR 0x01 // bitmap mask (1bit)
+	#define M_CH_FNUM 0x1E // bitmap mask (4bit)
+		#define M1_CH_FNUM 0x02
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_ch_fdir:1;
+		REGWORD v_ch_fnum:4;
+		REGWORD reserved_57:3;
+	} bit_a_channel; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_channel bit;} reg_a_channel; // register and bitmap access
+
+
+#define A_FIFO_SEQ 0xFD // register access
+	#define M_NEXT_FIFO_DIR 0x01 // bitmap mask (1bit)
+	#define M_NEXT_FIFO_NUM 0x1E // bitmap mask (4bit)
+		#define M1_NEXT_FIFO_NUM 0x02
+	#define M_SEQ_END 0x40 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_next_fifo_dir:1;
+		REGWORD v_next_fifo_num:4;
+		REGWORD reserved_58:1;
+		REGWORD v_seq_end:1;
+		REGWORD reserved_59:1;
+	} bit_a_fifo_seq; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_fifo_seq bit;} reg_a_fifo_seq; // register and bitmap access
+
+
+#define A_FIFO_CTRL 0xFF // register access
+	#define M_FIFO_IRQMSK 0x01 // bitmap mask (1bit)
+	#define M_BERT_EN 0x02 // bitmap mask (1bit)
+	#define M_MIX_IRQ 0x04 // bitmap mask (1bit)
+	#define M_FR_ABO 0x08 // bitmap mask (1bit)
+	#define M_NO_CRC 0x10 // bitmap mask (1bit)
+	#define M_NO_REP 0x20 // bitmap mask (1bit)
+
+	typedef struct // bitmap construction
+	{
+		REGWORD v_fifo_irqmsk:1;
+		REGWORD v_bert_en:1;
+		REGWORD v_mix_irq:1;
+		REGWORD v_fr_abo:1;
+		REGWORD v_no_crc:1;
+		REGWORD v_no_rep:1;
+		REGWORD reserved_60:2;
+	} bit_a_fifo_ctrl; // register and bitmap data
+	typedef union {REGWORD reg; bit_a_fifo_ctrl bit;} reg_a_fifo_ctrl; // register and bitmap access
+
+
+#endif /* _XHFC24SUCC_H_ */
+
+/*___________________________________________________________________________________*/
+/*                                                                                   */
+/*  End of XHFC-2S4U / XHFC-4SU register definitions.                                */
+/*                                                                                   */
+/*  Total number of registers processed: 122 of 122                                  */
+/*  Total number of bitmaps processed  : 523                                         */
+/*                                                                                   */
+/*___________________________________________________________________________________*/
+/*                                                                                   */

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_pci2pi.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_pci2pi.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_pci2pi.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,135 @@
+/* $Id: xhfc_pci2pi.c,v 1.5 2007/02/13 10:43:45 crich Exp $
+ *
+ * PCI2PI Pci Bridge support for xhfc_su.c
+ *
+ * Authors : Martin Bachem, Joerg Ciesielski
+ * Contact : info at colognechip.com
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "xhfc_su.h"
+#include "xhfc_pci2pi.h"
+
+
+
+static PCI2PI_cfg PCI2PI_config = {
+	/* default PI_INTELMX config */
+	.del_cs = 0,
+	.del_rd = 0,
+	.del_wr = 0,
+	.del_ale = 0,
+	.del_adr = 0,
+	.del_dout = 0,
+	.default_adr = 0x00,
+	.default_dout = 0x00,
+	.pi_mode = PI_MODE,
+	.setup = 1,
+	.hold = 1,
+	.cycle = 1,
+	.ale_adr_first = 0,
+	.ale_adr_setup = 0,
+	.ale_adr_hold = 1,
+	.ale_adr_wait = 0,
+	.pause_seq = 1,
+	.pause_end = 0,
+	.gpio_out = 0,
+	.status_int_enable = 1,
+	.pi_int_pol = 0,
+	.pi_wait_enable = 0,
+	.spi_cfg0 = 0,
+	.spi_cfg1 = 0,
+	.spi_cfg2 = 0,
+	.spi_cfg3 = 0,
+	.eep_recover = 4,
+};
+
+/* base addr to address several XHFCs on one PCI2PI bridge */
+__u32 PCI2PI_XHFC_OFFSETS[PCI2PI_MAX_XHFC] = {0, 0x400};
+
+
+/***********************************/
+/* initialise the XHFC PCI Bridge  */
+/* return 0 on success.            */
+/***********************************/
+int
+init_pci_bridge(xhfc_pi * pi)
+{
+	int err = -ENODEV;
+
+	printk(KERN_INFO "%s %s: using PCI2PI Bridge at 0x%p\n",
+	       pi->name, __FUNCTION__, pi->hw_membase);
+
+	/* test if Bridge regsiter accessable */
+	WritePCI2PI_u32(pi, PCI2PI_DEL_CS, 0x0);
+	if (ReadPCI2PI_u32(pi, PCI2PI_DEL_CS) == 0x00) {
+		WritePCI2PI_u32(pi, PCI2PI_DEL_CS, 0xFFFFFFFF);
+		if (ReadPCI2PI_u32(pi, PCI2PI_DEL_CS) == 0xF) {
+			err = 0;
+		}
+	}
+	if (err)
+		return (err);
+
+	/* enable hardware reset XHFC */
+	WritePCI2PI_u32(pi, PCI2PI_GPIO_OUT, GPIO_OUT_VAL);
+
+	WritePCI2PI_u32(pi, PCI2PI_PI_MODE, PCI2PI_config.pi_mode);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_CS, PCI2PI_config.del_cs);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_RD, PCI2PI_config.del_rd);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_WR, PCI2PI_config.del_wr);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_ALE, PCI2PI_config.del_ale);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_ADR, PCI2PI_config.del_adr);
+	WritePCI2PI_u32(pi, PCI2PI_DEL_DOUT, PCI2PI_config.del_dout);
+	WritePCI2PI_u32(pi, PCI2PI_DEFAULT_ADR, PCI2PI_config.default_adr);
+	WritePCI2PI_u32(pi, PCI2PI_DEFAULT_DOUT,
+			PCI2PI_config.default_dout);
+
+	WritePCI2PI_u32(pi, PCI2PI_CYCLE_SHD, 0x80 * PCI2PI_config.setup
+			+ 0x40 * PCI2PI_config.hold + PCI2PI_config.cycle);
+
+	WritePCI2PI_u32(pi, PCI2PI_ALE_ADR_WHSF,
+			PCI2PI_config.ale_adr_first +
+			PCI2PI_config.ale_adr_setup * 2 +
+			PCI2PI_config.ale_adr_hold * 4 +
+			PCI2PI_config.ale_adr_wait * 8);
+
+	WritePCI2PI_u32(pi, PCI2PI_CYCLE_PAUSE,
+			0x10 * PCI2PI_config.pause_seq +
+			PCI2PI_config.pause_end);
+	WritePCI2PI_u32(pi, PCI2PI_STATUS_INT_ENABLE,
+			PCI2PI_config.status_int_enable);
+
+	WritePCI2PI_u32(pi, PCI2PI_PI_INT_POL,
+			2 * PCI2PI_config.pi_wait_enable +
+			PCI2PI_config.pi_int_pol);
+
+	WritePCI2PI_u32(pi, PCI2PI_SPI_CFG0, PCI2PI_config.spi_cfg0);
+	WritePCI2PI_u32(pi, PCI2PI_SPI_CFG1, PCI2PI_config.spi_cfg1);
+	WritePCI2PI_u32(pi, PCI2PI_SPI_CFG2, PCI2PI_config.spi_cfg2);
+	WritePCI2PI_u32(pi, PCI2PI_SPI_CFG3, PCI2PI_config.spi_cfg3);
+	WritePCI2PI_u32(pi, PCI2PI_EEP_RECOVER, PCI2PI_config.eep_recover);
+	ReadPCI2PI_u32(pi, PCI2PI_STATUS);
+
+
+	/* release hardware reset XHFC */
+	WritePCI2PI_u32(pi, PCI2PI_GPIO_OUT, GPIO_OUT_VAL | PCI2PI_GPIO7_NRST);
+	udelay(10);
+
+	return (err);
+}

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_pci2pi.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_pci2pi.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_pci2pi.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,678 @@
+/* $Id: xhfc_pci2pi.h,v 1.4 2006/03/22 23:29:59 keil Exp $
+ *
+ * PCI2PI Pci Bridge support for xhfc_su.c
+ *
+ * Authors : Martin Bachem, Joerg Ciesielski
+ * Contact : info at colognechip.com
+ *
+ * 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.
+ *
+ */
+
+#ifndef _XHFC_PCI2PI_H_
+#define _XHFC_PCI2PI_H_
+
+#include "xhfc24succ.h"
+
+/* differnt PCI modes supported by PCI2PI */
+#define PI_INTELNOMX	0
+#define PI_INTELMX	1
+#define PI_MOT		2
+#define PI_MOTMX	3
+#define PI_SPI		4
+#define PI_EEPPRG	6
+#define PI_AUTOEEP	7
+
+/* PI_MODE to GPIO mapping */
+#define PI_INTELMX_GPIO		PCI2PI_GPIO3_MODE1	/* ALE pulse switches to MULTIPLEXED */
+#define PI_INTELNOMX_GPIO	PCI2PI_GPIO3_MODE1
+#define PI_MOT_GPIO		PCI2PI_GPIO2_MODE0
+#define PI_MOTMX_GPIO		PCI2PI_GPIO2_MODE0
+#define PI_SPI_GPIO		0
+#define PI_AUTOEEP_GPIO		PCI2PI_GPIO2_MODE0 | PCI2PI_GPIO3_MODE1
+
+
+/* PCI2PI GPIO to XHFC signal mapping */
+#define PCI2PI_GPIO7_NRST	0x80
+#define PCI2PI_GPIO6_TLA3	0x40
+#define PCI2PI_GPIO5_TLA2	0x20
+#define PCI2PI_GPIO4_TLA1	0x10
+#define PCI2PI_GPIO3_MODE1	0x08
+#define PCI2PI_GPIO2_MODE0	0x04
+#define PCI2PI_GPIO1_BOND1	0x02
+#define PCI2PI_GPIO0_BOND0	0x01
+
+/* PCI2PI GPIO XHFC Bond out selection */
+#define XHFC_1SU_BOND	0
+#define XHFC_2SU_BOND	PCI2PI_GPIO0_BOND0
+#define XHFC_2S4U_BOND	PCI2PI_GPIO1_BOND1
+#define XHFC_4SU_BOND	PCI2PI_GPIO1_BOND1 | PCI2PI_GPIO0_BOND0
+
+/* membase offset to address XHFC controllers */
+#define PCI2PI_MAX_XHFC 2
+extern __u32 PCI2PI_XHFC_OFFSETS[PCI2PI_MAX_XHFC];
+
+
+/*******************************************************/
+/*******************************************************/
+
+/* Select processor interface mode and Bond option     */
+/* of PCI2PI bridge */
+#define PI_MODE		PI_INTELMX
+#define XHFC_BOND	XHFC_4SU_BOND
+
+/*******************************************************/
+/*******************************************************/
+
+#if (PI_MODE == PI_INTELNOMX)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_INTELNOMX_GPIO
+
+#elif (PI_MODE == PI_INTELMX)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_INTELMX_GPIO
+
+#elif (PI_MODE == PI_MOT)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_MOT_GPIO
+
+#elif (PI_MODE == PI_MOTMX)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_MOTMX_GPIO
+
+#elif (PI_MODE == PI_SPI)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_SPI_GPIO
+
+#elif (PI_MODE == PI_AUTOEEP)
+#define GPIO_OUT_VAL	XHFC_BOND | PI_AUTOEEP_GPIO
+#endif
+
+/*******************************************************/
+
+
+#define PCI2PI_VENDORID		0x1397
+
+#define PCI2PI_DEVICEID		0xA003
+#define MAX_PCI2PI		2
+
+#define RV_PCI2PI_OK		0
+#define RV_PCI2PI_ERROR		1
+
+/* PCI2PI register definitions */
+#define PCI2PI_OFFSET		0x00000800
+#define PCI2PI_DEL_CS		4*0x00 + PCI2PI_OFFSET
+#define PCI2PI_DEL_RD		4*0x01 + PCI2PI_OFFSET
+#define PCI2PI_DEL_WR		4*0x02 + PCI2PI_OFFSET
+#define PCI2PI_DEL_ALE		4*0x03 + PCI2PI_OFFSET
+#define PCI2PI_DEL_ADR		4*0x04 + PCI2PI_OFFSET
+#define PCI2PI_DEL_DOUT		4*0x05 + PCI2PI_OFFSET
+#define PCI2PI_DEFAULT_ADR	4*0x06 + PCI2PI_OFFSET
+#define PCI2PI_DEFAULT_DOUT	4*0x07 + PCI2PI_OFFSET
+
+
+/*
+PCI2PI_PI_MODE bit 2..0:
+000: Intel non multiplexed
+001: Intel multiplexed
+010: Motorola
+100: SPI Motorola
+110: EEPROM programming mode throug PCIIF00 Target
+111: XHFC AutoEEPROM mode
+*/
+#define PCI2PI_PI_MODE		4*0x08 + PCI2PI_OFFSET
+
+#define PCI2PI_CYCLE_SHD	4*0x09 + PCI2PI_OFFSET
+#define PCI2PI_ALE_ADR_WHSF	4*0x0a + PCI2PI_OFFSET
+#define PCI2PI_CYCLE_PAUSE	4*0x0b + PCI2PI_OFFSET
+#define PCI2PI_GPIO_OUT		4*0x0c + PCI2PI_OFFSET
+#define PCI2PI_G1		4*0x0e + PCI2PI_OFFSET
+#define PCI2PI_G0		4*0x0f + PCI2PI_OFFSET
+
+/*
+bit0: is set by PI_INT active, is reseted by reading this register
+bit1: is set by PI_WAIT active, is reseted by reading this register
+*/
+#define PCI2PI_STATUS		4*0x10 + PCI2PI_OFFSET
+
+
+/* bit0: enable PCI interrupt output */
+#define PCI2PI_STATUS_INT_ENABLE	4*0x11 + PCI2PI_OFFSET
+
+/*
+bit0: 0 = low active interrupt is detected at PI_INT
+bit0: 1 = high active interrupt is detected at PI_INT
+*/
+#define PCI2PI_PI_INT_POL	4*0x12 + PCI2PI_OFFSET
+
+/* SPI registers */
+/* 32 bit SPI master data output register */
+#define PCI2PI_SPI_MO_DATA	4*0x20 + PCI2PI_OFFSET
+
+/* 32 bit SPI master data input register */
+#define PCI2PI_SPI_MI_DATA	4*0x21 + PCI2PI_OFFSET
+
+/*
+bit 0: 0 SPI bits are processing on the serial input/output
+bit 0: 1 SPI bits are processed, new data can be written or read
+bit 1..31: unused
+*/
+#define PCI2PI_SPI_STATUS	4*0x22 + PCI2PI_OFFSET
+
+/*
+bit 0: spi clock polarity, defines level for SPISEL1
+bit 1: spi clock phase, defines sampling edge, 0?, 1?
+bit 2: 0MSB first (default) , 1LSB first
+bit 3: 1SPI clock permanent during SPISEL1
+*/
+#define PCI2PI_SPI_CFG0		4*0x28 + PCI2PI_OFFSET
+
+/*
+bit 0..3: spi clock frequency, SPI clock period  (value+1) x 2 x PCIperiod
+0: 2 PCIperiods
+1:
+*/
+#define PCI2PI_SPI_CFG1		4*0x29 + PCI2PI_OFFSET
+
+/* bit 0..3: SPI Device SEL: defines level of D0..D3, XHFC SPI address */
+#define PCI2PI_SPI_CFG2		4*0x2A + PCI2PI_OFFSET
+
+/*
+bit 0: 1spi master out permanent driven
+bit 1: 1SPISEL remains low between bytes of a sequence
+bit 2: 1SPISEL remains low permanent
+*/
+#define PCI2PI_SPI_CFG3		4*0x2B + PCI2PI_OFFSET
+
+/* bit 0..3: default 0100 */
+#define PCI2PI_EEP_RECOVER	4*0x30 + PCI2PI_OFFSET
+
+typedef struct _PCI2PI_cfg {
+	__u32 del_cs;		/* Bit 3..0, bit 3: 0.5 PCI clk,
+				   bits 2..0: gate delay */
+	__u32 del_rd;
+	__u32 del_wr;
+	__u32 del_ale;
+
+	__u32 del_adr;		/* delay between default address
+				   value and selected address */
+	__u32 del_dout;		/* delay between default data
+				   value and written data */
+	__u32 default_adr;	/* default address value bit 0..7 */
+
+	__u32 default_dout;	/* default data value bit 0..7 */
+
+
+	__u32 pi_mode;		/* pi_mode bit 2..0:
+				   000: Intel non multiplexed
+				   001: Intel multiplexed
+				   010: Motorola
+				   100: SPI Motorola
+				   110: EEPROM programming mode throug PCIIF00 Target
+				   111: XHFC AutoEEPROM mode
+				 */
+
+	__u32 setup;		/* address/data setup berfore rd/wr/cs,
+				   0 or 1 PCI clk */
+
+	__u32 hold;		/* address/data hold after rd/wr/cs,
+				   0 or 1 PCI clk */
+
+	__u32 cycle;		/* bit 0 only
+				   address/data adds 0 or 1 PCI clk to /rd/wr/cs
+				   access time (cycle+1) PCI clk
+				 */
+
+	__u32 ale_adr_first;	/* bit 0 = 0: address valid before ALE=1
+				   bit 0 = 1: ALE=1  before adress valid */
+
+	__u32 ale_adr_setup;	/* bit 0 = 0 setup for ALE/addr = 0s
+				   bit 0 = 1:setup for ALE/addr = 1 PCI clk
+				   ALE/addr depends on ale_adr_first setting */
+
+	__u32 ale_adr_hold;	/* bit 0 = 0 hold for address after ALE: 0s
+				   bit 0 = 1:hold for address after ALE: 1 PCI clk */
+
+	__u32 ale_adr_wait;	/* bit 0 = 0: 0 PCI clk delay between address and data phase
+				   bit 0 = 1: 1 PCI clk delay between address and data phase */
+
+	__u32 pause_seq;	/* bit 0..3: number of PCI clocks between read/write
+				   acceses due to DWORD/WORD burst access */
+
+	__u32 pause_end;	/* bit 0..3: number of PCI clocks after DWORD/WORD
+				   burst access /delays PCI_TRDY signal */
+
+	__u32 gpio_out;		/* bit 0..7: GPIO output value */
+
+	__u32 status_int_enable;	/* bit 0: enables PCI interrupt for PI_INT signal
+					   bit 1: enables PCI interrupt for PI_NWAIT signal */
+
+	__u32 pi_int_pol;	/* bit 0: polarity of PI_INT signal */
+
+	__u32 pi_wait_enable;	/* access length can be controled by /wait  signal
+				   0 wait disabled, 1 wait enabled */
+
+	__u32 spi_cfg0;
+	__u32 spi_cfg1;
+	__u32 spi_cfg2;
+	__u32 spi_cfg3;
+	__u32 eep_recover;
+
+} PCI2PI_cfg;
+
+
+/*
+
+read and write functions to access registers of the PCI bridge
+
+*/
+
+static inline __u8
+ReadPCI2PI_u8(xhfc_pi * pi, __u16 reg_addr)
+{
+	return (*(volatile __u8 *) (pi->membase + reg_addr));
+}
+
+static inline __u16
+ReadPCI2PI_u16(xhfc_pi * pi, __u16 reg_addr)
+{
+	return (*(volatile __u16 *) (pi->membase + reg_addr));
+}
+
+static inline __u32
+ReadPCI2PI_u32(xhfc_pi * pi, __u16 reg_addr)
+{
+	return (*(volatile __u32 *) (pi->membase + reg_addr));
+}
+
+static inline void
+WritePCI2PI_u8(xhfc_pi * pi, __u16 reg_addr, __u8 value)
+{
+	*((volatile __u8 *) (pi->membase + reg_addr)) = value;
+}
+
+static inline void
+WritePCI2PI_u16(xhfc_pi * pi, __u16 reg_addr, __u16 value)
+{
+	*((volatile __u16 *) (pi->membase + reg_addr)) = value;
+}
+
+static inline void
+WritePCI2PI_u32(xhfc_pi * pi, __u16 reg_addr, __u32 value)
+{
+	*((volatile __u32 *) (pi->membase + reg_addr)) = value;
+}
+
+
+/*
+
+read and write functions to access a XHFC at the local bus interface of the PCI 
+bridge
+
+there are two sets of functions to access the XHFC in the following different 
+interface modes:
+
+multiplexed bus interface modes PI_INTELMX and PI_MOTMX
+- these modes use a single (atomic) PCI cycle to read or write a XHFC register
+
+non multiplexed bus interface modes PI_INTELNOMX, PI_MOTMX and PI_SPI
+
+- these modes use a separate PCI cycles to select the XHFC register and to read 
+or write data. That means these register accesses are non atomic and could be 
+interrupted by an interrupt. The driver must take care that a register access in 
+these modes is not interrupted by its own interrupt handler.
+
+
+*/
+
+
+/*****************************************************************************/
+
+
+#if ((PI_MODE==PI_INTELMX) || (PI_MODE==PI_MOTMX))
+
+
+/*
+functions for multiplexed access
+*/
+static inline __u8
+read_xhfc(xhfc_t * xhfc, __u8 reg_addr)
+{
+	return (*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2)));
+}
+
+
+/*
+read four bytes from the same register address
+e.g. A_FIFO_DATA
+this function is only defined for software compatibility here
+*/
+static inline __u32
+read32_xhfc(xhfc_t * xhfc, __u8 reg_addr)
+{
+	__u32 value;
+
+	value =  (*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2)));
+	value |= (*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2))) << 8;
+	value |= (*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2))) << 16;
+	value |= (*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2))) << 24;
+
+	return (value);
+}
+
+static inline void
+write_xhfc(xhfc_t * xhfc, __u8 reg_addr, __u8 value)
+{
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2))) = value;
+}
+
+/*
+writes four bytes to the same register address
+e.g. A_FIFO_DATA
+this function is only defined for software compatibility here
+*/
+static inline void
+write32_xhfc(xhfc_t * xhfc, __u8 reg_addr, __u32 value)
+{
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2))) = value & 0xff;
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2))) = (value >>8) & 0xff;
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2))) = (value >>16) & 0xff;
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2))) = (value >>24) & 0xff;
+}
+
+
+/* always reads a single byte with short read method
+this allows to read ram based registers
+that normally requires long read access times
+*/
+static inline __u8
+sread_xhfc(xhfc_t * xhfc, __u8 reg_addr)
+{
+	(*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (reg_addr << 2)));
+	return (*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + (R_INT_DATA << 2)));
+}
+
+/* this function reads the currently selected regsiter from XHFC and is only 
+required for non multiplexed access modes. For multiplexed access modes this 
+function is only defined for for software compatibility. */
+
+static inline __u8
+read_xhfcregptr(xhfc_t * xhfc)
+{
+	return 0;
+}
+
+/* this function writes the XHFC register address pointer and is only 
+required for non multiplexed access modes. For multiplexed access modes this 
+function is only defined for for software compatibility. */
+
+static inline void
+write_xhfcregptr(xhfc_t * xhfc, __u8 reg_addr)
+{
+}
+
+
+#endif /* PI_MODE==PI_INTELMX || PI_MODE==PI_MOTMX */
+
+
+
+/*****************************************************************************/
+
+
+#if PI_MODE==PI_INTELNOMX || PI_MODE==PI_MOT
+/*
+functions for non multiplexed access
+
+XHFC register address pointer is accessed with PCI address A2=1 and XHFC data 
+port is accessed with PCI address A2=0
+
+*/
+
+static inline __u8
+read_xhfc(xhfc_t * xhfc, __u8 reg_addr)
+{
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) = reg_addr;
+	return (*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx]));
+}
+
+
+/*
+
+read four bytes from the same register address by using a 32bit PCI access. The 
+PCI bridge generates for 8 bit data read cycles at the local bus interface.
+
+*/
+
+static inline __u32
+read32_xhfc(xhfc_t * xhfc, __u8 reg_addr)
+{
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) = reg_addr;
+	return (*(volatile __u32 *) xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx]);
+}
+
+static inline void
+write_xhfc(xhfc_t * xhfc, __u8 reg_addr, __u8 value)
+{
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) = reg_addr;
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx])) = value;
+}
+
+/*
+
+writes four bytes to the same register address (e.g. A_FIFO_DATA) by using a 
+32bit PCI access. The PCI bridge generates for 8 bit data write cycles at the 
+local bus interface.
+
+*/
+static inline void
+write32_xhfc(xhfc_t * xhfc, __u8 reg_addr, __u32 value)
+{
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) = reg_addr;
+	*((volatile __u32 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx])) = value;
+}
+
+
+/*
+
+reads a single byte with short read method (r*). This allows to read ram based 
+registers that normally requires long read access times
+
+*/
+static inline __u8
+sread_xhfc(xhfc_t * xhfc, __u8 reg_addr)
+{
+	
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) = reg_addr;
+	(*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] ));
+	*((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) = R_INT_DATA;
+	return (*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx]));
+}
+
+/*
+
+this function reads the currently selected regsiter from XHFC
+
+*/
+static inline __u8
+read_xhfcregptr(xhfc_t * xhfc)
+{
+	return (*(volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4));
+}
+
+/* this function writes the XHFC register address pointer */
+
+static inline void
+write_xhfcregptr(xhfc_t * xhfc, __u8 reg_addr)
+{
+    *((volatile __u8 *) (xhfc->pi->membase + PCI2PI_XHFC_OFFSETS[xhfc->chipidx] + 4)) = reg_addr;
+}
+
+
+
+#endif /* PI_MODE==PI_INTELNOMX || PI_MODE==PI_MOT */
+
+
+/*****************************************************************************/
+
+#if PI_MODE == PI_SPI
+
+// SPI mode transaction bit definitions 
+#define SPI_ADDR	0x40
+#define SPI_DATA	0x00
+#define SPI_RD		0x80
+#define SPI_WR		0x00
+#define SPI_BROAD	0x20
+#define SPI_MULTI	0x20
+
+
+/*
+functions for SPI access
+
+*/
+
+
+static inline __u8
+read_xhfc(xhfc_t * xhfc, __u8 reg_addr)
+{
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(hw, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer
+	WritePCI2PI_u32(hw, PCI2PI_SPI_MO_DATA, ((SPI_ADDR | SPI_WR | xhfc->chipidx) << 24) | (reg_addr << 16) | ((SPI_DATA | SPI_RD) << 8));
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(hw, PCI2PI_SPI_STATUS) & 1));
+	// read data from the SPI data receive register and return one byte
+	return (__u8) (ReadPCI2PI_u32(hw, PCI2PI_SPI_MI_DATA) & 0xFF);
+}
+
+
+/*
+
+read four bytes from the same register address by using a SPI multiple read access
+
+*/
+
+static inline __u32
+read32_xhfc(xhfc_t * xhfc, __u8 reg_addr)
+{
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 16 clock SPI master transfer
+	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA, ((SPI_ADDR | SPI_WR | xhfc->chipidx) << 8) | reg_addr);
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 8 clock SPI master transfer
+	WritePCI2PI_u8(xhfc->pi, PCI2PI_SPI_MO_DATA, (SPI_DATA | SPI_RD | SPI_MULTI));
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer
+	// output data is arbitrary
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA, 0);
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// read data from the SPI data receive register and return four bytes
+	return (__u32) be32_to_cpu(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_MI_DATA));
+}
+
+static inline void
+write_xhfc(xhfc_t * xhfc, __u8 reg_addr, __u8 value)
+{
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA, ((SPI_ADDR | SPI_WR | xhfc->chipidx) << 24) | (reg_addr << 16) | ((SPI_DATA | SPI_WR) << 8) | value);
+}
+
+/*
+
+writes four bytes to the same register address (e.g. A_FIFO_DATA) by using a SPI 
+multiple write access
+
+*/
+static inline void
+write32_xhfc(xhfc_t * xhfc, __u8 reg_addr, __u32 value)
+{
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 16 clock SPI master transfer
+	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA, ((SPI_ADDR | SPI_WR | xhfc->chipidx) << 8) | reg_addr);
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 8 clock SPI master transfer
+	WritePCI2PI_u8(xhfc->pi, PCI2PI_SPI_MO_DATA, (SPI_DATA | SPI_WR | SPI_MULTI));
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA, cpu_to_be32(value));
+}
+
+
+/*
+
+reads a single byte with short read method (r*). This allows to read ram based 
+registers that normally requires long read access times
+
+*/
+static inline __u8
+sread_xhfc(xhfc_t * xhfc, __u8 reg_addr)
+{
+        // wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA ,((SPI_ADDR | SPI_WR | xhfc->chipidx) << 24) | (reg_addr << 16) | ((SPI_DATA | SPI_RD) << 8));
+	
+	
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 32 clock SPI master transfer to read R_INT_DATA register
+	WritePCI2PI_u32(xhfc->pi, PCI2PI_SPI_MO_DATA, ((SPI_ADDR | SPI_WR | xhfc->chipidx) << 24) | (R_INT_DATA << 16) | ((SPI_DATA | SPI_RD) << 8));
+	
+	
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// read data from the SPI data receive register and return one byte
+	return (__u8) (ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_MI_DATA) & 0xFF);
+}
+
+/*
+
+this function reads the currently selected regsiter from XHFC
+
+*/
+static inline __u8
+read_xhfcregptr(xhfc_t * xhfc)
+{
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 16 clock SPI master transfer
+	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA, ((SPI_ADDR | SPI_RD | xhfc->chipidx) << 8));
+	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// read data from the SPI data receive register and return one byte
+	return (__u8) (ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_MI_DATA) & 0xFF);
+}
+
+/* this function writes the XHFC register address pointer */
+
+static inline void
+write_xhfcregptr(xhfc_t * xhfc, __u8 reg_addr)
+{
+    	// wait until SPI master is idle
+	while (!(ReadPCI2PI_u32(xhfc->pi, PCI2PI_SPI_STATUS) & 1));
+	// initiate a 16 clock SPI master transfer
+	WritePCI2PI_u16(xhfc->pi, PCI2PI_SPI_MO_DATA, ((SPI_ADDR | SPI_WR | xhfc->chipidx) << 8) | reg_addr);
+}
+
+#endif	/* PI_MODE == PI_SPI */
+
+
+
+/* Function Prototypes */
+int init_pci_bridge(xhfc_pi * pi);
+
+#endif	/* _XHFC_PCI2PI_H_ */

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_su.c
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_su.c	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_su.c	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,2182 @@
+/* xhfc_su.c
+ * mISDN driver for CologneChip AG's XHFC
+ *
+ * Authors : Martin Bachem, Joerg Ciesielski
+ * Contact : info at colognechip.com
+ *
+ * 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.
+ *
+ *******************************************************************************
+ *
+ * MODULE PARAMETERS:
+ * (NOTE: layermask and protocol must be given for all ports,
+ *  not for the number of cards.)
+ *
+ * - protocol=<p1>[,p2,p3...]
+ *   Values:
+ *      <bit  3 -  0>  D-channel protocol id
+ *      <bit  4 - 31>  Flags for special features
+ *
+ *      D-channel protocol ids
+ *        - 1       1TR6 (not released yet)
+ *        - 2       DSS1
+ *
+ *      Flags for special features
+ *        <bit 4>   0x0010  Net side stack (NT mode)
+ *        <bit 5>   0x0020  Line Interface Mode (0=S0, 1=Up)
+ *        <bit 6>   0x0040  st line polarity (1=exchanged)
+ *        <bit 7>   0x0080  B1 channel loop ST-RX -> XHFC PCM -> ST-TX
+ *        <bit 8>   0x0100  B2 channel loop ST-RX -> XHFC PCM -> ST-TX
+ *        <bit 9>   0x0200  D channel loop  ST-RX -> XHFC PCM -> ST-TX
+ *
+ * - layermask=<l1>[,l2,l3...] (32bit):
+ *        mask of layers to be used for D-channel stack
+ *
+ * - debug:
+ *        enable debugging (see xhfc_su.h for debug options)
+ *
+ */
+ 
+#include <linux/mISDNif.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <asm/timex.h>
+#include "core.h"
+#include "helper.h"
+#include "debug.h"
+#include "xhfc_su.h"
+#include "xhfc24succ.h"
+
+#if BRIDGE == BRIDGE_PCI2PI
+#include "xhfc_pci2pi.h"
+#endif
+
+static const char xhfc_rev[] = "1.22 - 10.05.2007";
+
+#define MAX_CARDS	8
+static int card_cnt;
+static u_int protocol[MAX_CARDS * MAX_PORT];
+static int layermask[MAX_CARDS * MAX_PORT];
+
+static mISDNobject_t hw_mISDNObj;
+static int debug = 0;
+
+
+#ifdef MODULE
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef OLD_MODULE_PARAM
+MODULE_PARM(debug, "1i");
+#define MODULE_PARM_T   "1-4i"
+MODULE_PARM(protocol, MODULE_PARM_T);
+MODULE_PARM(layermask, MODULE_PARM_T);
+#else
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+
+#ifdef OLD_MODULE_PARAM_ARRAY
+static int num_protocol=0, num_layermask=0;
+module_param_array(protocol, uint, num_protocol, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, num_layermask, S_IRUGO | S_IWUSR);
+#else
+module_param_array(protocol, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(layermask, uint, NULL, S_IRUGO | S_IWUSR);
+#endif
+#endif
+#endif
+
+/* static function prototypes */
+static void release_card(xhfc_pi * pi);
+static void setup_fifo(xhfc_t * xhfc, __u8 fifo, __u8 conhdlc, __u8 subcfg,
+                       __u8 fifoctrl, __u8 enable);
+static void setup_su(xhfc_t * xhfc, __u8 pt, __u8 bc, __u8 enable);
+static int  setup_channel(xhfc_t * xhfc, __u8 channel, int protocol);
+
+
+/****************************************************/
+/* Physical S/U commands to control Line Interface  */
+/****************************************************/
+static char *HFC_PH_COMMANDS[] = {
+	"HFC_L1_ACTIVATE_TE",
+	"HFC_L1_FORCE_DEACTIVATE_TE",
+	"HFC_L1_ACTIVATE_NT",
+	"HFC_L1_DEACTIVATE_NT",
+	"HFC_L1_TESTLOOP_B1",
+	"HFC_L1_TESTLOOP_B2",
+	"HFC_L1_TESTLOOP_D"
+};
+
+static void
+xhfc_ph_command(xhfc_port_t * port, u_char command)
+{
+	xhfc_t * xhfc = port->xhfc;
+	
+	if (debug & DEBUG_HFC_S0_STATES)
+		printk(KERN_INFO "%s %s: %s (%i)\n",
+		       __FUNCTION__, port->name, HFC_PH_COMMANDS[command], command);
+
+	switch (command) {
+		case HFC_L1_ACTIVATE_TE:
+			write_xhfc(xhfc, R_SU_SEL, port->idx);
+			write_xhfc(xhfc, A_SU_WR_STA, STA_ACTIVATE);
+			break;
+
+		case HFC_L1_FORCE_DEACTIVATE_TE:
+			write_xhfc(xhfc, R_SU_SEL, port->idx);
+			write_xhfc(xhfc, A_SU_WR_STA, STA_DEACTIVATE);
+			break;
+
+		case HFC_L1_ACTIVATE_NT:
+			write_xhfc(xhfc, R_SU_SEL, port->idx);
+			write_xhfc(xhfc, A_SU_WR_STA,
+				   STA_ACTIVATE | M_SU_SET_G2_G3);
+			break;
+
+		case HFC_L1_DEACTIVATE_NT:
+			write_xhfc(xhfc, R_SU_SEL, port->idx);
+			write_xhfc(xhfc, A_SU_WR_STA, STA_DEACTIVATE);
+			break;
+
+		case HFC_L1_TESTLOOP_B1:
+			setup_fifo(xhfc, port->idx*8,   0xC6, 0, 0, 0);	/* connect B1-SU RX with PCM TX */
+			setup_fifo(xhfc, port->idx*8+1, 0xC6, 0, 0, 0);	/* connect B1-SU TX with PCM RX */
+
+			write_xhfc(xhfc, R_SLOT, port->idx*8);		/* PCM timeslot B1 TX */
+			write_xhfc(xhfc, A_SL_CFG, port->idx*8 + 0x80); 	/* enable B1 TX timeslot on STIO1 */
+
+			write_xhfc(xhfc, R_SLOT, port->idx*8+1);		/* PCM timeslot B1 RX */
+			write_xhfc(xhfc, A_SL_CFG, port->idx*8+1 + 0xC0); /* enable B1 RX timeslot on STIO1*/
+
+			setup_su(xhfc, port->idx, 0, 1);
+			break;
+
+		case HFC_L1_TESTLOOP_B2:
+			setup_fifo(xhfc, port->idx*8+2, 0xC6, 0, 0, 0);	/* connect B2-SU RX with PCM TX */
+			setup_fifo(xhfc, port->idx*8+3, 0xC6, 0, 0, 0);	/* connect B2-SU TX with PCM RX */
+
+			write_xhfc(xhfc, R_SLOT, port->idx*8+2);		/* PCM timeslot B2 TX */
+			write_xhfc(xhfc, A_SL_CFG, port->idx*8+2 + 0x80); /* enable B2 TX timeslot on STIO1 */
+
+			write_xhfc(xhfc, R_SLOT, port->idx*8+3);		/* PCM timeslot B2 RX */
+			write_xhfc(xhfc, A_SL_CFG, port->idx*8+3 + 0xC0); /* enable B2 RX timeslot on STIO1*/
+
+			setup_su(xhfc, port->idx, 1, 1);
+			break;
+
+		case HFC_L1_TESTLOOP_D:
+			setup_fifo(xhfc, port->idx*8+4, 0xC4, 2, M_FR_ABO, 1);	/* connect D-SU RX with PCM TX */
+			setup_fifo(xhfc, port->idx*8+5, 0xC4, 2, M_FR_ABO | M_FIFO_IRQMSK, 1);	/* connect D-SU TX with PCM RX */
+			
+			write_xhfc(xhfc, R_SLOT, port->idx*8+4);		/* PCM timeslot D TX */
+			write_xhfc(xhfc, A_SL_CFG, port->idx*8 + 4 + 0x80); 	/* enable D TX timeslot on STIO1 */
+
+			write_xhfc(xhfc, R_SLOT, port->idx*8 + 5);		/* PCM timeslot D RX */
+			write_xhfc(xhfc, A_SL_CFG, port->idx*8 + 5 + 0xC0); /* enable D RX timeslot on STIO1*/
+			break;
+	}
+}
+
+
+static void
+l1_timer_start_t3(xhfc_port_t * port)
+{
+	if (!timer_pending(&port->t3_timer)) {
+		if (debug & DEBUG_HFC_S0_STATES)
+			printk(KERN_INFO "%s %s\n", __FUNCTION__, port->name);
+		port->t3_timer.expires = jiffies + (XHFC_TIMER_T3 * HZ) / 1000;
+		add_timer(&port->t3_timer);
+	}
+}
+
+static void
+l1_timer_stop_t3(xhfc_port_t * port)
+{
+	clear_bit(HFC_L1_ACTIVATING, &port->l1_flags);
+	if (timer_pending(&port->t3_timer)) {
+		if (debug & DEBUG_HFC_S0_STATES)
+			printk(KERN_INFO "%s %s\n", __FUNCTION__, port->name);
+		del_timer(&port->t3_timer);
+	}
+}
+
+/***********************************/
+/* called when timer t3 expires    */
+/* -> activation failed            */
+/*    force clean L1 deactivation  */
+/***********************************/
+static void
+l1_timer_expire_t3(xhfc_port_t * port)
+{
+	channel_t * dch = &port->xhfc->chan[port->idx * 4 + 2].ch;
+	
+	if (debug & DEBUG_HFC_S0_STATES)
+		printk(KERN_INFO "%s %s\n", __FUNCTION__, port->name);
+
+	clear_bit(HFC_L1_ACTIVATING, &port->l1_flags),
+	xhfc_ph_command(port, HFC_L1_FORCE_DEACTIVATE_TE);
+
+	mISDN_queue_data(&dch->inst, FLG_MSG_UP,
+		(PH_DEACTIVATE | INDICATION),
+		0, 0, NULL, 0);
+	mISDN_queue_data(&dch->inst, dch->inst.id | MSG_BROADCAST,
+		MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_DEACTIVATED,
+		0, NULL, 0);
+}
+
+static void
+l1_timer_start_t4(xhfc_port_t * port)
+{
+	set_bit(HFC_L1_DEACTTIMER, &port->l1_flags);
+	if (!timer_pending(&port->t4_timer)) {
+		if (debug & DEBUG_HFC_S0_STATES)
+			printk(KERN_INFO "%s %s\n", __FUNCTION__, port->name);
+
+		port->t4_timer.expires =
+		    jiffies + (XHFC_TIMER_T4 * HZ) / 1000;
+		add_timer(&port->t4_timer);
+	}
+}
+
+static void
+l1_timer_stop_t4(xhfc_port_t * port)
+{
+	clear_bit(HFC_L1_DEACTTIMER, &port->l1_flags);
+	if (timer_pending(&port->t4_timer)) {
+		if (debug & DEBUG_HFC_S0_STATES)
+			printk(KERN_INFO "%s %s\n", __FUNCTION__, port->name);
+		del_timer(&port->t4_timer);
+	}
+}
+
+/*****************************************************/
+/* called when timer t4 expires                      */
+/* send (PH_DEACTIVATE | INDICATION) to upper layer  */
+/*****************************************************/
+static void
+l1_timer_expire_t4(xhfc_port_t * port)
+{
+	channel_t * dch = &port->xhfc->chan[port->idx * 4 + 2].ch;
+	
+	if (debug & DEBUG_HFC_S0_STATES)
+		printk(KERN_INFO "%s %s\n", __FUNCTION__, port->name);
+
+	clear_bit(HFC_L1_DEACTTIMER, &port->l1_flags);
+	mISDN_queue_data(&dch->inst, FLG_MSG_UP,
+		(PH_DEACTIVATE | INDICATION), 0, 0, NULL, 0);
+	mISDN_queue_data(&dch->inst, dch->inst.id | MSG_BROADCAST,
+		MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_DEACTIVATED,
+		0, NULL, 0);	
+}
+
+/*********************************/
+/* Line Interface State handler  */
+/*********************************/
+static void
+su_new_state(xhfc_port_t * port)
+{
+	channel_t * dch = &port->xhfc->chan[port->idx * 4 + 2].ch;
+	xhfc_t * xhfc = port->xhfc;
+	u_int prim = 0;
+
+	if (port->mode & PORT_MODE_TE) {
+		if (debug & DEBUG_HFC_S0_STATES)
+			printk(KERN_INFO "%s %s: TE F%d\n",
+				__FUNCTION__, port->name, dch->state);
+
+		if ((dch->state <= 3) || (dch->state >= 7))
+			l1_timer_stop_t3(port);
+
+		switch (dch->state) {
+			case (3):
+				if (test_and_clear_bit(HFC_L1_ACTIVATED, &port->l1_flags))
+					l1_timer_start_t4(port);
+				return;
+
+			case (7):
+				if (timer_pending(&port->t4_timer))
+					l1_timer_stop_t4(port);
+					
+				if (test_and_clear_bit(HFC_L1_ACTIVATING, &port->l1_flags)) {
+					if (debug & DEBUG_HFC_S0_STATES)
+						printk(KERN_INFO "%s %s: l1->l2 (PH_ACTIVATE | CONFIRM)\n",
+						       __FUNCTION__, port->name);
+							 
+					set_bit(HFC_L1_ACTIVATED, &port->l1_flags);
+					prim = PH_ACTIVATE | CONFIRM;
+				} else {
+					if (!(test_and_set_bit(HFC_L1_ACTIVATED, &port->l1_flags))) {
+						if (debug & DEBUG_HFC_S0_STATES)
+							printk(KERN_INFO "%s %s: l1->l2 (PH_ACTIVATE | INDICATION)\n",
+							       __FUNCTION__, port->name);
+						prim = PH_ACTIVATE | INDICATION;
+					} else {
+						// L1 was already activated (e.g. F8->F7)
+						return;
+					}
+				}
+				mISDN_queue_data(&dch->inst, dch->inst.id | MSG_BROADCAST,
+					MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_ACTIVATED,
+					0, NULL, 0);
+				break;
+
+			case (8):
+				l1_timer_stop_t4(port);
+				return;
+			default:
+				return;
+		}
+		
+	} else if (port->mode & PORT_MODE_NT) {
+		
+		if (debug & DEBUG_HFC_S0_STATES)
+			printk(KERN_INFO "%s %s: NT G%d\n",
+				__FUNCTION__, port->name, dch->state);
+
+		switch (dch->state) {
+			case (1):
+				clear_bit(FLG_ACTIVE, &dch->Flags);
+				port->nt_timer = 0;
+				port->mode &= ~NT_TIMER;
+				prim = (PH_DEACTIVATE | INDICATION);
+				if (debug & DEBUG_HFC_S0_STATES)
+					printk(KERN_INFO "%s %s: l1->l2 (PH_DEACTIVATE | INDICATION)\n",
+					       __FUNCTION__, port->name);
+				break;
+			case (2):
+				if (port->nt_timer < 0) {
+					port->nt_timer = 0;
+					port->mode &= ~NT_TIMER;
+					xhfc_ph_command(port, HFC_L1_DEACTIVATE_NT);
+				} else {
+					port->nt_timer = NT_T1_COUNT;
+					port->mode |= NT_TIMER;
+
+					write_xhfc(xhfc, R_SU_SEL, port->idx);
+					write_xhfc(xhfc, A_SU_WR_STA, M_SU_SET_G2_G3);
+				}
+				return;
+			case (3):
+				set_bit(FLG_ACTIVE, &dch->Flags);
+				port->nt_timer = 0;
+				port->mode &= ~NT_TIMER;
+				prim = (PH_ACTIVATE | INDICATION);
+
+				if (debug & DEBUG_HFC_S0_STATES)
+					printk(KERN_INFO "%s %s: l1->l2 (PH_ACTIVATE | INDICATION)\n",
+					       __FUNCTION__, port->name);				
+				break;
+			case (4):
+				port->nt_timer = 0;
+				port->mode &= ~NT_TIMER;
+				return;
+			default:
+				break;
+		}
+		mISDN_queue_data(&dch->inst, dch->inst.id | MSG_BROADCAST,
+			MGR_SHORTSTATUS | INDICATION,  test_bit(FLG_ACTIVE, &dch->Flags) ?
+			SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED,
+			0, NULL, 0);
+	}
+
+	mISDN_queue_data(&dch->inst, FLG_MSG_UP, prim, 0, 0, NULL, 0);
+}
+
+/*************************************/
+/* Layer 1 D-channel hardware access */
+/*************************************/
+static int
+handle_dmsg(channel_t *dch, struct sk_buff *skb)
+{
+	xhfc_t * xhfc = dch->hw;
+	xhfc_port_t * port = xhfc->chan[dch->channel].port;
+	
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);	
+
+	switch (hh->prim) {
+		case (PH_ACTIVATE | REQUEST):
+			if ((dch->debug) & (debug & DEBUG_HFC_S0_STATES))
+				mISDN_debugprint(&dch->inst,
+					 "l2->l1 (PH_ACTIVATE | REQUEST)");				
+			
+			if (port->mode & PORT_MODE_TE) {
+				if (test_bit(HFC_L1_ACTIVATED, &port->l1_flags)) {
+					
+					if ((dch->debug) & (debug & DEBUG_HFC_S0_STATES))
+						mISDN_debugprint(&dch->inst,
+							 "l1->l2 (PH_ACTIVATE | CONFIRM)");
+					
+					mISDN_queue_data(&dch->inst, FLG_MSG_UP,
+					                 PH_ACTIVATE | CONFIRM,
+					                 0, 0, NULL, 0);
+				} else {
+					test_and_set_bit(HFC_L1_ACTIVATING, &port->l1_flags);
+
+					xhfc_ph_command(port, HFC_L1_ACTIVATE_TE);
+					l1_timer_start_t3(port);
+				}
+			} else {
+				if (dch->state == 3) {
+					mISDN_queue_data(&dch->inst, FLG_MSG_UP,
+					                 PH_ACTIVATE | INDICATION,
+					                 0, 0, NULL, 0);
+				} else {
+					xhfc_ph_command(port, HFC_L1_ACTIVATE_NT);
+				}
+			}
+			break;
+			
+		case (PH_DEACTIVATE | REQUEST):
+			if (port->mode & PORT_MODE_TE) {
+				// no deact request in TE mode !
+				ret = -EINVAL;
+			} else {
+				xhfc_ph_command(port, HFC_L1_DEACTIVATE_NT);
+			}
+			break;
+
+		case (MDL_FINDTEI | REQUEST):
+			return(mISDN_queue_up(&dch->inst, 0, skb));
+			break;
+	}
+	
+	return(ret);
+}
+
+/*************************************/
+/* Layer 1 B-channel hardware access */
+/*************************************/
+static int
+handle_bmsg(channel_t *bch, struct sk_buff *skb)
+{
+	xhfc_t 	*xhfc = bch->hw;
+	int		ret = 0;
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	u_long		flags;
+	
+	if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
+		   (hh->prim == (DL_ESTABLISH | REQUEST))) {
+		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
+			spin_lock_irqsave(&xhfc->lock, flags);
+			if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+				test_and_set_bit(FLG_L2DATA, &bch->Flags);			
+			ret =
+			    setup_channel(xhfc, bch->channel,
+					  bch->inst.pid.protocol[1]);
+			spin_unlock_irqrestore(&xhfc->lock, flags);
+		}
+#ifdef FIXME
+		if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+			if (bch->dev)
+				if_link(&bch->dev->rport.pif,
+					hh->prim | CONFIRM, 0, 0, NULL, 0);
+#endif
+		skb_trim(skb, 0);
+		return(mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, ret, skb));
+		
+	} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
+		(hh->prim == (DL_RELEASE | REQUEST)) ||
+		((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
+		   	
+		spin_lock_irqsave(&xhfc->lock, flags);
+		if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+			dev_kfree_skb(bch->next_skb);
+			bch->next_skb = NULL;
+		}
+		if (bch->tx_skb) {
+			dev_kfree_skb(bch->tx_skb);
+			bch->tx_skb = NULL;
+		}
+		bch->tx_idx = 0;
+		if (bch->rx_skb) {
+			dev_kfree_skb(bch->rx_skb);
+			bch->rx_skb = NULL;
+		}
+		test_and_clear_bit(FLG_L2DATA, &bch->Flags);
+		test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+		setup_channel(xhfc, bch->channel, ISDN_PID_NONE);
+		test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+		spin_unlock_irqrestore(&xhfc->lock, flags);
+		skb_trim(skb, 0);
+		if (hh->prim != (PH_CONTROL | REQUEST)) {
+#ifdef FIXME
+			if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
+				if (bch->dev)
+					if_link(&bch->dev->rport.pif,
+						hh->prim | CONFIRM, 0, 0, NULL, 0);
+#endif
+			if (!mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, 0, skb))
+				return(0);
+		}
+
+	} else {
+		printk(KERN_WARNING "%s %s: unknown prim(%x)\n",
+		       xhfc->name, __FUNCTION__, hh->prim);
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return (ret);
+}
+
+/***********************************************/
+/* handle Layer2 -> Layer 1 D-Channel messages */
+/***********************************************/
+static int
+xhfc_l2l1(mISDNinstance_t *inst, struct sk_buff *skb)
+{
+	channel_t	*chan = container_of(inst, channel_t, inst);
+	mISDN_head_t	*hh = mISDN_HEAD_P(skb);
+	xhfc_t		*xhfc = inst->privat;
+	int		ret = 0;
+	u_long		flags;
+	
+	if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) {
+		spin_lock_irqsave(inst->hwlock, flags);
+		ret = channel_senddata(chan, hh->dinfo, skb);
+		if (ret > 0) { /* direct TX */
+			tasklet_schedule(&xhfc->tasklet);
+			// printk ("PH_DATA_REQ: %i bytes in channel(%i)\n", ret, chan->channel);
+			ret = 0;
+		}
+		spin_unlock_irqrestore(inst->hwlock, flags);
+		return(ret);
+	}
+	if (test_bit(FLG_DCHANNEL, &chan->Flags)) {
+		ret = handle_dmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (test_bit(FLG_BCHANNEL, &chan->Flags)) {
+		ret = handle_bmsg(chan, skb);
+		if (ret != -EAGAIN)
+			return(ret);
+		ret = -EINVAL;
+	}
+	if (!ret)
+		dev_kfree_skb(skb);
+	return(ret);
+}
+
+static int
+xhfc_manager(void *data, u_int prim, void *arg)
+{
+	xhfc_t *xhfc = NULL;
+	mISDNinstance_t *inst = data;
+	struct sk_buff *skb;
+	int channel = -1;
+	int i;
+	channel_t *chan = NULL;
+	u_long flags;
+
+	if (!data) {
+		MGR_HASPROTOCOL_HANDLER(prim, arg, &hw_mISDNObj)
+		    printk(KERN_ERR "%s: no data prim %x arg %p\n",
+			   __FUNCTION__, prim, arg);
+		return (-EINVAL);
+	}
+	
+	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+
+	/* find channel and card */
+	list_for_each_entry(xhfc, &hw_mISDNObj.ilist, list) {
+		i = 0;
+		while (i < MAX_CHAN) {
+			if (xhfc->chan[i].ch.Flags &&
+				&xhfc->chan[i].ch.inst == inst) {
+				channel = i;
+				chan = &xhfc->chan[i].ch;
+				break;
+			}
+			i++;
+		}
+		if (channel >= 0)
+			break;
+	}
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+	
+	if (channel < 0) {
+		printk(KERN_ERR
+		       "%s: no card/channel found  data %p prim %x arg %p\n",
+		       __FUNCTION__, data, prim, arg);
+		return (-EINVAL);
+	}
+
+	switch (prim) {
+		case MGR_REGLAYER | CONFIRM:
+			mISDN_setpara(chan, &inst->st->para);
+			break;
+		case MGR_UNREGLAYER | REQUEST:
+			if ((skb = create_link_skb(PH_CONTROL | REQUEST,
+				HW_DEACTIVATE, 0, NULL, 0))) {
+				if (xhfc_l2l1(inst, skb))
+					dev_kfree_skb(skb);
+			} else
+				printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
+			mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
+			break;
+		case MGR_CLRSTPARA | INDICATION:
+			arg = NULL;
+		case MGR_ADDSTPARA | INDICATION:
+			mISDN_setpara(chan, arg);
+			break;
+		case MGR_RELEASE | INDICATION:
+			if (channel == 2) {
+				// release_card(xhfc);
+			} else {
+				hw_mISDNObj.refcnt--;
+			}
+			break;
+		case MGR_SETSTACK | INDICATION:
+			if ((channel != 2) && (inst->pid.global == 2)) {
+				if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
+					0, 0, NULL, 0))) {
+					if (xhfc_l2l1(inst, skb))
+						dev_kfree_skb(skb);
+				}
+				if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
+					mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
+						0, 0, NULL, 0);
+				else
+					mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
+						0, 0, NULL, 0);
+			}
+			break;
+		case MGR_GLOBALOPT | REQUEST:
+			if (arg) {
+				// FIXME: detect cards with HEADSET
+				u_int *gopt = arg;
+				*gopt = GLOBALOPT_INTERNAL_CTRL |
+				    GLOBALOPT_EXTERNAL_EQUIPMENT |
+				    GLOBALOPT_HANDSET;
+			} else
+				return (-EINVAL);
+			break;
+		case MGR_SELCHANNEL | REQUEST:
+			// no special procedure
+			return (-EINVAL);
+			PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
+		default:
+			printk(KERN_WARNING "%s %s: prim %x not handled\n",
+			       xhfc->name, __FUNCTION__, prim);
+			return (-EINVAL);
+	}
+	return (0);
+}
+
+/***********************************/
+/* check if new buffer for channel */
+/* is waitinng is transmitt queue  */
+/***********************************/
+static int
+next_tx_frame(xhfc_t * xhfc, __u8 channel)
+{
+	channel_t *ch = &xhfc->chan[channel].ch;
+
+	if (ch->tx_skb)
+		dev_kfree_skb(ch->tx_skb);
+	if (test_and_clear_bit(FLG_TX_NEXT, &ch->Flags)) {
+		ch->tx_skb = ch->next_skb;
+		if (ch->tx_skb) {
+			mISDN_head_t *hh = mISDN_HEAD_P(ch->tx_skb);
+			ch->next_skb = NULL;
+			test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
+			ch->tx_idx = 0;
+			queue_ch_frame(ch, CONFIRM, hh->dinfo, NULL);
+			return (1);
+		} else {
+			printk(KERN_WARNING
+			       "%s channel(%i) TX_NEXT without skb\n",
+			       xhfc->name, channel);
+			test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
+		}
+	} else
+		ch->tx_skb = NULL;
+	test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
+	return (0);
+}
+
+static inline void
+xhfc_waitbusy(xhfc_t * xhfc)
+{
+	while (read_xhfc(xhfc, R_STATUS) & M_BUSY);
+}
+
+static inline void
+xhfc_selfifo(xhfc_t * xhfc, __u8 fifo)
+{
+	write_xhfc(xhfc, R_FIFO, fifo);
+	xhfc_waitbusy(xhfc);
+}
+
+static inline void
+xhfc_inc_f(xhfc_t * xhfc)
+{
+	write_xhfc(xhfc, A_INC_RES_FIFO, M_INC_F);
+	xhfc_waitbusy(xhfc);
+}
+
+static inline void
+xhfc_resetfifo(xhfc_t * xhfc)
+{
+	write_xhfc(xhfc, A_INC_RES_FIFO, M_RES_FIFO | M_RES_FIFO_ERR);
+	xhfc_waitbusy(xhfc);
+}
+
+/**************************/
+/* fill fifo with TX data */
+/**************************/
+static void
+xhfc_write_fifo(xhfc_t * xhfc, __u8 channel)
+{
+	__u8		fcnt, tcnt, i;
+	__u8		free;
+	__u8		f1, f2;
+	__u8		fstat;
+	__u8		*data;
+	int		remain;
+	channel_t	*ch = &xhfc->chan[channel].ch;
+
+
+      send_buffer:
+	if (!ch->tx_skb)
+		return;
+	remain = ch->tx_skb->len - ch->tx_idx;
+	if (remain <= 0)
+		return;      
+      
+	xhfc_selfifo(xhfc, (channel * 2));
+
+	fstat = read_xhfc(xhfc, A_FIFO_STA);
+	free = (xhfc->max_z - (read_xhfc(xhfc, A_USAGE)));
+	tcnt = (free >= remain) ? remain : free;
+
+	f1 = read_xhfc(xhfc, A_F1);
+	f2 = read_xhfc(xhfc, A_F2);
+
+	fcnt = 0x07 - ((f1 - f2) & 0x07);	/* free frame count in tx fifo */
+
+	if (debug & DEBUG_HFC_FIFO) {
+		mISDN_debugprint(&ch->inst,
+				 "%s channel(%i) len(%i) idx(%i) f1(%i) f2(%i) fcnt(%i) tcnt(%i) free(%i) fstat(%i)",
+				 __FUNCTION__, channel, ch->tx_skb->len, ch->tx_idx,
+				 f1, f2, fcnt, tcnt, free, fstat);
+	}
+
+	/* check for fifo underrun during frame transmission */
+	fstat = read_xhfc(xhfc, A_FIFO_STA);
+	if (fstat & M_FIFO_ERR) {
+		if (debug & DEBUG_HFC_FIFO_ERR) {
+			mISDN_debugprint(&ch->inst,
+					 "%s transmit fifo channel(%i) underrun idx(%i), A_FIFO_STA(0x%02x)",
+					 __FUNCTION__, channel,
+					 ch->tx_idx, fstat);
+		}
+
+		write_xhfc(xhfc, A_INC_RES_FIFO, M_RES_FIFO_ERR);
+
+		/* restart frame transmission */
+		if ((test_bit(FLG_HDLC, &ch->Flags)) && ch->tx_idx) {
+			ch->tx_idx = 0;
+			goto send_buffer;
+		}
+	}
+
+	if (free && fcnt && tcnt) {
+		data = ch->tx_skb->data + ch->tx_idx;
+		ch->tx_idx += tcnt;
+
+		if (debug & DEBUG_HFC_FIFO) {
+			printk("%s channel(%i) writing: ",
+			       xhfc->name, channel);
+
+			i=0;
+			while (i<tcnt)
+				printk("%02x ", *(data+(i++)));
+			printk ("\n");
+		}
+		
+		/* write data to FIFO */
+		i=0;
+		while (i<tcnt) {
+			if ((tcnt-i) >= 4) {
+				write32_xhfc(xhfc, A_FIFO_DATA, *((__u32 *) (data+i)));
+				i += 4;
+			} else {
+				write_xhfc(xhfc, A_FIFO_DATA, *(data+i));
+				i++;
+			}
+		}
+
+		if (ch->tx_idx == ch->tx_skb->len) {
+			if (test_bit(FLG_HDLC, &ch->Flags)) {
+				/* terminate frame */
+				xhfc_inc_f(xhfc);
+			} else {
+				xhfc_selfifo(xhfc, (channel * 2));
+			}
+
+			/* check for fifo underrun during frame transmission */
+			fstat = read_xhfc(xhfc, A_FIFO_STA);
+			if (fstat & M_FIFO_ERR) {
+				if (debug & DEBUG_HFC_FIFO_ERR) {
+					mISDN_debugprint(&ch->inst,
+							 "%s transmit fifo channel(%i) underrun "
+							 "during transmission, A_FIFO_STA(0x%02x)\n",
+							 __FUNCTION__,
+							 channel,
+							 fstat);
+				}
+				write_xhfc(xhfc, A_INC_RES_FIFO, M_RES_FIFO_ERR);
+
+				if (test_bit(FLG_HDLC, &ch->Flags)) {
+					// restart frame transmission
+					ch->tx_idx = 0;
+					goto send_buffer;
+				}
+			}
+			
+			if (next_tx_frame(xhfc, channel)) {
+				if (debug & DEBUG_HFC_BTRACE)
+					mISDN_debugprint(&ch->inst,
+						"channel(%i) has next_tx_frame",
+						channel);
+				if ((free - tcnt) > 8) {
+					if (debug & DEBUG_HFC_BTRACE)
+						mISDN_debugprint(&ch->inst,
+							"channel(%i) continue B-TX immediatetly",
+							channel);
+					goto send_buffer;
+				}
+			}			
+
+			
+		} else {
+			/* tx buffer not complete, but fifo filled to maximum */
+			xhfc_selfifo(xhfc, (channel * 2));
+		}
+	} 
+}
+
+/****************************/
+/* read RX data out of fifo */
+/****************************/
+static void
+xhfc_read_fifo(xhfc_t * xhfc, __u8 channel)
+{
+	__u8	f1=0, f2=0, z1=0, z2=0;
+	__u8	fstat = 0;
+	int	i;
+	int	rcnt;		/* read rcnt bytes out of fifo */
+	__u8	*data;		/* new data pointer */
+	struct sk_buff	*skb;	/* data buffer for upper layer */
+	channel_t	*ch = &xhfc->chan[channel].ch;
+
+      receive_buffer:
+
+	xhfc_selfifo(xhfc, (channel * 2) + 1);
+
+	fstat = read_xhfc(xhfc, A_FIFO_STA);
+	if (fstat & M_FIFO_ERR) {
+		if (debug & DEBUG_HFC_FIFO_ERR)
+			mISDN_debugprint(&ch->inst,
+					 "RX fifo overflow channel(%i), "
+					 "A_FIFO_STA(0x%02x) f0cnt(%i)",
+					 channel, fstat, xhfc->f0_akku);
+		write_xhfc(xhfc, A_INC_RES_FIFO, M_RES_FIFO_ERR);
+	}
+
+	if (test_bit(FLG_HDLC, &ch->Flags)) {
+		/* hdlc rcnt */
+		f1 = read_xhfc(xhfc, A_F1);
+		f2 = read_xhfc(xhfc, A_F2);
+		z1 = read_xhfc(xhfc, A_Z1);
+		z2 = read_xhfc(xhfc, A_Z2);
+
+		rcnt = (z1 - z2) & xhfc->max_z;
+		if (f1 != f2)
+			rcnt++;
+
+	} else {
+		/* transparent rcnt */
+		rcnt = read_xhfc(xhfc, A_USAGE) - 1;
+	}
+
+	if (debug & DEBUG_HFC_FIFO) {
+		if (ch->rx_skb)
+			i = ch->rx_skb->len;
+		else
+			i = 0;
+		mISDN_debugprint(&ch->inst, "reading %i bytes channel(%i) "
+			"irq_cnt(%i) fstat(%i) idx(%i) f1(%i) f2(%i) z1(%i) z2(%i)",
+			rcnt, channel, xhfc->irq_cnt, fstat, i, f1, f2, z1, z2);
+	}
+
+	if (rcnt > 0) {
+		if (!ch->rx_skb) {
+			ch->rx_skb = alloc_stack_skb(ch->maxlen + 3, ch->up_headerlen);
+			if (!ch->rx_skb) {
+				printk(KERN_DEBUG "%s: No mem for rx_skb\n", __FUNCTION__);
+				return;
+			}
+		}
+		data = skb_put(ch->rx_skb, rcnt);
+
+		/* read data from FIFO */
+		i=0;
+		while (i<rcnt) {
+			if ((rcnt-i) >= 4) {
+				*((__u32 *) (data+i)) = read32_xhfc(xhfc, A_FIFO_DATA);
+				i += 4;
+			} else {
+				*(data+i) = read_xhfc(xhfc, A_FIFO_DATA);
+				i++;
+			}
+		}		
+	} else
+		return;
+
+	if (test_bit(FLG_HDLC, &ch->Flags)) {
+		if (f1 != f2) {
+			xhfc_inc_f(xhfc);
+
+			if ((ch->debug) && (debug & DEBUG_HFC_DTRACE)) {
+				mISDN_debugprint(&ch->inst,
+					"channel(%i) new RX len(%i): ",
+					channel, ch->rx_skb->len);
+				i = 0;
+				printk("  ");
+				while (i < ch->rx_skb->len)
+					printk("%02x ", ch->rx_skb->data[i++]);
+				printk("\n");
+			}
+
+			/* check minimum frame size */
+			if (ch->rx_skb->len < 4) {
+				if (debug & DEBUG_HFC_FIFO_ERR)
+					mISDN_debugprint(&ch->inst,
+							 "%s: frame in channel(%i) < minimum size",
+							 __FUNCTION__,
+							 channel);
+				goto read_exit;
+			}
+
+			/* check crc */
+			if (ch->rx_skb->data[ch->rx_skb->len - 1]) {
+				if (debug & DEBUG_HFC_FIFO_ERR)
+					mISDN_debugprint(&ch->inst,
+							 "%s: channel(%i) CRC-error",
+							 __FUNCTION__,
+							 channel);
+				goto read_exit;
+			}
+
+			/* remove cksum */
+			skb_trim(ch->rx_skb, ch->rx_skb->len - 3);
+
+			if (ch->rx_skb->len < MISDN_COPY_SIZE) {
+				skb = alloc_stack_skb(ch->rx_skb->len, ch->up_headerlen);
+				if (skb) {
+					memcpy(skb_put(skb, ch->rx_skb->len),
+						ch->rx_skb->data, ch->rx_skb->len);
+					skb_trim(ch->rx_skb, 0);
+				} else {
+					skb = ch->rx_skb;
+					ch->rx_skb = NULL;
+				}
+			} else {
+				skb = ch->rx_skb;
+				ch->rx_skb = NULL;
+			}
+			
+			queue_ch_frame(ch, INDICATION, MISDN_ID_ANY, skb);
+
+		      read_exit:
+			if (ch->rx_skb)
+				skb_trim(ch->rx_skb, 0);
+			if (read_xhfc(xhfc, A_USAGE) > 8) {
+				if (debug & DEBUG_HFC_FIFO)
+					mISDN_debugprint(&ch->inst,
+							 "%s: channel(%i) continue xhfc_read_fifo",
+							 __FUNCTION__,
+							 channel);
+				goto receive_buffer;
+			}
+			return;
+
+
+		} else {
+			xhfc_selfifo(xhfc, (channel * 2) + 1);
+		}
+	} else {
+		xhfc_selfifo(xhfc, (channel * 2) + 1);
+		if (ch->rx_skb->len >= TRANSP_PACKET_SIZE) {
+			/* deliver transparent data to layer2 */
+			queue_ch_frame(ch, INDICATION, MISDN_ID_ANY, ch->rx_skb);
+			ch->rx_skb = NULL;
+		}
+	}
+}
+
+/*************************************/
+/* bottom half handler for interrupt */
+/*************************************/
+static void
+xhfc_bh_handler(unsigned long ul_hw)
+{
+	xhfc_t 	*xhfc = (xhfc_t *) ul_hw;
+	int		i;
+	reg_a_su_rd_sta	su_state;
+	channel_t	*dch;
+
+	/* timer interrupt */
+	if (xhfc->misc_irq.bit.v_ti_irq) {
+		xhfc->misc_irq.bit.v_ti_irq = 0;
+
+		/* Handle tx Fifos */
+		for (i = 0; i < xhfc->max_fifo; i++) {
+			if ((1 << (i * 2)) & (xhfc->fifo_irqmsk)) {
+				xhfc->fifo_irq &= ~(1 << (i * 2));
+				if (test_bit(FLG_TX_BUSY, &xhfc->chan[i].ch.Flags)) {
+					xhfc_write_fifo(xhfc, i);
+				}
+			}
+		}
+		
+		/* handle NT Timer */
+		for (i = 0; i < xhfc->num_ports; i++) {
+			if ((xhfc->port[i].mode & PORT_MODE_NT)
+			    && (xhfc->port[i].mode & NT_TIMER)) {
+				if ((--xhfc->port[i].nt_timer) < 0)
+					su_new_state(&xhfc->port[i]);
+			}
+		}
+	}
+
+	/* set fifo_irq when RX data over treshold */
+	for (i = 0; i < xhfc->num_ports; i++) {
+		xhfc->fifo_irq |= read_xhfc(xhfc, R_FILL_BL0 + i) << (i * 8);
+	}
+
+	/* Handle rx Fifos */
+	if ((xhfc->fifo_irq & xhfc->fifo_irqmsk) & FIFO_MASK_RX) {
+		for (i = 0; i < xhfc->max_fifo; i++) {
+			if ((xhfc->fifo_irq & (1 << (i * 2 + 1)))
+			    & (xhfc->fifo_irqmsk)) {
+
+				xhfc->fifo_irq &= ~(1 << (i * 2 + 1));
+				xhfc_read_fifo(xhfc, i);
+			}
+		}
+	}
+
+	/* su interrupt */
+	if (xhfc->su_irq.reg & xhfc->su_irqmsk.reg) {
+		xhfc->su_irq.reg = 0;
+		for (i = 0; i < xhfc->num_ports; i++) {
+			write_xhfc(xhfc, R_SU_SEL, i);
+			su_state.reg = read_xhfc(xhfc, A_SU_RD_STA);
+			
+			dch = &xhfc->chan[(i << 2) + 2].ch;
+			if (su_state.bit.v_su_sta != dch->state) {
+				dch->state = su_state.bit.v_su_sta;
+				su_new_state(&xhfc->port[i]);
+			}
+		}
+	}
+}
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static irqreturn_t
+xhfc_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	xhfc_pi *pi = dev_id;
+	xhfc_t * xhfc = NULL;
+	__u8 i, j;
+	__u32 xhfc_irqs;
+#ifdef USE_F0_COUNTER
+	__u32 f0_cnt;
+#endif
+
+	xhfc_irqs = 0;
+	for (i=0; i<pi->driver_data.num_xhfcs; i++) {
+		xhfc = &pi->xhfc[i];
+		if (xhfc->irq_ctrl.bit.v_glob_irq_en && (read_xhfc(xhfc, R_IRQ_OVIEW)))
+			/* mark this xhfc possibly had irq */
+		    	xhfc_irqs |= (1 << i);
+	}
+	if (!xhfc_irqs) {
+		if (debug & DEBUG_HFC_IRQ)
+			printk(KERN_INFO
+			       "%s %s NOT M_GLOB_IRQ_EN or R_IRQ_OVIEW \n",
+			       xhfc->name, __FUNCTION__);
+		return IRQ_NONE;
+	}
+
+	xhfc_irqs = 0;
+	for (i=0; i<pi->driver_data.num_xhfcs; i++) {
+		xhfc = &pi->xhfc[i];
+
+		xhfc->misc_irq.reg |= read_xhfc(xhfc, R_MISC_IRQ);
+		xhfc->su_irq.reg |= read_xhfc(xhfc, R_SU_IRQ);
+
+		/* get fifo IRQ states in bundle */
+		for (j = 0; j < 4; j++) {
+			xhfc->fifo_irq |=
+			    (read_xhfc(xhfc, R_FIFO_BL0_IRQ + j) << (j * 8));
+		}
+
+		/* call bottom half at events
+		 *   - Timer Interrupt (or other misc_irq sources)
+		 *   - SU State change
+		 *   - Fifo FrameEnd interrupts (only at rx fifos enabled)
+		 */
+		if ((xhfc->misc_irq.reg & xhfc->misc_irqmsk.reg)
+		      || (xhfc->su_irq.reg & xhfc->su_irqmsk.reg)
+		      || (xhfc->fifo_irq & xhfc->fifo_irqmsk)) {
+		      	
+		      	/* mark this xhfc really had irq */
+			xhfc_irqs |= (1 << i);
+	
+			/* queue bottom half */
+			if (!(xhfc->testirq))
+				tasklet_schedule(&xhfc->tasklet);
+
+			/* count irqs */
+			xhfc->irq_cnt++;
+
+#ifdef USE_F0_COUNTER
+			/* akkumulate f0 counter diffs */
+			f0_cnt = read_xhfc(xhfc, R_F0_CNTL);
+			f0_cnt += read_xhfc(xhfc, R_F0_CNTH) << 8;
+			xhfc->f0_akku += (f0_cnt - xhfc->f0_cnt);
+			if ((f0_cnt - xhfc->f0_cnt) < 0)
+				xhfc->f0_akku += 0xFFFF;
+			xhfc->f0_cnt = f0_cnt;
+#endif
+		}
+	}
+	
+	return ((xhfc_irqs)?IRQ_HANDLED:IRQ_NONE);
+}
+
+/*****************************************************/
+/* disable all interrupts by disabling M_GLOB_IRQ_EN */
+/*****************************************************/
+static void
+disable_interrupts(xhfc_t * xhfc)
+{
+	if (debug & DEBUG_HFC_IRQ)
+		printk(KERN_INFO "%s %s\n", xhfc->name, __FUNCTION__);
+	xhfc->irq_ctrl.bit.v_glob_irq_en = 0;
+	write_xhfc(xhfc, R_IRQ_CTRL, xhfc->irq_ctrl.reg);
+}
+
+/******************************************/
+/* start interrupt and set interrupt mask */
+/******************************************/
+static void
+enable_interrupts(xhfc_t * xhfc)
+{
+	if (debug & DEBUG_HFC_IRQ)
+		printk(KERN_INFO "%s %s\n", xhfc->name, __FUNCTION__);
+
+	write_xhfc(xhfc, R_SU_IRQMSK, xhfc->su_irqmsk.reg);
+
+	/* use defined timer interval */
+	write_xhfc(xhfc, R_TI_WD, xhfc->ti_wd.reg);
+	xhfc->misc_irqmsk.bit.v_ti_irqmsk = 1;
+	write_xhfc(xhfc, R_MISC_IRQMSK, xhfc->misc_irqmsk.reg);
+
+	/* clear all pending interrupts bits */
+	read_xhfc(xhfc, R_MISC_IRQ);
+	read_xhfc(xhfc, R_SU_IRQ);
+	read_xhfc(xhfc, R_FIFO_BL0_IRQ);
+	read_xhfc(xhfc, R_FIFO_BL1_IRQ);
+	read_xhfc(xhfc, R_FIFO_BL2_IRQ);
+	read_xhfc(xhfc, R_FIFO_BL3_IRQ);
+
+	/* enable global interrupts */
+	xhfc->irq_ctrl.bit.v_glob_irq_en = 1;
+	xhfc->irq_ctrl.bit.v_fifo_irq_en = 1;
+	write_xhfc(xhfc, R_IRQ_CTRL, xhfc->irq_ctrl.reg);
+}
+
+/***********************************/
+/* initialise the XHFC ISDN Chip   */
+/* return 0 on success.            */
+/***********************************/
+static int
+init_xhfc(xhfc_t * xhfc)
+{
+	int err = 0;
+	int timeout = 0x2000;
+	__u8 chip_id;
+
+	chip_id = read_xhfc(xhfc, R_CHIP_ID);
+	switch (chip_id) {
+		case CHIP_ID_1SU:
+			xhfc->num_ports = 1;
+			xhfc->max_fifo = 4;
+			xhfc->max_z = 0xFF;
+			xhfc->ti_wd.bit.v_ev_ts = 0x6;	/* timer irq interval 16 ms */
+			write_xhfc(xhfc, R_FIFO_MD, M1_FIFO_MD * 2);
+			xhfc->su_irqmsk.bit.v_su0_irqmsk = 1;
+			sprintf(xhfc->name, "%s_PI%d_%i",
+			        CHIP_NAME_1SU,
+			        xhfc->pi->cardnum,
+			        xhfc->chipidx);
+			break;
+
+		case CHIP_ID_2SU:
+			xhfc->num_ports = 2;
+			xhfc->max_fifo = 8;
+			xhfc->max_z = 0x7F;
+			xhfc->ti_wd.bit.v_ev_ts = 0x5;	/* timer irq interval 8 ms */
+			write_xhfc(xhfc, R_FIFO_MD, M1_FIFO_MD * 1);
+			xhfc->su_irqmsk.bit.v_su0_irqmsk = 1;
+			xhfc->su_irqmsk.bit.v_su1_irqmsk = 1;
+			sprintf(xhfc->name, "%s_PI%d_%i",
+			        CHIP_NAME_2SU,
+			        xhfc->pi->cardnum,
+			        xhfc->chipidx);
+			break;
+
+		case CHIP_ID_2S4U:
+			xhfc->num_ports = 4;
+			xhfc->max_fifo = 16;
+			xhfc->max_z = 0x3F;
+			xhfc->ti_wd.bit.v_ev_ts = 0x4;	/* timer irq interval 4 ms */
+			write_xhfc(xhfc, R_FIFO_MD, M1_FIFO_MD * 0);
+			xhfc->su_irqmsk.bit.v_su0_irqmsk = 1;
+			xhfc->su_irqmsk.bit.v_su1_irqmsk = 1;
+			xhfc->su_irqmsk.bit.v_su2_irqmsk = 1;
+			xhfc->su_irqmsk.bit.v_su3_irqmsk = 1;		
+			sprintf(xhfc->name, "%s_PI%d_%i",
+			        CHIP_NAME_2S4U,
+			        xhfc->pi->cardnum,
+			        xhfc->chipidx);
+
+		case CHIP_ID_4SU:
+			xhfc->num_ports = 4;
+			xhfc->max_fifo = 16;
+			xhfc->max_z = 0x3F;
+			xhfc->ti_wd.bit.v_ev_ts = 0x4;	/* timer irq interval 4 ms */
+			write_xhfc(xhfc, R_FIFO_MD, M1_FIFO_MD * 0);
+			xhfc->su_irqmsk.bit.v_su0_irqmsk = 1;
+			xhfc->su_irqmsk.bit.v_su1_irqmsk = 1;
+			xhfc->su_irqmsk.bit.v_su2_irqmsk = 1;
+			xhfc->su_irqmsk.bit.v_su3_irqmsk = 1;
+			sprintf(xhfc->name, "%s_PI%d_%i",
+			        CHIP_NAME_4SU,
+			        xhfc->pi->cardnum,
+			        xhfc->chipidx);
+			break;
+		default:
+			err = -ENODEV;
+	}
+
+	if (err) {
+		if (debug & DEBUG_HFC_INIT)
+			printk(KERN_ERR "%s %s: unkown Chip ID 0x%x\n",
+			       xhfc->name, __FUNCTION__, chip_id);
+		return (err);
+	} else {
+		if (debug & DEBUG_HFC_INIT)
+			printk(KERN_INFO "%s ChipID: 0x%x\n",
+			       xhfc->name, chip_id);
+	}
+	
+	/* software reset to enable R_FIFO_MD setting */
+	write_xhfc(xhfc, R_CIRM, M_SRES);
+	udelay(5);
+	write_xhfc(xhfc, R_CIRM, 0);
+	
+	/* amplitude */
+	write_xhfc(xhfc, R_PWM_MD, 0x80);
+	write_xhfc(xhfc, R_PWM1, 0x18);
+
+	write_xhfc(xhfc, R_FIFO_THRES, 0x11);
+
+	while ((read_xhfc(xhfc, R_STATUS) & (M_BUSY | M_PCM_INIT))
+	       && (timeout))
+		timeout--;
+
+	if (!(timeout)) {
+		if (debug & DEBUG_HFC_INIT)
+			printk(KERN_ERR
+			       "%s %s: initialization sequence could not finish\n",
+			       xhfc->name, __FUNCTION__);
+		return (-ENODEV);
+	}
+
+	/* set PCM master mode */
+	xhfc->pcm_md0.bit.v_pcm_md = 1;
+	write_xhfc(xhfc, R_PCM_MD0, xhfc->pcm_md0.reg);
+
+	/* set pll adjust */
+	xhfc->pcm_md0.bit.v_pcm_idx = IDX_PCM_MD1;
+	xhfc->pcm_md1.bit.v_pll_adj = 3;
+	write_xhfc(xhfc, R_PCM_MD0, xhfc->pcm_md0.reg);
+	write_xhfc(xhfc, R_PCM_MD1, xhfc->pcm_md1.reg);
+
+
+	/* perfom short irq test */
+	xhfc->testirq=1;
+	enable_interrupts(xhfc);
+	mdelay(1 << xhfc->ti_wd.bit.v_ev_ts);
+	disable_interrupts(xhfc);
+	
+	if (xhfc->irq_cnt > 2) {
+		xhfc->testirq = 0;
+		return (0);
+	} else {
+		if (debug & DEBUG_HFC_INIT)
+			printk(KERN_INFO
+			       "%s %s: ERROR getting IRQ (irq_cnt %i)\n",
+			       xhfc->name, __FUNCTION__, xhfc->irq_cnt);
+		return (-EIO);
+	}
+}
+
+/*************************************/
+/* free memory for all used channels */
+/*************************************/
+static void
+release_channels(xhfc_t * xhfc)
+{
+	int i = 0;
+
+	while (i < MAX_CHAN) {
+		if (xhfc->chan[i].ch.Flags) {
+			if (debug & DEBUG_HFC_INIT)
+				printk(KERN_DEBUG "%s %s: free channel %d\n",
+					xhfc->name, __FUNCTION__, i);
+			mISDN_freechannel(&xhfc->chan[i].ch);
+			mISDN_ctrl(&xhfc->chan[i].ch.inst, MGR_UNREGLAYER | REQUEST, NULL);
+		}
+		i++;
+	}
+	
+	if (xhfc->chan)
+		kfree(xhfc->chan);
+	if (xhfc->port)
+		kfree(xhfc->port);
+}
+
+/*********************************************/
+/* setup port (line interface) with SU_CRTLx */
+/*********************************************/
+static void
+init_su(xhfc_t * xhfc, __u8 pt)
+{
+	xhfc_port_t *port = &xhfc->port[pt];
+
+	if (debug & DEBUG_HFC_MODE)
+		printk(KERN_INFO "%s %s port(%i)\n", xhfc->name,
+		       __FUNCTION__, pt);
+
+	write_xhfc(xhfc, R_SU_SEL, pt);
+
+	if (port->mode & PORT_MODE_NT)
+		port->su_ctrl0.bit.v_su_md = 1;
+
+	if (port->mode & PORT_MODE_EXCH_POL) 
+		port->su_ctrl2.reg = M_SU_EXCHG;
+
+	if (port->mode & PORT_MODE_UP) {
+		port->st_ctrl3.bit.v_st_sel = 1;
+		write_xhfc(xhfc, A_MS_TX, 0x0F);
+		port->su_ctrl0.bit.v_st_sq_en = 1;
+	}
+
+	/* configure end of pulse control for ST mode (TE & NT) */
+	if (port->mode & PORT_MODE_S0) {
+		port->su_ctrl0.bit.v_st_pu_ctrl = 1;
+		port->st_ctrl3.reg = 0xf8;
+	}
+
+	if (debug & DEBUG_HFC_MODE)
+		printk(KERN_INFO "%s %s su_ctrl0(0x%02x) "
+		       "su_ctrl1(0x%02x) "
+		       "su_ctrl2(0x%02x) "
+		       "st_ctrl3(0x%02x)\n",
+		       xhfc->name, __FUNCTION__,
+		       port->su_ctrl0.reg,
+		       port->su_ctrl1.reg,
+		       port->su_ctrl2.reg,
+		       port->st_ctrl3.reg);
+
+	write_xhfc(xhfc, A_ST_CTRL3, port->st_ctrl3.reg);
+	write_xhfc(xhfc, A_SU_CTRL0, port->su_ctrl0.reg);
+	write_xhfc(xhfc, A_SU_CTRL1, port->su_ctrl1.reg);
+	write_xhfc(xhfc, A_SU_CTRL2, port->su_ctrl2.reg);
+	
+	if (port->mode & PORT_MODE_TE)
+		write_xhfc(xhfc, A_SU_CLK_DLY, CLK_DLY_TE);
+	else
+		write_xhfc(xhfc, A_SU_CLK_DLY, CLK_DLY_NT);
+
+	write_xhfc(xhfc, A_SU_WR_STA, 0);
+}
+
+/*********************************************************/
+/* Setup Fifo using A_CON_HDLC, A_SUBCH_CFG, A_FIFO_CTRL */
+/*********************************************************/
+static void
+setup_fifo(xhfc_t * xhfc, __u8 fifo, __u8 conhdlc, __u8 subcfg,
+	   __u8 fifoctrl, __u8 enable)
+{
+	xhfc_selfifo(xhfc, fifo);
+	write_xhfc(xhfc, A_CON_HDLC, conhdlc);
+	write_xhfc(xhfc, A_SUBCH_CFG, subcfg);
+	write_xhfc(xhfc, A_FIFO_CTRL, fifoctrl);
+
+	if (enable)
+		xhfc->fifo_irqmsk |= (1 << fifo);
+	else
+		xhfc->fifo_irqmsk &= ~(1 << fifo);
+
+	xhfc_resetfifo(xhfc);
+	xhfc_selfifo(xhfc, fifo);
+
+	if (debug & DEBUG_HFC_MODE) {
+		printk(KERN_INFO
+		       "%s %s: fifo(%i) conhdlc(0x%02x) "
+		       "subcfg(0x%02x) fifoctrl(0x%02x)\n",
+		       xhfc->name, __FUNCTION__, fifo,
+		       sread_xhfc(xhfc, A_CON_HDLC),
+		       sread_xhfc(xhfc, A_SUBCH_CFG),
+		       sread_xhfc(xhfc,  A_FIFO_CTRL)
+		    );
+	}
+}
+
+/**************************************************/
+/* Setup S/U interface, enable/disable B-Channels */
+/**************************************************/
+static void
+setup_su(xhfc_t * xhfc, __u8 pt, __u8 bc, __u8 enable)
+{
+	xhfc_port_t *port = &xhfc->port[pt];
+
+	if (!((bc == 0) || (bc == 1))) {
+		printk(KERN_INFO "%s %s: pt(%i) ERROR: bc(%i) unvalid!\n",
+		       xhfc->name, __FUNCTION__, pt, bc);
+		return;
+	}
+
+	if (debug & DEBUG_HFC_MODE)
+		printk(KERN_INFO "%s %s %s pt(%i) bc(%i)\n",
+		       xhfc->name, __FUNCTION__,
+		       (enable) ? ("enable") : ("disable"), pt, bc);
+
+	if (bc) {
+		port->su_ctrl2.bit.v_b2_rx_en = (enable?1:0);
+		port->su_ctrl0.bit.v_b2_tx_en = (enable?1:0);
+	} else {
+		port->su_ctrl2.bit.v_b1_rx_en = (enable?1:0);
+		port->su_ctrl0.bit.v_b1_tx_en = (enable?1:0);
+	}
+
+	if (xhfc->port[pt].mode & PORT_MODE_NT)
+		xhfc->port[pt].su_ctrl0.bit.v_su_md = 1;
+
+	write_xhfc(xhfc, R_SU_SEL, pt);
+	write_xhfc(xhfc, A_SU_CTRL0, xhfc->port[pt].su_ctrl0.reg);
+	write_xhfc(xhfc, A_SU_CTRL2, xhfc->port[pt].su_ctrl2.reg);
+}
+
+/*********************************************/
+/* (dis-) connect D/B-Channel using protocol */
+/*********************************************/
+static int
+setup_channel(xhfc_t * xhfc, __u8 channel, int protocol)
+{
+	xhfc_port_t *port = xhfc->chan[channel].port;
+	
+	if (test_bit(FLG_BCHANNEL, &xhfc->chan[channel].ch.Flags)) {
+		if (debug & DEBUG_HFC_MODE)
+			mISDN_debugprint(&xhfc->chan[channel].ch.inst,
+					 "channel(%i) protocol %x-->%x",
+					 channel,
+					 xhfc->chan[channel].ch.state,
+					 protocol);
+
+		switch (protocol) {
+			case (-1):	/* used for init */
+				xhfc->chan[channel].ch.state = -1;
+				xhfc->chan[channel].ch.channel = channel;
+				/* fall trough */
+			case (ISDN_PID_NONE):
+				if (debug & DEBUG_HFC_MODE)
+					mISDN_debugprint(&xhfc->
+							 chan[channel].ch.inst,
+							 "ISDN_PID_NONE");
+				if (xhfc->chan[channel].ch.state == ISDN_PID_NONE)
+					return (0);	/* already in idle state */
+				xhfc->chan[channel].ch.state = ISDN_PID_NONE;
+
+				setup_fifo(xhfc, (channel << 1),     4, 0, 0, 0);	/* B-TX fifo */
+				setup_fifo(xhfc, (channel << 1) + 1, 4, 0, 0, 0);	/* B-RX fifo */
+
+				setup_su(xhfc, port->idx, (channel % 4) ? 1 : 0, 0);
+				
+				test_and_clear_bit(FLG_HDLC, &xhfc->chan[channel].ch.Flags);
+				test_and_clear_bit(FLG_TRANSPARENT, &xhfc->chan[channel].ch.Flags);
+
+				break;
+
+			case (ISDN_PID_L1_B_64TRANS):
+				if (debug & DEBUG_HFC_MODE)
+					mISDN_debugprint(&xhfc->chan[channel].ch.inst,
+							 "ISDN_PID_L1_B_64TRANS");
+				setup_fifo(xhfc, (channel << 1), 6, 0, 0, 1);	/* B-TX Fifo */
+				setup_fifo(xhfc, (channel << 1) + 1, 6, 0, 0, 1);	/* B-RX Fifo */
+
+				setup_su(xhfc, port->idx, (channel % 4) ? 1 : 0, 1);
+
+				xhfc->chan[channel].ch.state = ISDN_PID_L1_B_64TRANS;
+				test_and_set_bit(FLG_TRANSPARENT, &xhfc->chan[channel].ch.Flags);
+
+				break;
+
+			case (ISDN_PID_L1_B_64HDLC):
+				if (debug & DEBUG_HFC_MODE)
+					mISDN_debugprint(&xhfc->chan[channel].ch.inst,
+							 "ISDN_PID_L1_B_64HDLC");
+				setup_fifo(xhfc, (channel << 1), 4, 0, M_FR_ABO, 1);	// TX Fifo
+				setup_fifo(xhfc, (channel << 1) + 1, 4, 0, M_FR_ABO | M_FIFO_IRQMSK, 1);	// RX Fifo
+
+				setup_su(xhfc, port->idx, (channel % 4) ? 1 : 0, 1);
+
+				xhfc->chan[channel].ch.state = ISDN_PID_L1_B_64HDLC;
+				test_and_set_bit(FLG_HDLC, &xhfc->chan[channel].ch.Flags);
+
+				break;
+			default:
+				mISDN_debugprint(&xhfc->chan[channel].ch.inst,
+					"prot not known %x",
+					protocol);
+				return (-ENOPROTOOPT);
+		}
+		return (0);
+	}
+	else if (test_bit(FLG_DCHANNEL, &xhfc->chan[channel].ch.Flags)) {
+		if (debug & DEBUG_HFC_MODE)
+			mISDN_debugprint(&xhfc->chan[channel].ch.inst,
+					 "channel(%i) protocol(%i)",
+					 channel, protocol);
+
+		setup_fifo(xhfc, (channel << 1), 5, 2, M_FR_ABO, 1);	/* D TX fifo */
+		setup_fifo(xhfc, (channel << 1) + 1, 5, 2, M_FR_ABO | M_FIFO_IRQMSK, 1);	/* D RX fifo */
+
+		return (0);
+	}
+
+	printk(KERN_INFO
+	       "%s %s ERROR: channel(%i) is NEITHER B nor D !!!\n",
+	       xhfc->name, __FUNCTION__, channel);
+
+	return (-1);
+}
+
+/*******************************************************/
+/* register ISDN stack for one XHFC card               */
+/*   - register all ports and channels                 */
+/*   - set param_idx                                   */
+/*                                                     */
+/*  channel mapping in mISDN in xhfc->chan[MAX_CHAN]:  */
+/*    1st line interf:  0=B1,  1=B2,  2=D,  3=PCM      */
+/*    2nd line interf:  4=B1,  5=B2,  6=D,  7=PCM      */
+/*    3rd line interf:  8=B1,  9=B2, 10=D, 11=PCM      */
+/*    4th line interf; 12=B1, 13=B2, 14=D, 15=PCM      */
+/*******************************************************/
+static int
+init_mISDN_channels(xhfc_t * xhfc)
+{
+	int err;
+	int pt;		/* ST/U port index */
+	int ch_idx;	/* channel index */
+	int b;
+	channel_t *ch;
+	mISDN_pid_t pid;
+	u_long flags;
+	
+	for (pt = 0; pt < xhfc->num_ports; pt++) {
+		/* init D channels */
+		ch_idx = (pt << 2) + 2;
+		if (debug & DEBUG_HFC_INIT)
+			printk(KERN_INFO
+			       "%s %s: Registering D-channel, card(%d) "
+			       "ch(%d) port(%d) protocol(%x)\n",
+			       xhfc->name, __FUNCTION__, xhfc->chipnum,
+			       ch_idx, pt, xhfc->port[pt].dpid);
+
+		xhfc->port[pt].idx = pt;
+		xhfc->port[pt].xhfc = xhfc;
+		xhfc->chan[ch_idx].port = &xhfc->port[pt];
+		ch = &xhfc->chan[ch_idx].ch;
+		
+		memset(ch, 0, sizeof(channel_t));
+		ch->channel = ch_idx;
+		ch->debug = debug;
+		ch->inst.obj = &hw_mISDNObj;
+		ch->inst.hwlock = &xhfc->lock;
+		ch->inst.class_dev.dev = &xhfc->pi->pdev->dev;
+		mISDN_init_instance(&ch->inst, &hw_mISDNObj, xhfc, xhfc_l2l1);
+		ch->inst.pid.layermask = ISDN_LAYER(0);
+		sprintf(ch->inst.name, "%s_%d_D", xhfc->name, pt);
+		err = mISDN_initchannel(ch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
+		if (err)
+			goto free_channels;
+		ch->hw = xhfc;
+		
+		/* init t3 timer */
+		init_timer(&xhfc->port[pt].t3_timer);
+		xhfc->port[pt].t3_timer.data = (long) &xhfc->port[pt];
+		xhfc->port[pt].t3_timer.function = (void *) l1_timer_expire_t3;
+
+		/* init t4 timer */
+		init_timer(&xhfc->port[pt].t4_timer);
+		xhfc->port[pt].t4_timer.data = (long) &xhfc->port[pt];
+		xhfc->port[pt].t4_timer.function = (void *) l1_timer_expire_t4;
+
+		/* init B channels */
+		for (b = 0; b < 2; b++) {
+			ch_idx = (pt << 2) + b;
+			if (debug & DEBUG_HFC_INIT)
+				printk(KERN_DEBUG
+				       "%s %s: Registering B-channel, card(%d) "
+				       "ch(%d) port(%d)\n", xhfc->name,
+				       __FUNCTION__, xhfc->chipnum, ch_idx, pt);
+
+			xhfc->chan[ch_idx].port = &xhfc->port[pt];
+			ch = &xhfc->chan[ch_idx].ch;
+			
+			memset(ch, 0, sizeof(channel_t));
+			ch->channel = ch_idx;
+			ch->debug = debug;
+			mISDN_init_instance(&ch->inst, &hw_mISDNObj, xhfc, xhfc_l2l1);
+			ch->inst.pid.layermask = ISDN_LAYER(0);
+			ch->inst.hwlock = &xhfc->lock;
+			ch->inst.class_dev.dev = &xhfc->pi->pdev->dev;			
+			
+			sprintf(ch->inst.name, "%s_%d_B%d",
+				xhfc->name, pt, b + 1);
+
+			if (mISDN_initchannel(ch, MSK_INIT_BCHANNEL, MAX_DATA_MEM)) {
+				err = -ENOMEM;
+				goto free_channels;
+			}
+			ch->hw = xhfc;
+		}
+		
+		/* clear PCM */
+		memset(&xhfc->chan[(pt << 2) + 3], 0, sizeof(channel_t));
+
+		mISDN_set_dchannel_pid(&pid, xhfc->port[pt].dpid,
+				       layermask[xhfc->param_idx + pt]);
+
+		/* register D Channel */
+		ch = &xhfc->chan[(pt << 2) + 2].ch;
+		
+		/* set protocol for NT/TE */
+		if (xhfc->port[pt].mode & PORT_MODE_NT) {
+			/* NT-mode */
+			xhfc->port[xhfc->param_idx + pt].mode |= NT_TIMER;
+			xhfc->port[xhfc->param_idx + pt].nt_timer = 0;
+
+			ch->inst.pid.protocol[0] = ISDN_PID_L0_NT_S0;
+			ch->inst.pid.protocol[1] = ISDN_PID_L1_NT_S0;
+			pid.protocol[0] = ISDN_PID_L0_NT_S0;
+			pid.protocol[1] = ISDN_PID_L1_NT_S0;
+			ch->inst.pid.layermask |= ISDN_LAYER(1);
+			pid.layermask |= ISDN_LAYER(1);
+			if (layermask[xhfc->param_idx + pt] & ISDN_LAYER(2))
+				pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
+		} else {
+			/* TE-mode */
+			xhfc->port[xhfc->param_idx + pt].mode |= PORT_MODE_TE;
+			ch->inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
+			ch->inst.pid.protocol[1] = ISDN_PID_L1_TE_S0;
+			pid.protocol[0] = ISDN_PID_L0_TE_S0;
+			pid.protocol[1] = ISDN_PID_L1_TE_S0;
+		}
+
+		if (debug & DEBUG_HFC_INIT)
+			printk(KERN_INFO
+			       "%s %s: registering Stack for Port %i\n",
+			       xhfc->name, __FUNCTION__, pt);
+
+		/* register stack */
+		err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &ch->inst);
+		if (err) {
+			printk(KERN_ERR
+			       "%s %s: MGR_NEWSTACK | REQUEST  err(%d)\n",
+			       xhfc->name, __FUNCTION__, err);
+			goto free_channels;
+		}
+		ch->state = 0;
+
+		/* attach two BChannels to this DChannel (ch) */
+		for (b = 0; b < 2; b++) {
+			err = mISDN_ctrl(ch->inst.st, MGR_NEWSTACK | REQUEST,
+				&xhfc->chan[(pt << 2) + b].ch.inst);
+			if (err) {
+				printk(KERN_ERR
+				       "%s %s: MGR_ADDSTACK bchan error %d\n",
+				       xhfc->name, __FUNCTION__, err);
+				goto free_stack;
+			}
+		}
+
+		err = mISDN_ctrl(ch->inst.st, MGR_SETSTACK | REQUEST, &pid);
+
+		if (err) {
+			printk(KERN_ERR
+			       "%s %s: MGR_SETSTACK REQUEST dch err(%d)\n",
+			       xhfc->name, __FUNCTION__, err);
+			mISDN_ctrl(ch->inst.st, MGR_DELSTACK | REQUEST, NULL);
+			goto free_stack;
+		}
+
+		/* initial setup of each channel */
+		setup_channel(xhfc, ch->channel, -1);
+		for (b = 0; b < 2; b++)
+			setup_channel(xhfc, (pt << 2) + b, -1);
+
+		/* delay some time */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((100 * HZ) / 1000);	/* Timeout 100ms */
+
+		mISDN_ctrl(ch->inst.st, MGR_CTRLREADY | INDICATION, NULL);
+	}
+	return (0);
+
+      free_stack:
+	mISDN_ctrl(ch->inst.st, MGR_DELSTACK | REQUEST, NULL);
+      free_channels:
+      	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+	release_channels(xhfc);
+	list_del(&xhfc->list);
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+
+	return (err);
+}
+
+/********************************/
+/* parse module paramaters like */
+/* NE/TE and S0/Up port mode    */
+/********************************/
+static void
+parse_module_params(xhfc_t * xhfc)
+{
+	__u8 pt;
+
+	/* parse module parameters */
+	for (pt = 0; pt < xhfc->num_ports; pt++) {
+		/* D-Channel protocol: (2=DSS1) */
+		xhfc->port[pt].dpid = (protocol[xhfc->param_idx + pt] & 0x0F);
+		if (xhfc->port[pt].dpid == 0) {
+			printk(KERN_INFO
+			       "%s %s: WARNING: wrong value for protocol[%i], "
+			       "assuming 0x02 (DSS1)...\n",
+			       xhfc->name, __FUNCTION__,
+			       xhfc->param_idx + pt);
+			xhfc->port[pt].dpid = 0x02;
+		}
+
+		/* Line Interface TE or NT */
+		if (protocol[xhfc->param_idx + pt] & 0x10)
+			xhfc->port[pt].mode |= PORT_MODE_NT;
+		else
+			xhfc->port[pt].mode |= PORT_MODE_TE;
+
+		/* Line Interface in S0 or Up mode */
+		if (protocol[xhfc->param_idx + pt] & 0x20)
+			xhfc->port[pt].mode |= PORT_MODE_UP;
+		else
+			xhfc->port[pt].mode |= PORT_MODE_S0;
+
+		/* st line polarity */
+		if (protocol[xhfc->param_idx + pt] & 0x40)
+			xhfc->port[pt].mode |= PORT_MODE_EXCH_POL;
+
+		/* get layer1 loop-config */
+		if (protocol[xhfc->param_idx + pt] & 0x80)
+			xhfc->port[pt].mode |= PORT_MODE_LOOP_B1;
+
+		if (protocol[xhfc->param_idx + pt] & 0x0100)
+			xhfc->port[pt].mode |= PORT_MODE_LOOP_B2;
+
+		if (protocol[xhfc->param_idx + pt] & 0x0200)
+			xhfc->port[pt].mode |= PORT_MODE_LOOP_D;
+
+		if (debug & DEBUG_HFC_INIT)
+			printk ("%s %s: protocol[%i]=0x%02x, dpid=%d, mode:%s,%s %s, Loops:0x%x\n",
+			        xhfc->name, __FUNCTION__, xhfc->param_idx+pt,
+			        protocol[xhfc->param_idx + pt],
+			        xhfc->port[pt].dpid,
+			        (xhfc->port[pt].mode & PORT_MODE_TE)?"TE":"NT",
+			        (xhfc->port[pt].mode & PORT_MODE_S0)?"S0":"Up",
+			        (xhfc->port[pt].mode & PORT_MODE_EXCH_POL)?"SU_EXCH":"",
+			        (xhfc->port[pt].mode & PORT_MODE_LOOPS)
+			        );
+	}
+}
+
+/********************************/
+/* initialise the XHFC hardware */
+/* return 0 on success.         */
+/********************************/
+static int __devinit
+setup_instance(xhfc_t * xhfc)
+{
+	int err;
+	int pt;
+	xhfc_t *previous_hw;
+	xhfc_port_t * port = NULL;
+	xhfc_chan_t * chan = NULL;
+	u_long flags;
+
+
+	spin_lock_init(&xhfc->lock);
+	tasklet_init(&xhfc->tasklet, xhfc_bh_handler, (unsigned long) xhfc);
+
+	/* search previous instances to index protocol[] array */
+	list_for_each_entry(previous_hw, &hw_mISDNObj.ilist, list) {
+		xhfc->param_idx += previous_hw->num_ports;
+	}
+
+	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+	/* add this instance to hardware list */
+	list_add_tail(&xhfc->list, &hw_mISDNObj.ilist);
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+
+	err = init_xhfc(xhfc);
+	if (err)
+		goto out;
+
+	/* alloc mem for all ports and channels */
+	err = -ENOMEM;
+	port = kmalloc(sizeof(xhfc_port_t) * xhfc->num_ports, GFP_KERNEL);
+	if (port) {
+		xhfc->port = port;
+		memset(xhfc->port, 0, sizeof(xhfc_port_t) * xhfc->num_ports);
+		chan = kmalloc(sizeof(xhfc_chan_t) * xhfc->num_ports * CHAN_PER_PORT, GFP_KERNEL);
+		if (chan) {
+			xhfc->chan = chan;
+			memset(xhfc->chan, 0, sizeof(xhfc_chan_t) * xhfc->num_ports * CHAN_PER_PORT);
+			err = 0;
+		} else {
+			printk(KERN_ERR "%s %s: No kmem for xhfc_chan_t*%i \n",
+			       xhfc->name, __FUNCTION__, xhfc->num_ports * CHAN_PER_PORT);	
+			goto out;
+		}
+	} else {
+		printk(KERN_ERR "%s %s: No kmem for xhfc_port_t*%i \n",
+		       xhfc->name, __FUNCTION__, xhfc->num_ports);	
+		goto out;	
+	}
+	
+	parse_module_params(xhfc);
+
+	/* init line interfaces (ports) */
+	for (pt = 0; pt < xhfc->num_ports; pt++) {
+		sprintf(xhfc->port[pt].name, "%s_%i", xhfc->name, pt);
+		init_su(xhfc, pt);
+	}
+
+	/* register all channels at ISDN procol stack */
+	err = init_mISDN_channels(xhfc);
+	if (err)
+		goto out;
+
+	/* delay some time */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((100 * HZ) / 1000);	/* Timeout 100ms */
+
+	enable_interrupts(xhfc);
+
+	/* force initial layer1 statechanges */
+	xhfc->su_irq.reg = xhfc->su_irqmsk.reg;
+
+	/* init loops if desired */
+	for (pt = 0; pt < xhfc->num_ports; pt++) {
+		if (xhfc->port[pt].mode & PORT_MODE_LOOP_B1)
+			xhfc_ph_command(&xhfc->port[pt], HFC_L1_TESTLOOP_B1);
+		if (xhfc->port[pt].mode & PORT_MODE_LOOP_B2)
+			xhfc_ph_command(&xhfc->port[pt], HFC_L1_TESTLOOP_B2);
+		if (xhfc->port[pt].mode & PORT_MODE_LOOP_D)
+			xhfc_ph_command(&xhfc->port[pt], HFC_L1_TESTLOOP_D);
+	}
+
+	return (0);
+
+      out:
+	if (xhfc->chan)
+		kfree(xhfc->chan);
+	if (xhfc->port)
+		kfree(xhfc->port);
+	return (err);
+}
+
+/************************/
+/* release single card  */
+/************************/
+static void
+release_card(xhfc_pi * pi)
+{
+	u_long	flags;
+	__u8 i;
+
+	for (i=0; i<pi->driver_data.num_xhfcs; i++)
+		disable_interrupts(&pi->xhfc[i]);
+
+	free_irq(pi->irq, pi);
+
+	/* wait for pending tasklet to finish */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((100 * HZ) / 1000);	/* Timeout 100ms */
+
+	spin_lock_irqsave(&hw_mISDNObj.lock, flags);
+	for (i=0; i<pi->driver_data.num_xhfcs; i++) {
+		release_channels(&pi->xhfc[i]);
+		list_del(&pi->xhfc[i].list);
+	}
+	spin_unlock_irqrestore(&hw_mISDNObj.lock, flags);
+
+	kfree(pi->xhfc);
+	kfree(pi);
+}
+
+#if BRIDGE == BRIDGE_PCI2PI
+
+/*****************************************/
+/* PCI hotplug interface: probe new card */
+/*****************************************/
+static int __devinit
+xhfc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	pi_params * driver_data = (pi_params *) ent->driver_data;
+	xhfc_pi * pi = NULL;
+	__u8 i;
+
+	int err = -ENOMEM;
+
+	/* alloc mem for ProcessorInterface xhfc_pi */
+	if (!(pi = kmalloc(sizeof(xhfc_pi), GFP_KERNEL))) {
+		printk(KERN_ERR "%s: No kmem for XHFC card\n",
+		       __FUNCTION__);
+		goto out;
+	}
+	memset(pi, 0, sizeof(xhfc_pi));
+
+	pi->cardnum = card_cnt;
+
+	sprintf(pi->name, "%s_PI%d", DRIVER_NAME, pi->cardnum);
+	printk(KERN_INFO "%s %s: adapter '%s' found on PCI bus %02x dev %02x, using %i XHFC controllers\n",
+	       pi->name, __FUNCTION__, driver_data->device_name,
+	       pdev->bus->number, pdev->devfn, driver_data->num_xhfcs);
+
+	/* alloc mem for all XHFCs (xhfc_t) */
+	if (!(pi->xhfc = kmalloc(sizeof(xhfc_t) * driver_data->num_xhfcs, GFP_KERNEL))) {
+		printk(KERN_ERR "%s %s: No kmem for sizeof(xhfc_t)*%i \n",
+		       pi->name, __FUNCTION__, driver_data->num_xhfcs);
+		goto out;
+	}
+	memset(pi->xhfc, 0, sizeof(xhfc_t) * driver_data->num_xhfcs);
+
+	pi->pdev = pdev;
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s %s: error with pci_enable_device\n",
+		       pi->name, __FUNCTION__);
+		goto out;
+	}
+
+	if (driver_data->num_xhfcs > PCI2PI_MAX_XHFC) {
+		printk(KERN_ERR "%s %s: max number og adressable XHFCs aceeded\n",
+		       pi->name, __FUNCTION__);
+		goto out;
+	}
+
+	pi->driver_data = *driver_data;
+	pi->irq = pdev->irq;
+	pi->hw_membase = (u_char *) pci_resource_start(pdev, 1);
+	pi->membase = ioremap((ulong) pi->hw_membase, 4096);
+	pci_set_drvdata(pdev, pi);
+
+	err = init_pci_bridge(pi);
+	if (err) {
+		printk(KERN_ERR "%s %s: init_pci_bridge failed!\n",
+		       pi->name, __FUNCTION__);
+		goto out;
+	}
+
+	/* init interrupt engine */
+	if (request_irq(pi->irq, xhfc_interrupt, SA_SHIRQ, "XHFC", pi)) {
+		printk(KERN_WARNING "%s %s: couldn't get interrupt %d\n",
+		       pi->name, __FUNCTION__, pi->irq);
+		pi->irq = 0;
+		err = -EIO;
+		goto out;
+	}
+
+	err = 0;
+	for (i=0; i<pi->driver_data.num_xhfcs; i++) {
+		pi->xhfc[i].pi = pi;
+		pi->xhfc[i].chipidx = i;
+		err |= setup_instance(&pi->xhfc[i]);
+	}
+
+	if (!err) {
+		card_cnt++;
+		return (0);
+	} else {
+		goto out;
+	}
+
+      out:
+	if (pi->xhfc)
+		kfree(pi->xhfc);
+	if (pi)
+		kfree(pi);
+	return (err);
+};
+
+/**************************************/
+/* PCI hotplug interface: remove card */
+/**************************************/
+static void __devexit
+xhfc_pci_remove(struct pci_dev *pdev)
+{
+	xhfc_pi *pi = pci_get_drvdata(pdev);
+	printk(KERN_INFO "%s %s: removing card\n", pi->name,
+	       __FUNCTION__);
+	release_card(pi);
+	card_cnt--;
+	pci_disable_device(pdev);
+	return;
+};
+
+
+static struct pci_device_id xhfc_ids[] = {
+	{.vendor = PCI_VENDOR_ID_CCD,
+	 .device = 0xA003,
+	 .subvendor = 0x1397,
+	 .subdevice = 0xA003,
+	 .driver_data =
+	 (unsigned long) &((pi_params) {1, "XHFC Evaluation Board"}),
+	 },
+	{}
+};
+
+/***************/
+/* Module init */
+/***************/
+static struct pci_driver xhfc_driver = {
+      name:DRIVER_NAME,
+      probe:xhfc_pci_probe,
+      remove:__devexit_p(xhfc_pci_remove),
+      id_table:xhfc_ids,
+};
+
+
+MODULE_DEVICE_TABLE(pci, xhfc_ids);
+
+#endif // BRIDGE_PCI2PI
+
+/***************/
+/* Module init */
+/***************/
+static int __init
+xhfc_init(void)
+{
+	int err;
+
+	printk(KERN_INFO "XHFC: %s driver Rev. %s (debug=%i)\n",
+	       __FUNCTION__, mISDN_getrev(xhfc_rev), debug);
+
+#ifdef MODULE
+	hw_mISDNObj.owner = THIS_MODULE;
+#endif
+
+	INIT_LIST_HEAD(&hw_mISDNObj.ilist);
+	spin_lock_init(&hw_mISDNObj.lock);
+	hw_mISDNObj.name = DRIVER_NAME;
+	hw_mISDNObj.own_ctrl = xhfc_manager;
+
+	hw_mISDNObj.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0 | ISDN_PID_L0_NT_S0;
+	hw_mISDNObj.DPROTO.protocol[1] = ISDN_PID_L1_TE_S0 | ISDN_PID_L1_NT_S0;
+	hw_mISDNObj.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS | ISDN_PID_L1_B_64HDLC;
+	hw_mISDNObj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS | ISDN_PID_L2_B_RAWDEV;
+	card_cnt = 0;
+
+	if ((err = mISDN_register(&hw_mISDNObj))) {
+		printk(KERN_ERR "XHFC: can't register xhfc error(%d)\n",
+		       err);
+		goto out;
+	}
+	
+#if BRIDGE == BRIDGE_PCI2PI
+	err = pci_register_driver(&xhfc_driver);
+	if (err < 0) {
+		goto out;
+	}
+#endif
+
+	printk(KERN_INFO "XHFC: %d cards installed\n", card_cnt);
+
+#if !defined(CONFIG_HOTPLUG)
+	if (err == 0) {
+		err = -ENODEV;
+		pci_unregister_driver(&xhfc_driver);
+		goto out;
+	}
+#endif
+
+	mISDN_module_register(THIS_MODULE);
+
+	return 0;
+
+      out:
+	return (err);
+}
+
+static void __exit
+xhfc_cleanup(void)
+{
+	int err;
+
+	mISDN_module_unregister(THIS_MODULE);
+
+#if BRIDGE == BRIDGE_PCI2PI
+	pci_unregister_driver(&xhfc_driver);
+#endif
+
+	if ((err = mISDN_unregister(&hw_mISDNObj))) {
+		printk(KERN_ERR "XHFC: can't unregister xhfc, error(%d)\n",
+		       err);
+	}
+	printk(KERN_INFO "%s: driver removed\n", __FUNCTION__);
+}
+
+module_init(xhfc_init);
+module_exit(xhfc_cleanup);

Added: misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_su.h
===================================================================
--- misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_su.h	                        (rev 0)
+++ misdn-kernel/trunk/drivers/isdn/hardware/mISDN/xhfc_su.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,218 @@
+/* $Id: xhfc_su.h,v 1.6 2006/03/17 07:43:41 mbachem Exp $
+ *
+ * mISDN driver for Colognechip xHFC chip
+ *
+ * Authors : Martin Bachem, Joerg Ciesielski
+ * Contact : info at colognechip.com
+ *
+ * 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.
+ *
+ */
+
+#ifndef _XHFC_SU_H_
+#define _XHFC_SU_H_
+
+#include <linux/timer.h>
+#include "channel.h"
+#include "xhfc24succ.h"
+
+#define DRIVER_NAME "XHFC"
+
+#ifndef CHIP_ID_2S4U
+#define CHIP_ID_2S4U	0x62
+#endif
+#ifndef CHIP_ID_4SU
+#define CHIP_ID_4SU	0x63
+#endif
+#ifndef CHIP_ID_1SU
+#define CHIP_ID_1SU	0x60
+#endif
+#ifndef CHIP_ID_2SU
+#define CHIP_ID_2SU	0x61
+#endif
+
+
+/* define bridge for chip register access */	
+#define BRIDGE_UNKWOWN	0
+#define BRIDGE_PCI2PI	1 /* used at Cologne Chip AG's Evaluation Card */
+#define BRIDGE		BRIDGE_PCI2PI
+
+#define MAX_PORT	4
+#define CHAN_PER_PORT	4	/* D, B1, B2, PCM */
+#define MAX_CHAN	MAX_PORT * CHAN_PER_PORT
+
+/* flags in _u16  port mode */
+#define PORT_UNUSED		0x0000
+#define PORT_MODE_NT		0x0001
+#define PORT_MODE_TE		0x0002
+#define PORT_MODE_S0		0x0004
+#define PORT_MODE_UP		0x0008
+#define PORT_MODE_EXCH_POL	0x0010
+#define PORT_MODE_LOOP_B1	0x0020
+#define PORT_MODE_LOOP_B2	0x0040
+#define PORT_MODE_LOOP_D	0x0080
+#define NT_TIMER		0x8000
+
+#define PORT_MODE_LOOPS		0xE0	/* mask port mode Loop B1/B2/D */
+
+
+/* NT / TE defines */
+#define NT_T1_COUNT	25	/* number of 4ms interrupts for G2 timeout */
+#define CLK_DLY_TE	0x0e	/* CLKDEL in TE mode */
+#define CLK_DLY_NT	0x6c	/* CLKDEL in NT mode */
+#define STA_ACTIVATE	0x60	/* start activation   in A_SU_WR_STA */
+#define STA_DEACTIVATE	0x40	/* start deactivation in A_SU_WR_STA */
+#define LIF_MODE_NT	0x04	/* Line Interface NT mode */
+#define XHFC_TIMER_T3	8000	/* 8s activation timer T3 */
+#define XHFC_TIMER_T4	500	/* 500ms deactivation timer T4 */
+
+/* xhfc Layer1 physical commands */
+#define HFC_L1_ACTIVATE_TE		0x00
+#define HFC_L1_FORCE_DEACTIVATE_TE	0x01
+#define HFC_L1_ACTIVATE_NT		0x02
+#define HFC_L1_DEACTIVATE_NT		0x03
+#define HFC_L1_TESTLOOP_B1		0x04
+#define HFC_L1_TESTLOOP_B2		0x05
+#define HFC_L1_TESTLOOP_D		0x06
+
+
+/* xhfc Layer1 Flags (stored in xhfc_port_t->l1_flags) */
+#define HFC_L1_ACTIVATING	1
+#define HFC_L1_ACTIVATED	2
+#define HFC_L1_DEACTTIMER	4
+#define HFC_L1_ACTTIMER		8
+
+#define FIFO_MASK_TX	0x55555555
+#define FIFO_MASK_RX	0xAAAAAAAA
+
+
+/* DEBUG flags, use combined value for module parameter debug=x */
+#define DEBUG_HFC_INIT		0x0001
+#define DEBUG_HFC_MODE		0x0002
+#define DEBUG_HFC_S0_STATES	0x0004
+#define DEBUG_HFC_IRQ		0x0008
+#define DEBUG_HFC_FIFO_ERR	0x0010
+#define DEBUG_HFC_DTRACE	0x2000
+#define DEBUG_HFC_BTRACE	0x4000	/* very(!) heavy messageslog load */
+#define DEBUG_HFC_FIFO		0x8000	/* very(!) heavy messageslog load */
+
+#define USE_F0_COUNTER	1	/* akkumulate F0 counter diff every irq */
+#define TRANSP_PACKET_SIZE 0	/* minium tranparent packet size for transmittion to upper layer */
+
+
+/* private driver_data */
+typedef struct {
+	__u8	num_xhfcs;
+	char	*device_name;
+} pi_params;
+
+
+struct _xhfc_t;
+struct _xhfc_pi;
+
+/* port struct for each S/U port */
+typedef struct {
+	int idx;
+	struct _xhfc_t * xhfc;
+	char name[20];	/* XHFC_PI0_0_0 = ProcessorInterface no. 0, Chip no. 0, port no 0 */
+	
+	__u8 dpid;		/* DChannel Protocoll ID */
+	__u16 mode;		/* NT/TE + ST/U */
+	int nt_timer;
+
+	u_long	l1_flags;
+	struct timer_list t3_timer;	/* timer 3 for activation/deactivation */
+	struct timer_list t4_timer;	/* timer 4 for activation/deactivation */
+
+	/* chip registers */
+	reg_a_su_ctrl0 su_ctrl0;
+	reg_a_su_ctrl1 su_ctrl1;
+	reg_a_su_ctrl2 su_ctrl2;
+	reg_a_st_ctrl3 st_ctrl3;
+} xhfc_port_t;
+
+
+/* channel struct for each fifo */
+typedef struct {
+	channel_t   ch;
+	xhfc_port_t * port;
+} xhfc_chan_t;
+
+
+/**********************/
+/* hardware structure */
+/**********************/
+typedef struct _xhfc_t {
+	char		name[15];	/* XHFC_PI0_0 = ProcessorInterface no. 0, Chip no. 0 */
+	__u8		chipnum;	/* global chip number */
+	__u8		chipidx;	/* index in pi->xhfcs[NUM_XHFCS] */
+	struct _xhfc_pi	* pi;		/* backpointer to xhfc_pi */
+	__u8		param_idx;	/* used to access module param arrays */
+	
+	struct list_head list;
+	spinlock_t lock;
+	struct tasklet_struct tasklet;	/* interrupt bottom half */
+	
+	__u8 testirq;
+
+	int num_ports;		/* number of S and U interfaces */
+	int max_fifo;		/* always 4 fifos per port */
+	__u8 max_z;		/* fifo depth -1 */
+
+	xhfc_port_t * port;	/* one for each Line intercace */
+	xhfc_chan_t * chan;	/* one each D/B/PCM channel */
+
+	__u32 irq_cnt;	/* count irqs */
+	__u32 f0_cnt;	/* last F0 counter value */
+	__u32 f0_akku;	/* akkumulated f0 counter deltas */
+
+	/* chip registers */
+	reg_r_irq_ctrl 		irq_ctrl;
+	reg_r_misc_irqmsk	misc_irqmsk;	/* mask of enabled interrupt sources */
+	reg_r_misc_irq		misc_irq;	/* collect interrupt status bits */
+
+	reg_r_su_irqmsk		su_irqmsk;	/* mask of line interface state change interrupts */
+	reg_r_su_irq		su_irq;		/* collect interrupt status bits */
+	reg_r_ti_wd		ti_wd;		/* timer interval */
+
+	reg_r_pcm_md0		pcm_md0;
+	reg_r_pcm_md1		pcm_md1;
+
+	__u32 fifo_irq;		/* fifo bl irq */
+	__u32 fifo_irqmsk;	/* fifo bl irq */
+	
+} xhfc_t;
+
+
+/**********************/
+/* hardware structure */
+/**********************/
+typedef struct _xhfc_pi {
+#if BRIDGE == BRIDGE_PCI2PI
+	struct pci_dev *pdev;
+	int		irq;
+	int 		iobase;	
+	u_char		*membase;
+	u_char		*hw_membase;
+	int		cardnum;
+	char		name[10];	/* 'XHFC_PI0' = ProcessorInterface no. 0 */
+	pi_params	driver_data;
+#endif
+
+	xhfc_t		* xhfc;
+} xhfc_pi;
+
+
+#endif				/* _XHFC_SU_H_ */

Added: misdn-kernel/trunk/include/linux/isdn_compat.h
===================================================================
--- misdn-kernel/trunk/include/linux/isdn_compat.h	                        (rev 0)
+++ misdn-kernel/trunk/include/linux/isdn_compat.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,128 @@
+#ifndef _LINUX_ISDN_COMPAT_H
+#define _LINUX_ISDN_COMPAT_H
+
+#ifdef __KERNEL__
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+
+#define set_current_state(sta) (current->state = sta)
+#define module_init(x)  int init_module(void) { return x(); }
+#define module_exit(x)  void cleanup_module(void) { x(); }
+#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0 = 0; } while (0)
+#define init_MUTEX(x)                           *(x)=MUTEX
+#define init_MUTEX_LOCKED(x)                    *(x)=MUTEX_LOCKED
+#define __devinit
+#define __devinitdata
+
+#else
+#define COMPAT_HAS_NEW_WAITQ
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+
+#define COMPAT_HAS_2_2_PCI
+#define get_pcibase(ps,nr) ps->base_address[nr]
+#define pci_resource_start_io(pdev,nr)	pdev->base_address[nr] & PCI_BASE_ADDRESS_IO_MASK
+#define pci_resource_start_mem(pdev,nr)	pdev->base_address[nr] & PCI_BASE_ADDRESS_MEM_MASK
+#define pci_get_sub_vendor(pdev, id)	pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &id)
+#define pci_get_sub_system(pdev, id)	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &id)
+#define dev_kfree_skb_any(a)		dev_kfree_skb(a)
+#define dev_kfree_skb_irq(a)		dev_kfree_skb(a)
+typedef	struct timer_list		timer_t;
+#else /* 2.4.0 and later */
+#include <linux/netdevice.h>
+#define pci_resource_start_io(pdev, nr) pci_resource_start(pdev, nr)
+#define pci_resource_start_mem(pdev, nr) pci_resource_start(pdev, nr)
+#define get_pcibase(ps, nr) ps->resource[nr].start
+#define pci_get_sub_system(pdev, id)	id = pdev->subsystem_device
+#define pci_get_sub_vendor(pdev, id)	id = pdev->subsystem_vendor
+#endif /* 2,4,0 */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#ifndef IRQ_HANDLED /* maybe these are also defined in include/linux/interrupt.h */
+typedef void irqreturn_t;
+#define IRQ_NONE
+#define IRQ_HANDLED
+#define IRQ_RETVAL(x)
+#endif
+#define CAPI_SendMessage_void
+#define OLDCAPI_DRIVER_INTERFACE
+#undef  HAS_WORKQUEUE
+#define work_struct	tq_struct
+#define INIT_WORK(q, f, d)	(q)->routine=f;(q)->data=d;
+#define schedule_work(q)	queue_task(q, &tq_immediate);mark_bh(IMMEDIATE_BH);
+#define MAKEDAEMON(n)		daemonize();strcpy(current->comm, n)
+#undef NEW_ISAPNP
+#define pnp_register_driver(d)		isapnp_register_driver(d)
+#define pnp_unregister_driver(d)	isapnp_unregister_driver(d)
+#define pnp_get_drvdata(d)		pci_get_drvdata(d)
+#define pnp_set_drvdata(p,d)		pci_set_drvdata(p,d)
+#define pnp_activate_dev(d)		isapnp_activate_dev(d, "mISDN")
+#define pnp_disable_dev(d)		((struct pci_dev *)d)->prepare(d);((struct pci_dev *)d)->deactivate(d)
+#define pnp_port_start(d,n)		d->resource[n].start
+#define pnp_irq(d,n)			d->irq_resource[n].start
+#undef iminor
+#define iminor(i)	MINOR(i->i_rdev)
+#else
+#undef  OLDCAPI_DRIVER_INTERFACE
+#define HAS_WORKQUEUE
+#undef  MINOR
+#define MINOR(inode)	minor(inode)
+#define NEED_JIFFIES_INCLUDE
+#define MAKEDAEMON(n)	daemonize(n)
+#define NEW_ISAPNP
+#endif /* 2,5,0 */
+
+#ifndef COMPAT_HAS_NEW_WAITQ
+typedef struct wait_queue wait_queue_t;
+typedef struct wait_queue *wait_queue_head_t;
+
+#define DECLARE_WAITQUEUE(wait, current)	struct wait_queue wait = { current, NULL }
+#define DECLARE_WAIT_QUEUE_HEAD(wait)		wait_queue_head_t wait
+#define init_waitqueue_head(x)			*(x)=NULL
+#define init_waitqueue_entry(q,p)		((q)->task)=(p)
+#endif /* COMPAT_HAS_NEW_WAITQ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+#define	OLD_PCI_REGISTER_DRIVER	1
+#define OLD_MODULE_PARAM_ARRAY
+#else
+#undef	OLD_PCI_REGISTER_DRIVER
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
+#define __ATTR(_name,_mode,_show,_store) { \
+	.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
+	.show   = _show,								\
+	.store  = _store,								\
+}
+#define LOCAL_FCSTAB
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+#define MODULE_MKOBJ_POINTER
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11)
+#define CLASSDEV_HAS_DEVT
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
+#define OLD_MODULE_PARAM
+/* udev sysfs stuff */
+#define CLASS_WITHOUT_OWNER
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+#define kzalloc kmalloc
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+#define kzalloc(s,f) kcalloc(1,s,f)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+#include <linux/config.h>
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_ISDN_COMPAT_H */

Added: misdn-kernel/trunk/include/linux/mISDNdebugtool.h
===================================================================
--- misdn-kernel/trunk/include/linux/mISDNdebugtool.h	                        (rev 0)
+++ misdn-kernel/trunk/include/linux/mISDNdebugtool.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,44 @@
+#ifndef __mISDNdebugtool_H__
+#define __mISDNdebugtool_H__
+
+/*
+ * 0        8        16       24      31
+ * +--------+--------+--------+--------+
+ * |  vers  |  type  |    reserved     +
+ * +--------+--------+--------+--------+
+ * |         stack identifier          +
+ * +--------+--------+--------+--------+
+ * |        seconds since epoch        |
+ * +--------+--------+--------+--------+
+ * |            nanoseconds            |
+ * +--------+--------+--------+--------+
+ * |          payload length           |
+ * +--------+--------+--------+--------+
+ */
+
+enum mISDN_dt_type {
+
+	D_RX = 1,  /* payload: copy of dchannel payload */
+	D_TX,      /* payload: copy of dchannel payload */
+
+	L1_UP,     /* no payload */
+	L1_DOWN,   /* no payload */
+
+	CRC_ERR,   /* no payload */
+
+	NEWSTATE,  /* payload: state-id (uint) :: message (NULL-terminated charstring)
+	              thrown by: hfcmulti */
+};
+
+typedef struct mISDN_dt_header {
+	unsigned char version;
+	unsigned char type;
+	unsigned short reserved;
+	unsigned int stack_id;
+	unsigned int stack_protocol;
+	struct timespec time;
+	unsigned int plength;
+} mISDN_dt_header_t;
+
+#endif
+

Added: misdn-kernel/trunk/include/linux/mISDNif.h
===================================================================
--- misdn-kernel/trunk/include/linux/mISDNif.h	                        (rev 0)
+++ misdn-kernel/trunk/include/linux/mISDNif.h	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,906 @@
+/* $Id: mISDNif.h,v 1.42 2006/12/27 18:50:50 jolly Exp $
+ *
+ */
+
+#ifndef mISDNIF_H
+#define mISDNIF_H
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
+/*
+ * ABI Version 32 bit
+ *
+ * <16 bit> Major version
+ *		- changed if any interface become backwards incompatible
+ *
+ * <16 bit> Minor version
+ *              - changed if any interface is extended but backwards compatible
+ *
+ */
+#define	MISDN_MAJOR_VERSION	5
+#define	MISDN_MINOR_VERSION	0
+#define	MISDN_VERSION		((MISDN_MAJOR_VERSION<<16) | MISDN_MINOR_VERSION)
+
+#define MISDN_REVISION		"$Revision: 1.42 $"
+#define MISDN_DATE		"$Date: 2006/12/27 18:50:50 $"
+
+/* collect some statistics about the message queues */
+//#define MISDN_MSG_STATS
+
+/* primitives for information exchange
+ * generell format
+ * <8 bit reserved>
+ * <4 bit flags>
+ * <4 bit layer>
+ * <8 bit command>
+ * <8 bit subcommand>
+ *
+ */
+
+#define MISDN_CMD_MASK	0xffffff00
+#define MISDN_SUB_MASK	0x000000ff
+
+/* SUBCOMMANDS */
+#define REQUEST		0x80
+#define CONFIRM		0x81
+#define INDICATION	0x82
+#define RESPONSE	0x83
+#define SUB_ERROR	0xff
+
+/* management */
+#define MGR_FUNCTION	0x0f0000
+#define MGR_GETOBJECT	0x0f0100
+#define MGR_NEWOBJECT	0x0f0200
+#define MGR_DELOBJECT	0x0f0300
+#define MGR_NEWENTITY	0x0f0600
+#define MGR_DELENTITY	0x0f0700
+#define MGR_GETSTACK	0x0f1100
+#define MGR_NEWSTACK	0x0f1200
+#define MGR_DELSTACK	0x0f1300
+#define MGR_SETSTACK	0x0f1400
+#define MGR_CLEARSTACK	0x0f1500
+#define MGR_REGLAYER	0x0f1600
+#define MGR_UNREGLAYER	0x0f1700
+#define MGR_SELCHANNEL	0x0f1800
+#define MGR_SETSTACK_NW	0x0f1900
+#define MGR_ADDSTPARA	0x0f1A00
+#define MGR_CLRSTPARA	0x0f1B00
+#define MGR_ADDLAYER	0x0f1C00
+#define MGR_GETLAYER	0x0f2100
+#define MGR_GETLAYERID	0x0f2200
+#define MGR_NEWLAYER	0x0f2300
+#define MGR_DELLAYER	0x0f2400
+//#define MGR_CLONELAYER	0x0f2500
+//#define MGR_GETIF	0x0f3100
+//#define MGR_CONNECT	0x0f3200
+//#define MGR_DISCONNECT	0x0f3300
+//#define MGR_SETIF	0x0f3400
+//#define MGR_ADDIF	0x0f3500
+//#define MGR_QUEUEIF	0x0f3600
+#define MGR_CTRLREADY	0x0f4100
+#define MGR_STACKREADY	0x0f4200
+#define MGR_STOPSTACK	0x0f4300
+#define MGR_STARTSTACK	0x0f4400
+#define MGR_RELEASE	0x0f4500
+#define MGR_GETDEVICE	0x0f5100
+#define MGR_DELDEVICE	0x0f5200
+#define MGR_SETDEVOPT	0x0f5300
+#define MGR_GETDEVOPT	0x0f5400
+#define MGR_INITTIMER	0x0f8100
+#define MGR_ADDTIMER	0x0f8200
+#define MGR_DELTIMER	0x0f8300
+#define MGR_REMOVETIMER	0x0f8400
+#define MGR_TIMER	0x0f8800
+#define MGR_CONTROL	0x0fe100
+#define MGR_STATUS	0x0fe200
+#define MGR_HASPROTOCOL	0x0fe300
+#define MGR_EVALSTACK	0x0fe400
+#define MGR_GLOBALOPT	0x0fe500
+#define MGR_SHORTSTATUS	0x0fe600
+#define MGR_LOADFIRM	0x0ff000
+#define MGR_LOGDATA	0x0ff100
+#define MGR_DEBUGDATA	0x0ff200
+#define MGR_VERSION	0x0fff00
+
+/* layer 1 <-> hardware */
+#define PH_SIGNAL	0x000100
+#define PH_CONTROL	0x000200
+#define PH_STATUS	0x000300
+
+/* PH_SIGNAL parameter */
+#define INFO0		0x1000
+#define INFO1		0x1100
+#define INFO2		0x1200
+#define INFO3_P8	0x1308
+#define INFO3_P10	0x130a
+#define INFO4_P8	0x1408
+#define INFO4_P10	0x140a
+#define D_RX_MON0	0x1800
+#define D_TX_MON0	0x1801
+#define D_RX_MON1	0x1810
+#define D_TX_MON1	0x1811
+#define LOSTFRAMING	0x1f00
+#define ANYSIGNAL	0x1f01
+
+/* PH_CONTROL parameter */
+#define HW_RESET	0x0001
+#define HW_POWERDOWN	0x0100
+#define HW_POWERUP	0x0101
+#define HW_DEACTIVATE	0x0200
+#define HW_ACTIVATE	0x0201
+#define HW_MOD_FRM	0x0400
+#define HW_MOD_FRH	0x0401
+#define HW_MOD_FTM	0x0402
+#define HW_MOD_FTH	0x0403
+#define HW_MOD_FTS	0x0404
+#define HW_MOD_CONNECT	0x0410
+#define HW_MOD_OK	0x0411
+#define HW_MOD_NOCARR	0x0412
+#define HW_MOD_FCERROR	0x0413
+#define HW_MOD_READY	0x0414
+#define HW_MOD_LASTDATA	0x0415
+#define HW_MOD_SILENCE	0x0416
+#define HW_FEATURES	0x04ff
+#define HW_HFC_COEFF	0x0500
+#define HW_LOS		0x0501
+#define HW_LOS_OFF	0x0502
+#define HW_AIS		0x0503
+#define HW_AIS_OFF	0x0504
+#define HW_SLIP_TX	0x0505
+#define HW_SLIP_RX	0x0506
+#define HW_PCM_CONN	0x0580
+#define HW_PCM_DISC	0x0581
+#define HW_CONF_JOIN	0x0582
+#define HW_CONF_SPLIT	0x0583
+#define HW_RECEIVE_OFF	0x0584
+#define HW_RECEIVE_ON	0x0585
+#define HW_SPL_LOOP_ON	0x0586
+#define HW_SPL_LOOP_OFF	0x0587
+#define HW_ECHOCAN_ON 	0x0588
+#define HW_ECHOCAN_OFF 	0x0589
+#define HW_TESTLOOP	0xFF00
+#define HW_FIRM_START	0xFF10
+#define HW_FIRM_DATA	0xFF11
+#define HW_FIRM_END	0xFF12
+#define HW_D_BLOCKED	0xFF20
+#define HW_D_NOBLOCKED	0xFF21
+#define HW_TESTRX_RAW	0xFF40
+#define HW_TESTRX_HDLC	0xFF41
+#define HW_TESTRX_OFF	0xFF4f
+/* TOUCH TONE IS 0x20XX  XX "0"..."9", "A","B","C","D","*","#" */
+#define DTMF_TONE_VAL	0x2000
+#define DTMF_TONE_MASK	0x007F
+#define DTMF_TONE_START	0x2100
+#define DTMF_TONE_STOP	0x2200
+#define CMX_CONF_JOIN	0x2300
+#define CMX_CONF_SPLIT	0x2301
+#define CMX_ECHO_ON	0x2302
+#define CMX_ECHO_OFF	0x2303
+#define CMX_RECEIVE_OFF	0x2304
+#define CMX_RECEIVE_ON	0x2305
+#define CMX_MIX_ON	0x2306
+#define CMX_MIX_OFF	0x2307
+#define TONE_PATT_ON	0x2310
+#define TONE_PATT_OFF	0x2311
+#define VOL_CHANGE_TX	0x2312
+#define VOL_CHANGE_RX	0x2313
+#define BF_ENABLE_KEY	0x2314
+#define BF_DISABLE	0x2315
+#define BF_ACCEPT	0x2316
+#define BF_REJECT	0x2317
+#define ECHOCAN_ON	0x2318
+#define ECHOCAN_OFF	0x2319
+#define HW_POTS_ON		0x1001
+#define HW_POTS_OFF		0x1002
+#define HW_POTS_SETMICVOL	0x1100
+#define HW_POTS_SETSPKVOL	0x1101
+#define HW_POTS_GETMICVOL	0x1110
+#define HW_POTS_GETSPKVOL	0x1111
+
+/* TONE_PATT_ON parameter */
+#define TONE_OFF			0x0000
+#define TONE_GERMAN_DIALTONE		0x0001
+#define TONE_GERMAN_OLDDIALTONE		0x0002
+#define TONE_AMERICAN_DIALTONE		0x0003
+#define TONE_GERMAN_DIALPBX		0x0004
+#define TONE_GERMAN_OLDDIALPBX		0x0005
+#define TONE_AMERICAN_DIALPBX		0x0006
+#define TONE_GERMAN_RINGING		0x0007
+#define TONE_GERMAN_OLDRINGING		0x0008
+#define TONE_AMERICAN_RINGPBX		0x000b
+#define TONE_GERMAN_RINGPBX		0x000c
+#define TONE_GERMAN_OLDRINGPBX		0x000d
+#define TONE_AMERICAN_RINGING		0x000e
+#define TONE_GERMAN_BUSY		0x000f
+#define TONE_GERMAN_OLDBUSY		0x0010
+#define TONE_AMERICAN_BUSY		0x0011
+#define TONE_GERMAN_HANGUP		0x0012
+#define TONE_GERMAN_OLDHANGUP		0x0013
+#define TONE_AMERICAN_HANGUP		0x0014
+#define TONE_SPECIAL_INFO		0x0015
+#define TONE_GERMAN_GASSENBESETZT	0x0016
+#define TONE_GERMAN_AUFSCHALTTON	0x0016
+
+#define GLOBALOPT_INTERNAL_CTRL		0x0001
+#define GLOBALOPT_EXTERNAL_EQUIPMENT	0x0002
+#define GLOBALOPT_HANDSET		0x0004
+#define GLOBALOPT_DTMF			0x0008
+#define GLOBALOPT_SUPPLEMENTARY_SERVICE	0x0010
+#define GLOBALOPT_CHANNEL_ALLOCATION	0x0020
+#define GLOBALOPT_PARAMETER_B_CHANNEL	0x0040
+#define GLOBALOPT_LINE_INTERCONNECT	0x0080
+
+
+/* layer 1 */
+#define PH_ACTIVATE	0x010100
+#define PH_DEACTIVATE	0x010000
+#define PH_DATA		0x110200
+#define MPH_DEACTIVATE	0x011000
+#define MPH_ACTIVATE	0x011100
+#define MPH_INFORMATION	0x012000
+
+/* layer 2 */
+#define DL_ESTABLISH	0x020100
+#define DL_RELEASE	0x020000
+#define DL_DATA		0x120200
+#define DL_UNITDATA	0x120300
+#define MDL_UNITDATA	0x121200
+#define MDL_ASSIGN	0x022100
+#define MDL_REMOVE	0x022000
+#define MDL_ERROR	0x023000
+#define MDL_INFORMATION	0x024000
+#define MDL_STATUS	0x028100
+#define MDL_FINDTEI	0x028200
+
+/* layer 3 */
+#define CC_ALERTING		0x030100
+#define CC_PROCEEDING		0x030200
+#define CC_PROGRESS		0x030300
+#define CC_SETUP		0x030500
+#define CC_CONNECT		0x030700
+#define CC_SETUP_ACKNOWLEDGE	0x030d00
+#define CC_CONNECT_ACKNOWLEDGE	0x030f00
+#define CC_USER_INFORMATION	0x032000
+#define CC_SUSPEND_REJECT	0x032100
+#define CC_RESUME_REJECT	0x032200
+#define CC_HOLD			0x032400
+#define CC_SUSPEND		0x032500
+#define CC_RESUME		0x032600
+#define CC_HOLD_ACKNOWLEDGE	0x032800
+#define CC_SUSPEND_ACKNOWLEDGE	0x032d00
+#define CC_RESUME_ACKNOWLEDGE	0x032e00
+#define CC_HOLD_REJECT		0x033000
+#define CC_RETRIEVE		0x033100
+#define CC_RETRIEVE_ACKNOWLEDGE	0x033300
+#define CC_RETRIEVE_REJECT	0x033700
+#define CC_DISCONNECT		0x034500
+#define CC_RESTART		0x034600
+#define CC_RELEASE		0x034d00
+#define CC_RELEASE_COMPLETE	0x035a00
+#define CC_FACILITY		0x036200
+#define CC_NOTIFY		0x036e00
+#define CC_STATUS_ENQUIRY	0x037500
+#define CC_INFORMATION		0x037b00
+#define CC_STATUS		0x037d00
+
+#define CC_NEW_CR		0x03f000
+#define CC_RELEASE_CR		0x03f100
+#define CC_TIMEOUT		0x03ff00
+
+#define CC_B3_DATA		0x138600
+
+#define CAPI_MESSAGE_REQUEST	0x040080
+
+#define LAYER_MASK	0x0F0000
+#define COMMAND_MASK	0x00FF00
+#define SUBCOMMAND_MASK	0x0000FF
+#define DATA_COMMAND	0x100000
+#define CMD_IS_DATA(p)	(p & DATA_COMMAND)
+
+/* short cuts layer 1 */
+#define PH_ACTIVATE_REQ		(PH_ACTIVATE | REQUEST)
+#define PH_ACTIVATE_IND		(PH_ACTIVATE | INDICATION)
+#define PH_DEACTIVATE_IND	(PH_DEACTIVATE | INDICATION)
+#define PH_DATA_REQ		(PH_DATA | REQUEST)
+#define PH_DATA_IND		(PH_DATA | INDICATION)
+#define PH_DATA_CNF		(PH_DATA | CONFIRM)
+#define PH_DATA_RSP		(PH_DATA | RESPONSE)
+#define MPH_ACTIVATE_REQ	(MPH_ACTIVATE | REQUEST)
+#define MPH_DEACTIVATE_REQ	(MPH_DEACTIVATE | REQUEST)
+#define MPH_INFORMATION_IND	(MPH_INFORMATION | INDICATION)
+
+/* short cuts layer 2 */
+#define DL_ESTABLISH_REQ	(DL_ESTABLISH | REQUEST)
+#define DL_ESTABLISH_IND	(DL_ESTABLISH | INDICATION)
+#define DL_ESTABLISH_CNF	(DL_ESTABLISH | CONFIRM)
+#define DL_RELEASE_REQ		(DL_RELEASE | REQUEST)
+#define DL_RELEASE_IND		(DL_RELEASE | INDICATION)
+#define DL_RELEASE_CNF		(DL_RELEASE | CONFIRM)
+#define DL_DATA_REQ		(DL_DATA | REQUEST)
+#define DL_DATA_IND		(DL_DATA | INDICATION)
+#define DL_UNITDATA_REQ		(DL_UNITDATA | REQUEST)
+#define DL_UNITDATA_IND		(DL_UNITDATA | INDICATION)
+#define MDL_ASSIGN_REQ		(MDL_ASSIGN | REQUEST)
+#define MDL_ASSIGN_IND		(MDL_ASSIGN | INDICATION)
+#define MDL_REMOVE_REQ		(MDL_REMOVE | REQUEST)
+#define MDL_ERROR_IND		(MDL_ERROR | INDICATION)
+#define MDL_ERROR_RSP		(MDL_ERROR | RESPONSE)
+#define MDL_INFORMATION_IND	(MDL_INFORMATION | INDICATION)
+
+/* protocol id */
+#define ISDN_PID_NONE			0
+#define ISDN_PID_ANY			0xffffffff
+#define ISDN_PID_L0_TE_S0		0x00000001
+#define ISDN_PID_L0_NT_S0		0x00000100
+#define ISDN_PID_L0_TE_U		0x00000002
+#define ISDN_PID_L0_NT_U		0x00000200
+#define ISDN_PID_L0_TE_UP2		0x00000004
+#define ISDN_PID_L0_NT_UP2		0x00000400
+#define ISDN_PID_L0_TE_E1		0x00000008
+#define ISDN_PID_L0_NT_E1		0x00000800
+#define ISDN_PID_L0_IP_S0		0x00000010
+#define ISDN_PID_L0_IP_E1		0x00000020
+#define ISDN_PID_L0_LOOP		0x00000030
+#define ISDN_PID_L1_TE_S0		0x01000001
+#define ISDN_PID_L1_NT_S0		0x01000100
+#define ISDN_PID_L1_TE_U		0x01000002
+#define ISDN_PID_L1_NT_U		0x01000200
+#define ISDN_PID_L1_TE_UP2		0x01000004
+#define ISDN_PID_L1_NT_UP2		0x01000400
+#define ISDN_PID_L1_TE_E1		0x01000008
+#define ISDN_PID_L1_NT_E1		0x01000800
+#define ISDN_PID_L2_LAPD		0x02000001
+#define ISDN_PID_L2_LAPD_NET		0x02000002
+/* Bit 15-0  reserved for CAPI defined protocols */
+#define ISDN_PID_L0_B_IP		0x40000001
+#define ISDN_PID_L1_B_64HDLC		0x41000001
+#define ISDN_PID_L1_B_64TRANS		0x41000002
+#define ISDN_PID_L1_B_V110_ASYNC	0x41000004
+#define ISDN_PID_L1_B_V110_HDLC		0x41000008
+#define ISDN_PID_L1_B_T30FAX		0x41000010
+#define ISDN_PID_L1_B_64HDLC_INV	0x41000020
+#define ISDN_PID_L1_B_56TRANS		0x41000040
+#define ISDN_PID_L1_B_MODEM_ALL		0x41000080
+#define ISDN_PID_L1_B_MODEM_ASYNC	0x41000100
+#define ISDN_PID_L1_B_MODEM_HDLC	0x41000200
+/* Bit 15-0  reserved for CAPI defined protocols */
+#define ISDN_PID_L2_B_X75SLP		0x42000001
+#define ISDN_PID_L2_B_TRANS		0x42000002
+#define ISDN_PID_L2_B_TRANSDTMF		0x42300002
+#define ISDN_PID_L2_B_RAWDEV		0x42400002
+#define ISDN_PID_L2_B_SDLC		0x42000004
+#define ISDN_PID_L2_B_LAPD		0x42000008
+#define ISDN_PID_L2_B_T30		0x42000010
+#define ISDN_PID_L2_B_PPP		0x42000020
+#define ISDN_PID_L2_B_TRANSNOERR	0x42000040
+#define ISDN_PID_L2_B_MODEM		0x42000080
+#define ISDN_PID_L2_B_X75SLPV42BIS	0x42000100
+#define ISDN_PID_L2_B_V120ASYNC		0x42000200
+#define ISDN_PID_L2_B_V120ASYNCV42BIS	0x42000400
+#define ISDN_PID_L2_B_V120TRANS		0x42000800
+#define ISDN_PID_L2_B_LAPDFREESAPI	0x42001000
+#define ISDN_PID_L3_B_TRANS		0x43000001
+#define ISDN_PID_L3_B_T90NL		0x43000002
+#define ISDN_PID_L3_B_X25DTE		0x43000004
+#define ISDN_PID_L3_B_X25DCE		0x43000008
+#define ISDN_PID_L3_B_T30		0x43000010
+#define ISDN_PID_L3_B_T30EXT		0x43000020
+#define ISDN_PID_L3_B_MODEM		0x43000080
+/* Bit 15-0  reserved for CAPI defined protocols */
+#define ISDN_PID_L3_B_DSP		0x43010000
+#define ISDN_PID_L3_DSS1USER		0x03000001
+#define ISDN_PID_L3_DSS1NET		0x03000100
+#define ISDN_PID_L4_CAPI20		0x04000001
+#define ISDN_PID_L4_B_CAPI20		0x44000001
+
+#define ISDN_PID_BCHANNEL_BIT		0x40000000
+#define ISDN_PID_LAYER_MASK		0x0f000000
+#define ISDN_PID_LAYER(n)		(n<<24)
+#define ISDN_PID_FEATURE_MASK		0x00F00000
+#define ISDN_PID_IDX_MAX		23
+
+#define ISDN_PID_L2_DF_PTP		0x00100000
+#define ISDN_PID_L2_DF_MULT_TEI		0x00200000
+#define	ISDN_PID_L3_DF_PTP		0x00100000
+#define ISDN_PID_L3_DF_EXTCID		0x00200000
+#define ISDN_PID_L3_DF_CRLEN2		0x00400000
+
+
+// short message status
+#define SSTATUS_ALL		0x0fffffff
+#define SSTATUS_BROADCAST_BIT	0x10000000
+#define SSTATUS_L1		0x01ffffff
+#define SSTATUS_L2		0x02ffffff
+#define SSTATUS_L1_DEACTIVATED	0x01000000
+#define SSTATUS_L1_ACTIVATED	0x01000001
+#define SSTATUS_L2_RELEASED	0x02000000
+#define SSTATUS_L2_ESTABLISHED	0x02000001
+
+
+#define mISDN_CORE_DEVICE	0
+#define mISDN_RAW_DEVICE	128
+
+#define FLG_mISDNPORT_BUSY	1
+#define FLG_mISDNPORT_ENABLED	2
+#define FLG_mISDNPORT_BLOCK	3
+#define FLG_mISDNPORT_OPEN	4
+#define FLG_mISDNPORT_ONEFRAME	5
+
+
+/*
+ * A "ENTITY" is a instance which assign id's with a none local
+ * scope. A id has a local part (a range of ids which the instance
+ * maintains) and the global ENTITY ID.
+ * A instance which wan't to assign IDs have to request a unique
+ * ENTITY ID with MGR_NEWENTITY | REQUEST.
+ * If the instance is deleted or don't need this feature anymore
+ * it has to delete the ENTITY with MGR_DELENTITY | REQUEST.
+ * ENTITY ID 0xFFFF is a special one.
+ * One example for using this is the L3/L4 process ID.
+ */
+
+#define MISDN_MAX_ENTITY	2048
+#define MISDN_ENTITY_NONE	0x0000ffff
+#define MISDN_ID_ENTITYMASK	0xffff0000
+#define MISDN_ID_LOCALMASK	0x0000FFFF
+#define MISDN_ID_ANY		0xffffffff
+#define MISDN_ID_NONE		0xfffffffe
+#define MISDN_ID_DUMMY		0xffff0001
+#define MISDN_ID_GLOBAL		0xffff0002
+
+#define MAX_LAYER_NR		7
+#define ISDN_LAYER(n)		(1<<n)
+#define LAYER_OUTRANGE(layer)	((layer<0) || (layer>MAX_LAYER_NR))
+
+/* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */
+#define mISDN_MAX_IDLEN		20
+
+#ifdef OBSOLETE
+#define IF_NOACTIV	0x00000000
+#define IF_DOWN		0x01000000
+#define IF_UP		0x02000000
+#define IF_CHAIN	0x04000000
+#define IF_HANDSHAKE	0x08000000
+#define IF_TYPEMASK	0x07000000
+#define IF_ADDRMASK	0xF0FFFFFF
+#define IF_IADDRMASK	0xF0FFFFFF
+#define IF_CONTRMASK	0x000000FF
+#define IF_CHILDMASK	0x1000FF00
+#define IF_CLONEMASK	0x2000FF00
+#define IF_INSTMASK	0x400F0000
+#define IF_LAYERMASK	0x00F00000
+#define IF_TYPE(i)	((i)->stat & IF_TYPEMASK)
+#endif
+
+/*
+ * general ID layout for instance and stack id's
+ * 3322 2222 2222 1111 1111 1100 0000 0000
+ * 1098 7654 3210 9876 5432 1098 7654 3210
+ * FFFF FFFF CCCC CCCC SSSS SSSS RRRR LLLL
+ *
+ * L (bit 03-00) Layer ID
+ * R (bit 06-04) reserved (0)
+ * U (bit 07)    user device id
+ * S (bit 15-08) Stack ID/controller number
+ * C (bit 23-16) Child/Clone ID
+ * F (bit 31-24) Flags as defined below
+ *
+ */
+
+#define FLG_MSG_DOWN	0x01000000
+#define FLG_MSG_UP	0x02000000
+#define FLG_MSG_TARGET	0x04000000
+#define FLG_MSG_CLONED	0x08000000
+#define FLG_CHILD_STACK	0x10000000
+#define FLG_CLONE_STACK	0x20000000
+#define FLG_INSTANCE	0x40000000
+#define FLG_MSG_TAGGED	0x80000000
+#define MSG_DIR_MASK	0x03000000
+#define MSG_BROADCAST	0x03000000
+#define MSG_TO_OWNER	0x00000000
+
+#define CHILD_ID_INC	0x00010000
+#define CHILD_ID_MAX	0x10FF0000
+#define CHILD_ID_MASK	0x00FF0000
+#define CLONE_ID_INC	0x00010000
+#define CLONE_ID_MAX	0x20FF0000
+#define CLONE_ID_MASK	0x00FF0000
+#define STACK_ID_INC	0x00000100
+#define STACK_ID_MAX	0x00007F00
+#define STACK_ID_MASK	0x30FFFF00
+#define MASTER_ID_MASK	0x0000FF00
+#define LAYER_ID_INC	0x00000001
+#define LAYER_ID_MAX	MAX_LAYER_NR
+#define LAYER_ID_MASK	0x0000000F
+#define FLG_ID_USER	0x00000080
+#define INST_ID_MASK	0x70FFFFFF
+
+#define DUMMY_CR_FLAG	0x7FFFFF00
+// #define CONTROLER_MASK	0x0000FF
+
+/* stack channel values */
+#define CHANNEL_NUMBER	0x000000FF
+#define CHANNEL_RXSLOT	0x0000FF00
+#define CHANNEL_TXSLOT	0x00FF0000
+#define CHANNEL_EXTINFO	0xFF000000
+#define CHANNEL_NR_D	0x00000000
+#define CHANNEL_NR_B1	0x00000001
+#define CHANNEL_NR_B2	0x00000002
+#define CHANNEL_EXT_PCM	0x01000000
+#define CHANNEL_EXT_REV	0x02000000
+
+/* instance/stack extentions */
+#define EXT_STACK_CLONE 0x00000001
+#define EXT_INST_CLONE	0x00000100
+#define EXT_INST_MGR	0x00000200
+#define EXT_INST_MIDDLE	0x00000400
+#define EXT_INST_UNUSED 0x00000800
+//#define EXT_IF_CHAIN	0x00010000
+//#define EXT_IF_EXCLUSIV	0x00020000
+//#define EXT_IF_CREATE	0x00040000
+//#define EXT_IF_SPLIT	0x00080000
+
+/* stack status flag */
+#define mISDN_STACK_ACTION_MASK		0x0000ffff
+#define mISDN_STACK_COMMAND_MASK	0x000f0000
+#define mISDN_STACK_STATUS_MASK		0xfff00000
+/* action bits 0-15 */
+#define mISDN_STACK_WORK	0
+#define mISDN_STACK_SETUP	1
+#define mISDN_STACK_CLEARING	2
+#define mISDN_STACK_RESTART	3
+#define mISDN_STACK_WAKEUP	4
+#define mISDN_STACK_ABORT	15
+/* status bits 16-31 */
+#define mISDN_STACK_STOPPED	16
+#define mISDN_STACK_INIT	17
+#define mISDN_STACK_THREADSTART	18
+#define mISDN_STACK_DELETED	28
+#define mISDN_STACK_ACTIVE	29
+#define mISDN_STACK_RUNNING	30
+#define mISDN_STACK_KILLED	31
+
+/* special packet type */
+#define PACKET_NOACK	250
+
+/* limits for buffers */
+
+#define MAX_PHONE_DIGIT		31
+#define MAX_DFRAME_LEN		260
+#define MAX_DATA_SIZE		2048
+#define MAX_DATA_MEM		2080
+#define MAX_HEADER_LEN		4
+#define	DEFAULT_PORT_QUEUELEN	256
+#define PORT_SKB_RESERVE	L3_EXTRA_SIZE
+#define PORT_SKB_MINIMUM	128
+
+/* structure for information exchange between layer/entity boundaries */
+
+#define STATUS_INFO_L1	1
+#define STATUS_INFO_L2	2
+
+typedef struct _mISDN_head {
+	u_int	addr;
+	u_int	prim;
+	int	dinfo;
+	int	len;
+}  __attribute__((packed)) mISDN_head_t;
+
+#define mISDN_HEADER_LEN	sizeof(mISDN_head_t)
+
+typedef struct _status_info {
+	int	len;
+	int	typ;
+	u_char	info[120];
+} status_info_t;
+
+typedef struct _logdata {
+	char    *head;
+	char	*fmt;
+	va_list args;
+} logdata_t;
+
+typedef struct _moditem {
+	char	*name;
+	int	protocol;
+} moditem_t;
+
+typedef struct _mISDN_pid {
+	int	protocol[MAX_LAYER_NR +1];
+	int	layermask;
+	int	maxplen;
+	/* 0 is defined as no prameter, all other values are offsets into pbuf
+	 * so pbuf[0] is always unused */
+	u16	param[MAX_LAYER_NR +1];
+	u16	global;
+	u16	pidx;
+	u_int modparm_protocol;
+	u_char	*pbuf;
+} mISDN_pid_t;
+
+typedef struct _mISDN_stPara {
+	int	maxdatalen;
+	int	up_headerlen;
+	int	down_headerlen;
+} mISDN_stPara_t;
+
+typedef struct _stack_info {
+	u_int		id;
+	mISDN_pid_t	pid;
+	mISDN_stPara_t	para;
+	u_int		extentions;
+	u_int		mgr;
+	u_int		master;
+	u_int		clone;
+	int		instcnt;
+	int		inst[MAX_LAYER_NR +1];
+	int		childcnt;
+	u_int		child[2]; /* this is correct handled for PRI see get_stack_info() */
+} stack_info_t;
+
+typedef struct _layer_info {
+	char		name[mISDN_MAX_IDLEN];
+	int		object_id;
+	int		extentions;
+	u_int		id;
+	u_int		st;
+	u_int		clone;
+	u_int		parent;
+	mISDN_pid_t	pid;
+} layer_info_t;
+
+#ifdef OBSOLETE
+typedef struct _interface_info {
+	int		extentions;
+	u_int		owner;
+	u_int		peer;
+	int		stat;
+} interface_info_t;
+#endif
+
+typedef struct _channel_info {
+	u_int		channel;
+	union {
+		u_int	id;
+		void	*p;
+	} st;
+} channel_info_t;
+
+/* l3 pointer arrays */
+
+typedef struct _ie_info {
+	u16	off	: 10,
+		ridx	: 3,
+		res1	: 1,
+		cs_flg	: 1,
+		repeated: 1;
+} __attribute__((packed)) ie_info_t;
+
+typedef struct _ie_val {
+	u16	codeset	: 3,
+		res1	: 5,
+		val	: 8;
+} __attribute__((packed)) ie_val_t;;
+
+typedef struct _cs_info {
+	u16	codeset	: 3,
+		locked	: 1,
+		res1	: 2,
+		len	: 10;
+} __attribute__((packed)) cs_info_t;
+
+typedef struct _ie_info_ext {
+	ie_info_t	ie;
+	union {
+		ie_val_t	v;
+		cs_info_t	cs;
+	};
+} __attribute__((packed)) ie_info_ext_t;
+
+typedef struct _Q931_info {
+	u_char		type;
+	u_char		crlen;
+	u16		cr;
+	ie_info_t	bearer_capability;
+	ie_info_t	cause;
+	ie_info_t	call_id;
+	ie_info_t	call_state;
+	ie_info_t	channel_id;
+	ie_info_t	facility;
+	ie_info_t	progress;
+	ie_info_t	net_fac;
+	ie_info_t	notify;
+	ie_info_t	display;
+	ie_info_t	date;
+	ie_info_t	keypad;
+	ie_info_t	signal;
+	ie_info_t	info_rate;
+	ie_info_t	end2end_transit;
+	ie_info_t	transit_delay_sel;
+	ie_info_t	pktl_bin_para;
+	ie_info_t	pktl_window;
+	ie_info_t	pkt_size;
+	ie_info_t	closed_userg;
+	ie_info_t	connected_nr;
+	ie_info_t	connected_sub;
+	ie_info_t	calling_nr;
+	ie_info_t	calling_sub;
+	ie_info_t	called_nr;
+	ie_info_t	called_sub;
+	ie_info_t	redirect_nr;
+	ie_info_t	redirect_dn;
+	ie_info_t	transit_net_sel;
+	ie_info_t	restart_ind;
+	ie_info_t	llc;
+	ie_info_t	hlc;
+	ie_info_t	useruser;
+	ie_info_t	more_data;
+	ie_info_t	sending_complete;
+	ie_info_t	congestion_level;
+	ie_info_t	comprehension_required;
+	ie_info_ext_t	ext[8];
+}  __attribute__((packed)) Q931_info_t;
+
+#define L3_EXTRA_SIZE	sizeof(Q931_info_t)
+
+#ifdef __KERNEL__
+#include <linux/isdn_compat.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+typedef struct _mISDNobject	mISDNobject_t;
+typedef struct _mISDNinstance	mISDNinstance_t;
+typedef struct _mISDNstack	mISDNstack_t;
+typedef struct _mISDNport	mISDNport_t;
+typedef struct _mISDNdevice	mISDNdevice_t;
+typedef int	(ctrl_func_t)(void *, u_int, void *);
+typedef int	(if_func_t)(mISDNinstance_t *, struct sk_buff *);
+
+#define mISDN_HEAD_P(s)		((mISDN_head_t *)&s->cb[0])
+#define mISDN_HEAD_PRIM(s)	((mISDN_head_t *)&s->cb[0])->prim
+#define mISDN_HEAD_DINFO(s)	((mISDN_head_t *)&s->cb[0])->dinfo
+
+typedef struct _mISDN_headext {
+	u_int	addr;
+	u_int	prim;
+	int	dinfo;
+	void	*data[3];
+	union {
+		ctrl_func_t	*ctrl;
+		if_func_t	*iff;
+		void		*func;
+	} func;
+}  __attribute__((packed)) mISDN_headext_t;
+
+#define mISDN_HEADEXT_P(s) ((mISDN_headext_t *)&s->cb[0])
+
+/* Basic struct of a mISDN component */
+struct _mISDNobject {
+	struct list_head	list;
+	char			*name;
+	u_int			id;
+	int			refcnt;
+	mISDN_pid_t		DPROTO;
+	mISDN_pid_t		BPROTO;
+	ctrl_func_t		*own_ctrl;
+	struct list_head	ilist;
+	spinlock_t		lock;
+	struct module		*owner;
+	struct class_device	class_dev;
+};
+
+#ifdef OBSOLETE
+/* the interface between two mISDNinstances */
+struct _mISDNif {
+	if_func_t		*func;
+	void			*fdata;
+	mISDNif_t		*clone;
+	mISDNif_t		*predecessor;
+	int			extentions;
+	int			stat;
+	mISDNstack_t		*st;
+	mISDNinstance_t		*owner;
+	mISDNinstance_t		*peer;
+};
+#endif
+
+/* a instance of a mISDNobject */
+struct _mISDNinstance {
+	struct list_head	list;
+	char			name[mISDN_MAX_IDLEN];
+	int			extentions;
+	u_int			id;
+	int			regcnt;
+	mISDN_pid_t		pid;
+	mISDNstack_t		*st;
+	mISDNobject_t		*obj;
+	void			*privat;
+	mISDNinstance_t		*clone;
+	mISDNinstance_t		*parent;
+	if_func_t		*function;
+	spinlock_t		*hwlock;
+	struct class_device	class_dev;
+};
+
+#ifdef OBSOLETE
+/* a list of parallel (horizontal) mISDNinstances in the same layer
+ * normally here is only one instance per layer only if the information
+ * will be splitted here are more instances */
+struct _mISDNlayer {
+	struct list_head	list;
+	mISDNinstance_t		*inst;
+};
+#endif
+/* the STACK; a (vertical) chain of layers */
+ 
+struct _mISDNstack {
+	struct list_head	list;
+	u_int			id;
+	u_int			extentions;
+	mISDN_pid_t		pid;
+	mISDN_stPara_t		para;
+	u_long			status;
+	struct task_struct	*thread;
+	struct semaphore	*notify;
+	wait_queue_head_t	workq;
+	struct sk_buff_head	msgq;
+#ifdef MISDN_MSG_STATS
+	u_int			msg_cnt;
+	u_int			sleep_cnt;
+	u_int			clone_cnt;
+	u_int			stopped_cnt;
+#endif
+	mISDNinstance_t		*i_array[MAX_LAYER_NR + 1];
+	struct list_head	prereg;
+	mISDNinstance_t		*mgr;
+	mISDNstack_t		*master;
+	mISDNstack_t		*clone;
+	mISDNstack_t		*parent;
+	struct list_head	childlist;
+	struct class_device	class_dev;
+	/* temporary use */
+	mISDN_pid_t		new_pid;
+};
+
+/* lowlevel read/write struct for the mISDNdevice */
+struct _mISDNport {
+	wait_queue_head_t	procq;
+	spinlock_t		lock;
+//	mISDNif_t		pif;
+	u_long			Flag;
+	struct sk_buff_head	queue;
+	u_int			maxqlen;
+};
+
+/* the user interface to handle /dev/mISDN */
+struct _mISDNdevice {
+	struct list_head	list;
+	int			minor;
+	struct semaphore	io_sema;
+	int			open_mode;
+	mISDNport_t		rport;
+	mISDNport_t		wport;
+	struct list_head	layerlist;
+	struct list_head	stacklist;
+	struct list_head	timerlist;
+	struct list_head	entitylist;
+};
+
+/* common helper functions */
+extern int	mISDN_bprotocol2pid(void *, mISDN_pid_t *);
+// extern int	mISDN_SetIF(mISDNinstance_t *, mISDNif_t *, u_int, void *, void *, void *);
+// extern int	mISDN_ConnectIF(mISDNinstance_t *, mISDNinstance_t *);
+// extern int	mISDN_DisConnectIF(mISDNinstance_t *, mISDNif_t *);
+extern int	mISDN_queue_message(mISDNinstance_t *, u_int, struct sk_buff *);
+
+
+/* global register/unregister functions */
+
+extern int	mISDN_register(mISDNobject_t *obj);
+extern int	mISDN_unregister(mISDNobject_t *obj);
+extern int	mISDN_ctrl(void *, u_int, void *);
+
+#endif /* __KERNEL__ */
+#endif /* mISDNIF_H */

Added: misdn-kernel/trunk/km_mISDN.spec
===================================================================
--- misdn-kernel/trunk/km_mISDN.spec	                        (rev 0)
+++ misdn-kernel/trunk/km_mISDN.spec	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,60 @@
+Vendor:       SuSE GmbH, Nuernberg, Germany
+Distribution: SuSE Linux 8.2 (i386)
+Name:         km_mISDN
+Release:      14
+Packager:     feedback at suse.de
+
+Copyright:    Karsten Keil GPL
+Group:        unsorted
+Autoreqprov:  on
+Version:      1.0
+Summary:      modular ISDN driver architecture
+Source:       mISDN-%{version}-%{release}.tar.bz2
+#Patch:       isdn4k-utils.dif
+Buildroot:    /var/tmp/mISDN.build
+
+%description
+This package provides the mISDN sourcecode for kernelmodules
+Attention!!! These modules are BETA code and experimental, they may be
+crash your machine. Here is no support from SuSE for it.
+
+Authors:
+--------
+	Karsten Keil
+
+SuSE series: unsorted
+
+%prep
+%setup -n mISDN
+#%patch
+
+%build
+mv Makefile.standalone Makefile
+
+%install
+rm -f -r $RPM_BUILD_ROOT
+DESTDIR=$RPM_BUILD_ROOT/usr/src/kernel-modules/mISDN
+mkdir -p $DESTDIR
+install -p Makefile* $DESTDIR
+install -p Rules.make.ext $DESTDIR
+install -p add.config $DESTDIR
+mkdir -p $DESTDIR/newinclude/linux
+install -p include/linux/*.h $DESTDIR/newinclude/linux
+mkdir -p $DESTDIR/drivers/isdn/hardware/mISDN
+install -p drivers/isdn/hardware/mISDN/Makefile $DESTDIR/drivers/isdn/hardware/mISDN
+install -p drivers/isdn/hardware/mISDN/*.[ch] $DESTDIR/drivers/isdn/hardware/mISDN
+install -p drivers/isdn/hardware/mISDN/Rules.mISDN.v2.4 $DESTDIR/drivers/isdn/hardware/mISDN/Rules.mISDN
+
+#
+%{?suse_check}
+
+%clean
+
+%files
+%dir %attr (-,root,root) /usr/src/kernel-modules/mISDN
+%attr (-,root,root) /usr/src/kernel-modules/mISDN/*
+
+%changelog -n km_mISDN
+
+* Tue Jul 01 2003 - kkeil at suse.de
+  - first version

Added: misdn-kernel/trunk/mISDN.modprobe.d
===================================================================
--- misdn-kernel/trunk/mISDN.modprobe.d	                        (rev 0)
+++ misdn-kernel/trunk/mISDN.modprobe.d	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,25 @@
+
+install hfcmulti /usr/sbin/misdn-init start hfcmulti
+remove  hfcmulti /usr/sbin/misdn-init stop 
+
+install hfcpci /usr/sbin/misdn-init start hfcpci
+remove  hfcpci /usr/sbin/misdn-init stop 
+
+install hfcsusb /usr/sbin/misdn-init start hfcsusb
+remove  hfcsusb /usr/sbin/misdn-init stop 
+
+install hfcsmini /usr/sbin/misdn-init start hfcsmini
+remove  hfcsmini /usr/sbin/misdn-init stop 
+
+install xhfc /usr/sbin/misdn-init start xhfc
+remove  xhfc /usr/sbin/misdn-init stop 
+
+install avmfritz /usr/sbin/misdn-init start avmfritz
+remove  avmfritz /usr/sbin/misdn-init stop 
+
+install w6692pci /usr/sbin/misdn-init start w6692pci
+remove  w6692pci /usr/sbin/misdn-init stop 
+
+install sedlfax /usr/sbin/misdn-init start sedlfax
+remove  sedlfax /usr/sbin/misdn-init stop 
+

Added: misdn-kernel/trunk/misdn-init
===================================================================
--- misdn-kernel/trunk/misdn-init	                        (rev 0)
+++ misdn-kernel/trunk/misdn-init	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,780 @@
+#!/bin/bash
+
+################################################################################
+#
+# misdn-init init script
+#
+# Copyright (C) 2005, Nadi Sarrar
+#
+# Nadi Sarrar <nadi at beronet.com>
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License
+#
+
+#
+# USAGE:
+#
+#   /usr/sbin/misdn-init start|stop|restart|config|scan|help
+#
+
+# chkconfig: 2345 35 60
+# description: mISDN Kernel Modules
+
+#
+# CONFIGURATION:
+#
+# Path to your misdn-init.conf:
+#
+misdn_init_conf="/etc/misdn-init.conf"
+#
+################################################################################
+
+#
+# change this to modify the user/group settings of /dev/mISDN
+#
+USER=asterisk
+GROUP=asterisk
+
+# HFC 8/4 (S0) Options
+master_clock=17
+
+# HFC-E1 Options
+optical=17
+los=19
+ais=20
+slip=21
+nocrc4=24
+
+# Card Settings
+ulaw=9
+dtmf=10
+pcm_slave=12
+ignore_pcm_frameclock=13
+
+rxclock=14
+crystalclock=19
+
+watchdog=20
+
+
+#dsp defaults
+dsp_options=0
+
+poll_option=
+
+dsp_poll_option=
+
+dtmfthreshold_option=
+
+function check_cmd {
+	if ! which "${1}" > /dev/null; then
+		if [ "$(id -u)" != "0" ]; then
+			echo "[!!] FATAL: $1 not in path, please install and/or be root."
+		else
+			echo "[!!] FATAL: $1 not in path, please install."
+		fi
+		if [ "${2}" != "notfatal" ] ; then
+			exit 1
+		fi
+	else
+		var=$(echo ${1} | tr a-z A-Z)
+		eval "$var=`which ${1}`"
+	fi
+}
+
+check_cmd modprobe
+check_cmd rmmod
+check_cmd insmod
+check_cmd lspci
+check_cmd lsusb notfatal
+check_cmd mknod
+check_cmd bc
+check_cmd cut
+check_cmd wc
+check_cmd seq
+check_cmd sed
+
+function check_asterisk {
+	if ps ax | grep -v grep | grep asterisk > /dev/null ; then asterisk -rx "stop now" ; fi
+}
+
+function create_card_db
+{
+	cardline=""
+	cardcount=1
+	skipnext=0
+
+	IFS=$'\n'
+	NL="
+"
+	function addcard {
+		cardline="${cardline}${cardcount},${1}${NL}"
+		let "cardcount = ${cardcount} + 1"
+	}
+
+	function addport {
+		let "portcount = ${portcount} + ${1}"
+	}
+
+	for line in $(${LSPCI} -n -d 0xd161:b410); do
+		addcard "4,0x4"
+	done
+
+	for line in $(${LSPCI} -n | ${SED} -n 's/^\(0000:\|\)\([0-9a-f]\{2\}:[0-9a-f]\{2\}.[0-9a-f]\{1\}\)\( Class \| \)[0-9a-f]\{4\}: 1397:\([0-9a-f]\{4\}\).*$/\4 \2/p'); do
+		if [ ${skipnext} -eq 1 ]; then
+			skipnext=0
+			continue
+		fi
+		case "${line}" in
+			30b1*)
+				case "${line:5}" in
+					00*)
+						addcard "1,0x1"
+						;;
+					*)
+						if [ $(${LSPCI} -n -s ${line:5:3} -d 0x1397:30b1 | ${WC} -l) -eq 2 ]; then
+							addcard "2,2E1"
+							skipnext=1
+						else
+							addcard "1,0x1"
+						fi
+						;;
+				esac
+				;;
+			16b8*)
+				addcard "8,0x8"
+				;;
+			08b4*)
+
+				if ${LSPCI} -n -v -s "${line:5}" | grep "Subsystem" | grep "1397:b567" > /dev/null ; then
+					addcard "1,0x4"
+				elif ${LSPCI} -n -v -s "${line:5}" | grep "Subsystem" | grep "1397:b566\|1397:b569" > /dev/null ; then
+					addcard "2,0x4"
+				else
+					addcard "4,0x4"
+				fi
+				;;
+		esac
+	done
+	for line in $(${LSPCI} -n | grep "1397:\(2bd\(0\|6\|7\|8\|9\|a\|b\|c\)\|b100\)\|1043:0675\|0871:ffa\(1\|2\)\|1051:0100\|15b0:2bd0\|114f:007\(0\|1\|2\|3\)\|13d1:2bd1\|182d:3069"); do
+		addcard "1,hfcpci"
+	done
+	for line in $(${LSPCI} -n | grep "1244:\(0a00\|0e00\)"); do
+		addcard "1,avmfritz"
+	done
+	for line in $(${LSPCI} -n -d 1050:6692); do
+		addcard "1,w6692pci"
+	done
+	
+	if [ -e ${LSUSB} ]; then 
+		for line in $(${LSUSB} | grep "0959:2bd0\|0675:1688\|07b0:0006\|0742:200\(7\|8\|9\|A\)\|08e3:0301\|07fa:084\(7\|8\)\|07ba:0006"); do
+			addcard "1,hfcsusb"
+		done
+	fi
+
+	echo "${cardline}"
+}
+
+function expand
+{
+	local IFS=$','
+	for tok in $1; do
+		if [ "$(echo $tok | ${SED} -ne 's/\([0-9]*\)-\([0-9]*\)/\1 \2/p')" != "" ]; then
+			${SEQ} $(echo $tok | ${SED} -ne 's/\([0-9]*\)-[0-9]*/\1/p') $(echo $tok | ${SED} -ne 's/[0-9]*-\([0-9]*\)/\1/p')
+		else
+			echo $tok
+		fi
+	done
+}
+
+function load_card_modules {
+
+	carddb=$(create_card_db)
+
+	function find_carddb_line {
+		i=1
+		for l in ${carddb} ; do
+			if [ $i -eq $1 ] ; then 
+				echo $l
+				return
+			fi
+			let "i=$i+1"
+		done
+	}
+
+	if [ ! -z "$1" ] ; then
+		echo "Loading only $1"
+	fi
+
+	IFS=$'\n'
+	skipnr=0
+
+	for line in $(${SED} -n -e '/^[^#]/p' ${misdn_init_conf});
+	do
+		var=$(echo "${line}" | ${CUT} -d "=" -f1)
+		val=$(echo "${line}" | ${CUT} -d "=" -f2)
+		
+		case "${var}" in
+			card)
+				#echo "processing line: $val" 
+				nr=$(echo "${val}" | ${CUT} -d "," -f1)
+				mod=$(echo "${val}" | ${CUT} -d "," -f2)
+				opns=$(echo "${val}" | ${CUT} -d "," -f3-)
+
+				#getting portcount from carddb
+				ports=$(find_carddb_line $nr | ${CUT} -d "," -f2)
+				let "nr = ${nr} + ${skipnr}"
+				#echo "nr $nr ports $ports mod $mod opns: $opns"
+
+				case "${mod}" in
+					2E1)
+						hfcmulti[${nr}]=1
+						hfcmulti[$((${nr} + 1))]=1
+						let "hfcports = ${hfcports} + ${ports}"
+						IFS=$','
+						for li in ${opns}; do
+							hfcmulti[${nr}]=$(echo "obase=10;2^(${!li}-1)+${hfcmulti[${nr}]}" | ${BC})
+							if [ "${li}" != "pcm_slave" ]; then
+								hfcmulti[$((${nr} + 1))]=$(echo "obase=10;2^(${!li}-1)+${hfcmulti[$((${nr}+1))]}" | ${BC})
+							fi
+						done
+						IFS=$'\n'
+						hfcmulti[$((${nr} + 1))]=$(echo "obase=10;2^(${pcm_slave}-1)+${hfcmulti[$((${nr}+1))]}" | ${BC})
+						let "skipnr = ${skipnr} + 1"
+						;;
+					0x*)
+						hfcmulti[${nr}]=$(echo ${mod} | ${SED} -e "s/^0x\([0-9]*\)/\1/")
+						let "hfcports = ${hfcports} + ${ports}"
+						IFS=$','
+						for li in ${opns}; do
+							hfcmulti[${nr}]=$(echo "obase=10;2^(${!li}-1)+${hfcmulti[${nr}]}" | ${BC})
+						done
+						IFS=$'\n'
+						;;
+					*)
+						other_card[${nr}]=${mod}
+						;;
+				esac
+				;;
+			te_ptp)
+				for li in $(expand "${val}"); do
+					layermask[${li}]="0xf"
+					protocol[${li}]=34 # 0x22 == 34
+				done
+				;;
+			te_ptmp)
+				for li in $(expand "${val}"); do
+					layermask[${li}]="0xf"
+					protocol[${li}]=2 # 0x2 == 2
+				done
+				;;
+			nt_*)
+				for li in $(expand "${val}"); do
+					layermask[${li}]="0x3"
+					protocol[${li}]=18 # 0x12 == 18
+				done
+				;;
+			te_capi_ptp)
+				for li in $(expand "${val}"); do
+					layermask[${li}]="0x0"
+					protocol[${li}]=34 # 0x22 == 34
+				done
+
+				export addcapi=1
+				;;
+			te_capi_ptmp)
+				for li in $(expand "${val}"); do
+					layermask[${li}]="0x0"
+					protocol[${li}]=2 # 0x2 == 2
+				done
+
+				export addcapi=1
+				;;
+
+			option)
+				port=`echo "${val}" | ${SED} -e "s/^\([0-9]*\),.*/\1/"`
+				opt=`echo "${val}" | ${SED} -e "s/^[0-9]*,\(.*\)/\1/"`
+
+				if [ -z ${protocol[${port}]} ]; then
+					protocol[${port}]="0"
+				fi
+				
+				IFS=$','
+				for li in ${opt}; do
+					protocol[${port}]=$(echo "obase=10;2^(${!li}-1)+${protocol[${port}]}" | ${BC})
+				done
+				IFS=$'\n'
+				;;
+			poll)
+				poll=${val}
+				poll_option=poll=${val}
+				;;
+			dsp_poll)
+				dsp_poll_option=poll=${val}
+				;;
+			pcm)
+				pcm=${val}
+				;;
+			dsp_options)
+				export dsp_options=${val}
+				;;
+			dtmfthreshold)
+				export dtmfthreshold_option="dtmfthreshold=${val}"
+				;;
+			debug)
+				debug=${val}
+				;;
+			timer)
+				timer=${val}
+				;;
+			*)
+				echo "unknown variable: ${var}"
+				;;
+		esac
+		
+	done
+
+	echo "-----------------------------------------"
+	echo " Loading module(s) for your misdn-cards:"
+	echo "-----------------------------------------"
+
+	card_index=1
+	port_index=1
+	while [ ! -z ${hfcmulti[${card_index}]} ] || [ ! -z ${other_card[${card_index}]} ];
+	do
+		if [ ! -z ${hfcmulti[${card_index}]} ]; then
+	# MODPROBE COMMAND FOR hfcmulti CARD
+			hfcmulti_type="type="
+			hfcmulti_prot="protocol="
+			hfcmulti_layer="layermask="
+			while [ ! -z ${hfcmulti[${card_index}]} ];
+			do
+				hfcmulti_type="${hfcmulti_type}$(echo "obase=16;\"0x\";${hfcmulti[${card_index}]}" | ${BC} ),"
+				let "card_index = ${card_index} + 1"
+			done
+			while [ ${hfcports} -gt 0 ];
+			do
+				if [ ! -z ${protocol[${port_index}]} ]; then
+					hfcmulti_prot="${hfcmulti_prot}$(echo "obase=16;\"0x\";${protocol[${port_index}]}" | ${BC}),"
+				else
+					hfcmulti_prot="${hfcmulti_prot}0x2,"
+				fi
+				if [ ! -z ${layermask[${port_index}]} ]; then
+					hfcmulti_layer="${hfcmulti_layer}${layermask[${port_index}]},"
+				else
+					hfcmulti_layer="${hfcmulti_layer}0xf,"
+				fi
+				let "port_index = ${port_index} + 1"
+				let "hfcports = ${hfcports} - 1"
+			done
+			hfcmulti_type="$(echo ${hfcmulti_type} | ${SED} -e 's/^\(.*\),$/\1/')"
+			hfcmulti_prot="$(echo ${hfcmulti_prot} | ${SED} -e 's/^\(.*\),$/\1/')"
+			hfcmulti_layer="$(echo ${hfcmulti_layer} | ${SED} -e 's/^\(.*\),$/\1/')"
+			hfcmulti_cmd="${MODPROBE} --ignore-install hfcmulti ${hfcmulti_type} ${hfcmulti_prot} ${hfcmulti_layer}"
+			if [ ! -z ${poll} ]; then
+				hfcmulti_cmd="${hfcmulti_cmd} poll=${poll}"
+			fi
+			if [ ! -z ${pcm} ]; then
+				hfcmulti_cmd="${hfcmulti_cmd} pcm=${pcm}"
+			fi
+			if [ ! -z ${debug} ]; then
+				hfcmulti_cmd="${hfcmulti_cmd} debug=${debug}"
+			fi
+
+			if [ ! -z ${timer} ]; then
+				hfcmulti_cmd="${hfcmulti_cmd} timer=${timer}"
+			fi
+
+			if [ -z "$1" ] ; then
+				echo ${hfcmulti_cmd}
+				eval ${hfcmulti_cmd}
+			else
+				if [ "$1" = "hfcmulti" ] ; then 
+					echo ${hfcmulti_cmd}
+					eval ${hfcmulti_cmd}
+				fi
+			fi
+		else
+	# MODPROBE COMMAND FOR _NON_ hfcmulti CARD
+			other_mod="${other_card[${card_index}]}"
+			other_cmd="${MODPROBE} --ignore-install ${other_mod}"
+			if [ ! -z ${protocol[${port_index}]} ]; then
+				other_prot="protocol=$(echo "obase=16;\"0x\";${protocol[${port_index}]}" | ${BC}),"
+			else
+				other_prot="protocol=0x2,"
+			fi
+			if [ ! -z ${layermask[${port_index}]} ]; then
+				other_layer="layermask=${layermask[${port_index}]},"
+			else
+				other_layer="layermask=0xf,"
+			fi
+			other_extra=""
+			modinfo $other_mod | egrep -q 'parm: *poll' && other_extra="$other_extra ${poll_option}"
+
+			let "prev = ${card_index}"
+			let "card_index = ${card_index} + 1"
+			let "port_index = ${port_index} + 1"
+			while [ "${other_card[${card_index}]}" == "${other_card[${prev}]}" ];
+			do
+				if [ ! -z ${protocol[${port_index}]} ]; then
+					other_prot="${other_prot}$(echo "obase=16;\"0x\";${protocol[${port_index}]}" | ${BC}),"
+				else
+					other_prot="${other_prot}0x2,"
+				fi
+				if [ ! -z ${layermask[${port_index}]} ]; then
+					other_layer="${other_layer}${layermask[${port_index}]},"
+				else
+					other_layer="${other_layer}0xf,"
+				fi
+				let "prev = ${card_index}"
+				let "card_index = ${card_index} + 1"
+				let "port_index = ${port_index} + 1"
+			done
+			
+			other_prot="$(echo ${other_prot} | ${SED} -e 's/^\(.*\),$/\1/')"
+			other_layer="$(echo ${other_layer} | ${SED} -e 's/^\(.*\),$/\1/')"
+			other_cmd="${other_cmd} ${other_prot} ${other_layer} ${other_extra}"
+
+			if [ -z "$1" ] ; then
+				echo "${other_cmd}"
+				eval ${other_cmd}
+			else
+				if [ "$1" = "${other_card[${prev}]}" ] ; then 
+					echo ${other_cmd}
+					eval ${other_cmd}
+				fi
+			fi
+
+
+		fi
+	done
+}
+
+function unload_card_modules {
+
+	IFS=$'\n'
+
+	for line in $(${SED} -ne '/^[^#]/p' ${misdn_init_conf});
+	do
+		var=$(echo "${line}" | ${CUT} -d "=" -f 1)
+		val=$(echo "${line}" | ${CUT} -d "=" -f 2)
+		
+		case "${var}" in
+			card)
+				nr=$(echo "${val}" | ${CUT} -d "," -f 1)
+				mod=$(echo "${val}" | ${CUT} -d "," -f 2)
+				case "${mod}" in
+					2E1)
+						modulelist[${nr}]=hfcmulti
+						;;
+					0x*)
+						modulelist[${nr}]=hfcmulti
+						;;
+					*)
+						modulelist[${nr}]=${mod}
+						;;
+				esac
+				;;
+		esac
+		
+	done
+
+	echo "-------------------------------------------"
+	echo " Unloading module(s) for your misdn-cards:"
+	echo "-------------------------------------------"
+
+	rmmod_cmd="${RMMOD} ${modulelist[1]}"
+	echo "${rmmod_cmd}"
+	eval ${rmmod_cmd}
+	
+	index=2
+	prev=1
+	while [ ! -z ${modulelist[${index}]} ];
+	do
+		if [ ${modulelist[${index}]} != ${modulelist[${prev}]} ]; then
+			rmmod_cmd="${RMMOD} ${modulelist[${index}]}"
+			echo "${rmmod_cmd}"
+			eval ${rmmod_cmd}
+		fi
+		let "prev = ${index}"
+		let "index = ${index} + 1"
+	done
+}
+
+function create_misdn_init_conf {
+	cardline=""	
+	cardcount=1
+	portcount=0
+	cardconf=""
+	IFS=$'\n'
+	NL="
+"
+	carddb=$(create_card_db)
+
+	for line in $carddb ; do 
+		tmp="card=$(echo $line | ${CUT} -d, -f1,3)"
+		let "portcount = ${portcount} + $(echo $line | ${CUT} -d, -f2)"
+		cardline="${cardline}${tmp}${NL}"	
+	done
+
+	function die {
+		echo "[!!] ${1}"
+		exit 1
+	}
+	
+	if [ "${1}" == "scan" ]; then
+		echo "[OK] found the following devices:"
+		echo "${cardline}[ii] run \"/usr/sbin/misdn-init config\" to store this information to ${misdn_init_conf}"
+	else
+		
+		index=1
+		portline="te_ptmp="
+		while [ ${index} -le ${portcount} ]; do
+			portline="${portline}${index},"
+			let "index = ${index} + 1"
+		done
+		portline="$(echo ${portline} | ${SED} -e 's/^\(.*\),$/\1/')"
+
+		misdn_cfg_pt1="#
+# Configuration file for your misdn hardware
+#
+# Usage: /usr/sbin/misdn-init start|stop|restart|config|scan|help
+#
+
+#
+# Card Settings
+#
+# Syntax: card=<number>,<type>[,<option>...]
+#
+#    <number>   count your cards beginning with 1
+#    <type>     either 0x1,0x4 or 0x8 for your hfcmulti hardware,
+#               or the name of your card driver module.
+#    <option>	ulaw       - uLaw (instead of aLaw)
+#               dtmf       - enable DTMF detection on all B-channels
+#
+#               pcm_slave  - set PCM bus into slave mode
+#			     If you have a set of cards, all wired via PCM. Set 
+#			     all cards into pcm_slave mode and leave one out.
+#			     The left card will automatically be Master.
+#
+#		ignore_pcm_frameclock	- this can be set in conjunction with
+#					pcm_slave. If this card has a  
+#					PCI Bus Position before the Position 
+#					of the Master, then this port cannot
+#					yet receive a frameclock, so it must
+#					ignore the pcm frameclock.
+#					 
+#		rxclock    - use clocking for pcm from ST Port
+#		crystalclock - use clocking for pcm from PLL (genrated on board)
+#		watchdog   - This dual E1 Board has a Watchdog for 
+#			     transparent mode
+#
+#"
+		misdn_cfg_pt2="#
+# Port settings
+#
+# Syntax: <port_type>=<port_number>[,<port_number>...]
+#
+#    <port_type>    te_ptp   		- TE-Mode, PTP
+#                   te_ptmp  		- TE-Mode, PTMP
+#                   te_capi_ptp  	- TE-Mode (capi), PTP
+#                   te_capi_ptmp 	- TE-Mode (capi), PTMP
+#                   nt_ptp   		- NT-Mode, PTP
+#                   nt_ptmp  		- NT-Mode, PTMP
+#    <port_number>  port that should be considered
+#"
+		misdn_cfg_pt3="#
+# Port Options
+#
+# Syntax: option=<port_number>,<option>[,<option>...]
+#
+#    <option>  master_clock  - use master clock for this S/T interface
+#                              (only once per chip, only for HFC 8/4)
+#              optical       - optical (only HFC-E1)
+#              los           - report LOS (only HFC-E1)
+#              ais           - report AIS (only HFC-E1)
+#              slip          - report SLIP (only HFC-E1)
+#              nocrc4	     - turn off crc4 mode use double frame instead 
+#				(only HFC-E1)
+#
+# The master_clock option is essential for retrieving and transmitting
+# faxes to avoid failures during transmission. It tells the driver to 
+# synchronize the Card with the given Port which should be a TE Port and
+# connected to the PSTN in general.
+#
+#option=1,master_clock
+#option=2,ais,nocrc4
+#option=3,optical,los,ais,slip
+
+
+#
+# General Options for your hfcmulti hardware
+#
+# poll=<number>
+#
+#        Only one poll value must be given for all cards.
+#        Give the number of samples for each fifo process.
+#        By default 128 is used. Decrease to reduce delay, increase to
+#        reduce cpu load. If unsure, don't mess with it!!!
+#        Valid is 32, 64, 128, 256.
+#
+# dsp_poll=<number>
+#	This is the poll option which is used by mISDN_dsp, this might 
+# 	differ from the one given by poll= for the hfc based cards, since
+# 	they can only use multiples of 32, the dsp_poll is dependant on 
+#	the kernel timer setting which can be found in the CPU section
+#	in the kernel config. Defaults are there either 100Hz, 250Hz 
+#	or 1000Hz. If your setting is either 1000 or 250 it is compatible
+#	with the poll option for the hfc chips, if you have 100 it is 
+#	different and you need here a multiple of 80.
+#	The default is to have no dsp_poll option, then the dsp itself
+#	finds out which option is the best to use by itself
+#
+# pcm=<number>
+#        
+#        Give the id of the PCM bus. All PCM busses with the same ID
+#        are expected to be connected and have equal slots.
+#        Only one chip of the PCM bus must be master, the others slave.
+#
+# debug=<number>
+#
+#        Enable debugging (see hfc_multi.h for debug options).
+#
+# dsp_options=<number>
+#  
+#	set this to 2 and you'll have software bridging instead of 
+#	hardware bridging.
+# 
+#
+# dtmfthreshold=<milliseconds>
+#
+#	Here you can tune the sensitivity of the dtmf tone recognizer.
+#
+# timer=<1|0>
+# 
+#	set this to 1 if you want hfcmulti to register at ztdummy (zaptel) 
+#	and provide a 1khz timing source for it. This makes it possible
+#	to have an accurate timing source for asterisk through zaptel from
+#	hfcmulti to make applications like Meetme and faxing between wctdm
+#	and hfcmulti work properly.
+#
+poll=128
+dsp_poll=128
+dsp_options=0
+dtmfthreshold=100
+debug=0"
+
+		if [ -f ${misdn_init_conf} ]; then
+			cp "${misdn_init_conf}" "${misdn_init_conf}.save" || die "could not backup your existing ${misdn_init_conf}!"
+			echo "[OK] ${misdn_init_conf} already present. backing it up to ${misdn_init_conf}.save"
+		fi
+		echo "${misdn_cfg_pt1}${NL}${cardline}${NL}${misdn_cfg_pt2}${NL}${portline}${NL}${NL}${misdn_cfg_pt3}" > ${misdn_init_conf} || die "could not write to /etc/misdn-init.conf!"
+#echo "${misdn_cfg_pt1}${NL}${cardline}${NL}${misdn_cfg_pt2}${NL}${portline}${NL}${NL}${misdn_cfg_pt3}" > testconf || die "could not write to /etc/misdn-init.conf!"
+
+		echo "[OK] ${misdn_init_conf} created. It's now safe to run \"/usr/sbin/misdn-init start\""
+		if [ ${portcount} -gt 1 ]; then
+			echo "[ii] make your ports (1-${portcount}) available in asterisk by editing \"/etc/asterisk/misdn.conf\""
+		elif [ ${portcount} -eq 1 ]; then
+			echo "[ii] make your port (1) available in asterisk by editing \"/etc/asterisk/misdn.conf\""
+		fi
+	fi
+}
+
+function check_cfg_file {
+	if [ ! -f ${misdn_init_conf} ]; then
+
+		if [ ! -z "$1" ] ; then
+			/usr/sbin/misdn-init config
+		else
+			echo "[!!] failed to load: ${misdn_init_conf}"
+			echo "run \"/usr/sbin/misdn-init config\" to scan your devices and generate a basic config file."
+			exit 1
+		fi
+	fi
+}
+
+# MAIN #############
+
+case "$1" in
+	start|--start)
+		check_cfg_file $2
+
+		${MODPROBE} capi
+		${MODPROBE} mISDN_core debug=0
+		${MODPROBE} mISDN_l1 debug=0
+		${MODPROBE} mISDN_l2 debug=0
+		${MODPROBE} l3udss1 debug=0
+		${MODPROBE} mISDN_capi
+		
+		load_card_modules $2
+		
+		echo "${MODPROBE} mISDN_dsp debug=0x0 options=$dsp_options $dsp_poll_option $dtmfthreshold_option"
+		${MODPROBE} mISDN_dsp debug=0x0 options=$dsp_options $dsp_poll_option $dtmfthreshold_option
+		sleep 1
+		
+		if [ ! -e /dev/mISDN ]; then
+			$MKNOD /dev/mISDN c 46 0
+			if grep asterisk /etc/passwd > /dev/null; then
+				chown $USER:$GROUP /dev/mISDN 
+			fi
+			echo "[i] creating device node: /dev/mISDN"
+		fi
+		;;
+
+	stop|--stop)
+		
+		check_cfg_file
+
+		check_asterisk
+
+		
+		for mod in $(lsmod | ${SED} -ne '/Module/!{s/\([^ ]*\).*/\1/;p}');
+		do
+			case "${mod}" in
+				mISDN_capi | mISDN_dsp | l3udss1 | mISDN_l2 | mISDN_l1 | mISDN_isac )
+					eval "${RMMOD} ${mod}"
+					;;
+			esac
+		done
+
+		unload_card_modules
+
+		${RMMOD} mISDN_core
+
+		;;
+
+	restart|--restart)
+		
+		check_cfg_file
+
+		sh $0 stop
+		sleep 2 # some phones will release tei when layer 1 is down
+		sh $0 start
+		;;
+
+	config|--config)
+
+		create_misdn_init_conf
+
+		;;
+
+	scan|--scan)
+
+		create_misdn_init_conf scan
+
+		;;
+
+	help|--help)
+		echo "Usage: $0 {start|stop|restart|config|scan|help}"
+		exit 0
+		;;
+
+	*)
+		echo "Usage: $0 {start|stop|restart|config|scan|help}"
+		exit 2
+		;;
+
+esac
+
+


Property changes on: misdn-kernel/trunk/misdn-init
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-kernel/trunk/std2kern
===================================================================
--- misdn-kernel/trunk/std2kern	                        (rev 0)
+++ misdn-kernel/trunk/std2kern	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,325 @@
+#!/bin/sh
+
+KERNELDIR=/lib/modules/$(uname -r)/build
+PREPARSER="./preparser"
+UNIQUE=false
+VERBOSE=false
+NOTEST=true
+DODIFF=false
+DIFFREV=false
+ALLOW_ANY_DIR=true
+
+docp() {
+
+    SRCNAME=$1;
+    if $VERBOSE; then
+	echo -n "$SRCNAME... "
+    fi
+
+    # special cases
+    
+    TMPNAME=/tmp/`basename $1`.$$
+    
+    # Makefiles
+    BASENAME=`basename $2`; 
+    if [ "$BASENAME" = "Makefile" ]; then
+	if [ $VERSION -gt 3 -o \( $VERSION -eq 2 -a $PATCHLEVEL -gt 3 \) ]; then
+	    sed -e "s/drivers\/isdn\/Rules\.make/Rules\.make/" < $SRCNAME > $TMPNAME
+	    if $VERBOSE ; then
+		echo -n "processing... modified..."
+	    fi
+	    SRCNAME=$TMPNAME
+	fi
+    fi
+
+    # Rules.make
+    if [ "$BASENAME" = "Rules.make" ]; then
+	if ! [ $VERSION -gt 3 -o \( $VERSION -eq 2 -a $PATCHLEVEL -gt 3 \) ]; then
+	    if $VERBOSE; then
+		echo "skipped"
+	    fi
+	    return
+	fi
+    fi
+
+    # *.[hc] : preparse if selected
+    if $UNIQUE ; then
+        if echo $SRCNAME | egrep -q '.[hc]$'; then
+	    # only copy isdn_compat.h if we don't have a
+	    # delete #include <linux/isdn_compat.h> in the ctrlfile
+	    if [ "$1" = "include/linux/isdn_compat.h" ]; then
+		if grep -q isdn_compat.h $CTRLNAME; then
+		    if $VERBOSE; then
+			echo "skipped"
+		    fi
+		    return
+		fi;
+	    fi
+	    if $VERBOSE; then
+		echo -n "processing... "
+	    fi
+	    $PREPARSER -c $CTRLNAME $SRCNAME $TMPNAME
+	    RETVAL=$?
+	    if [ $RETVAL -ne 2 -a $RETVAL -ne 0 ] ; then 
+		echo "Problem with preparser retval $RETVAL"
+		exit 1
+	    fi
+	    if [ $RETVAL -eq 2 ] ; then
+		if $VERBOSE; then
+		    echo -n "modified... "
+		fi
+		SRCNAME=$TMPNAME
+	    fi
+	fi
+    fi
+
+    if $DODIFF; then
+	if $VERBOSE; then
+	    echo
+	fi
+	if $DIFFREV; then
+	    diff -u $2 $SRCNAME
+        else
+	    diff -u $SRCNAME $2
+	fi
+    else
+	# do the actual copy, if necessary
+	if ! cmp -s $SRCNAME $2 ; then
+	    if $VERBOSE; then
+		echo "copying"
+	    else
+		echo "$1... copying"
+	    fi
+	    if $NOTEST ; then
+		    mkdir -p `dirname $2`
+		    rm -f $2 # unlink first
+		    cp $SRCNAME $2
+	    fi
+	else
+	    if $VERBOSE; then
+		echo "up to date"
+	    fi
+	fi
+    fi
+	
+    if [ -f $TMPNAME ]; then
+	rm -f $TMPNAME
+    fi
+}
+
+#
+# Print usage and exit
+#
+usage() {
+	cat<<EOM
+
+	std2kern is used for updating your kernel-tree from within
+	this directory.
+
+	std2kern [-h] [-k DIR] [-v] [-u] [-c FILE] [files ...]
+
+	Options:
+
+	-h	This Text.
+	-k DIR	Kerneltree is in DIR instead of /usr/src/linux
+        -v      More mesages about processing
+	-u      preprocessing with $PREPARSER
+	-d      don't copy but do a unified diff instead
+	-r      reverse directions of diff
+	-c FILE	Use FILE as control file for $PREPARSER (only with -u)
+	-t      Test, don't really copy files
+	-p PREFIX use PREFIX to install mISDNif.h in the system in the path $PREFIX/usr/include/linux
+
+	Without any files given, within the whole tree, the "right"
+	files are copied. When any files are given in the commandline,
+	only those are copied.
+
+EOM
+	exit
+}
+
+#
+# Check, if argument is a linux kernel dir
+#
+checkkernel() {
+	if [ -f $1/Makefile ] ; then
+		if [ "`grep ^vmlinux: $1/Makefile | grep vmlinux`" != "" ] ; then
+			return 0
+		fi
+	fi
+	echo "The given argument does not look like a kernel dir"
+	if ! $ALLOW_ANY_DIR; then
+	    exit 1
+	fi
+}
+
+#
+# Determine a control file name
+#
+calc_ctrl_file() {
+	if [ -z "$CTRLNAME" ] ; then
+		CTRLNAME=v$VERSION.$PATCHLEVEL.$SUBLEVEL.ctrl
+		if [ -f $CTRLNAME ] ; then
+			return 0
+		fi
+		CTRLNAME=v$VERSION.$PATCHLEVEL.ctrl
+		if [ -f $CTRLNAME ] ; then
+			return 0
+		fi
+		CTRLNAME=default.ctrl
+	fi
+	if [ -f $CTRLNAME ] ; then
+		return 0
+	fi
+	echo "No control file found"
+	exit 1
+}
+
+#
+# Determine a version depend file name
+#
+calc_version_file() {
+	VERSION_NAME=$1.v$VERSION.$PATCHLEVEL.$SUBLEVEL
+	if [ -f $VERSION_NAME ] ; then
+		return 0
+	fi
+	VERSION_NAME=$1.v$VERSION.$PATCHLEVEL
+	if [ -f $VERSION_NAME ] ; then
+		return 0
+	fi
+	VERSION_NAME=""
+	return 1
+}
+
+while getopts :p:dhk:uc:vtidr a ; do
+	case $a in
+		\?)	case $OPTARG in
+				k)	echo "-k requires Kernel directory parameter"
+					;;
+				*)  echo "Unknown option: -$OPTARG"
+					echo "Try std2kern -h"
+					;;
+			esac
+			exit 1
+			;;
+		k)	checkkernel $OPTARG
+			KERNELDIR=$OPTARG
+			;;
+		c)	CTRLNAME=$OPTARG
+			;;
+		u)	UNIQUE=true
+			;;
+		v)	VERBOSE=true
+			;;
+		t)	NOTEST=false
+			;;
+		i)      ALLOW_ANY_DIR=true;
+			;;
+		d)      DODIFF=true;
+			;;
+		r)      DIFFREV=true;
+			;;
+		p)      PREFIX=$OPTARG;
+			;;
+		h)	usage
+			;;
+	esac
+done
+shift `expr $OPTIND - 1`
+
+echo 
+echo "BE AWARE!!"
+echo 
+echo "You are just attempting to overwrite your Kernel mISDN Sources"
+echo "and to install mISDNif.h in your /usr/include/linux directory"
+echo "you probably prefer to use make install."
+echo
+echo "KERNELDIR=$KERNELDIR"
+ls -ld $KERNELDIR
+echo 
+echo "If you still want to patch this Kernel just answer yes:"
+read i
+
+if [ ! $i == "yes" ] ; then
+	echo "OK exiting"
+	exit 1
+fi
+
+#copy mISDNif.h to allow userspace apps to compile againt mISDN
+echo "Installing mISDNif.h in $PREFIX/usr/include/linux/mISDNif.h"
+mkdir -p $PREFIX/usr/include/linux/
+cp include/linux/mISDNif.h $PREFIX/usr/include/linux/
+
+if [ -z "$VERSION" -o -z "$PATCHLEVEL" ] ; then
+    if ! [ -f $KERNELDIR/Makefile ] ; then
+	echo "VERSION/PATCHLEVEL not set and no Makefile to read from"
+	exit 1
+    fi
+    eval `sed -n 's/^\([A-Z]*\) = \([0-9]*\)$/\1=\2/p' $KERNELDIR/Makefile`
+fi
+echo "Current kernel version is $VERSION.$PATCHLEVEL.$SUBLEVEL"
+
+if $UNIQUE ; then
+    calc_ctrl_file
+    echo "Controlfile $CTRLNAME"
+fi
+
+if [ $# != 0 ]; then
+    for i in $* ; do
+	docp $i $KERNELDIR/$i
+    done
+else
+    for i in `find drivers -type f -name '*.[hc]'`; do
+	docp $i $KERNELDIR/$i
+    done
+    for i in `find include -type f -name '*.h'`; do
+	docp $i $KERNELDIR/$i
+    done
+    for i in drivers/isdn/hardware/Makefile \
+	drivers/isdn/hardware/Kconfig \
+	drivers/isdn/hardware/mISDN/Makefile \
+	drivers/isdn/hardware/mISDN/Rules.mISDN \
+	drivers/isdn/hardware/mISDN/Kconfig \
+	drivers/isdn/Config.in \
+	drivers/isdn/Makefile; do
+	calc_version_file $i 
+	if [ -n "$VERSION_NAME" ] ; then
+	    docp $VERSION_NAME $KERNELDIR/$i
+	else
+	    if [ -f $i ] ; then
+		echo "use version independ $i for version v$VERSION.$PATCHLEVEL.$SUBLEVEL"
+		docp $i $KERNELDIR/$i
+	    else
+		echo "no $i for version v$VERSION.$PATCHLEVEL.$SUBLEVEL found -- skipped"
+	    fi
+	fi
+    done
+#    for i in `find Documentation -type f | grep -v CVS`; do
+#	docp $i $KERNELDIR/$i
+#    done
+fi
+exit 0
+
+  if [ -f $KERNELDIR/Documentation/Configure.help ] ; then
+    grep -q CONFIG_ISDN_DIVERSION $KERNELDIR/Documentation/Configure.help
+    if [ $? != 0 ] ; then
+      patch -d $KERNELDIR/Documentation < Documentation/Configure.help.divert.diff
+    fi
+  fi
+  if [ -f $KERNELDIR/Documentation/Configure.help ] ; then
+    grep -q CONFIG_ISDN_DRV_EICON $KERNELDIR/Documentation/Configure.help
+    if [ $? != 0 ] ; then
+      patch -d $KERNELDIR/Documentation < Documentation/Configure.help.eicon.diff
+    fi
+  fi
+  if $NOTEST ; then
+    if [ -f $KERNELDIR/Documentation/Configure.help ] ; then
+      grep -q CONFIG_ISDN_WITH_ABC $KERNELDIR/Documentation/Configure.help
+      if [ $? != 0 ] ; then
+	  if [ -f  Documentation/Configure.help.dwabc.diff ] ; then
+            patch -d $KERNELDIR/Documentation < Documentation/Configure.help.dwabc.diff
+	  fi
+      fi
+    fi
+  fi
+fi


Property changes on: misdn-kernel/trunk/std2kern
___________________________________________________________________
Name: svn:executable
   + *

Added: misdn-kernel/trunk/stddiff
===================================================================
--- misdn-kernel/trunk/stddiff	                        (rev 0)
+++ misdn-kernel/trunk/stddiff	2007-07-17 14:12:37 UTC (rev 3754)
@@ -0,0 +1,206 @@
+#!/bin/sh
+
+KERNELDIR=/lib/modules/$(uname -r)/build
+KERNFIRST=false
+PREPARSER="./preparser"
+DODIFF=dodiff
+UNIQUE=false
+
+dodiff() {
+  if $KERNFIRST ; then
+    diff -u $EXTRAOPT $2 $1
+  else
+    diff -u $EXTRAOPT $1 $2
+  fi
+}
+
+dodiffuni() {
+    echo -n "Processing $1 ... "
+    TMPNAME=/tmp/`basename $1`.$$ 
+    $PREPARSER -c $CTRLNAME $1 $TMPNAME
+    RES=$?
+    if [ "$RES" -eq "0" ] ; then 
+	echo diff original
+	dodiff $1 $2
+	rm $TMPNAME
+	return 0
+    fi
+    if [ "$RES" -eq "2" ] ; then
+	echo diff modified
+	dodiff $TMPNAME $2
+	rm $TMPNAME
+	return 0
+    fi
+    echo "problem with $PREPARSER retcode $RES"
+    exit 1
+}
+
+
+#
+# Print usage and exit
+#
+usage() {
+	cat<<EOM
+
+	stddiff is used for generating diffs of the cvs-tree
+		versus the kernel-tree.
+
+	stddiff [-r] [-h] [-k DIR] [-u] [-c FILE] [-w] [files ...]
+
+	Options:
+
+	-h      This Text.
+	-r      Reverse direction (kernel versus cvs).
+	-k DIR  Kerneltree is in DIR instead of /usr/src/linux
+	-u      Make a diff for a unique kernel-tree 
+                (preprocessing with $PREPARSER)
+	-c FILE	Use FILE as control file for $PREPARSER (only with -u)
+	-w      Ignore white space when comparing lines 
+
+	Without any files given, within the whole tree, the "right"
+	files are diffed. When any files are given in the commandline,
+	only those are diffed.
+
+EOM
+	exit
+}
+
+#
+# Check, if argument is a linux kernel dir
+#
+checkkernel() {
+	if [ -f $1/Makefile ] ; then
+#		if [ "`grep ^vmlinux: $1/Makefile | grep vmlinux`" != "" ] ; then
+			return 0
+#		fi
+	fi
+	echo "The given argument does not look like a kernel dir"
+	exit 1
+}
+
+#
+# Determine a control file name
+#
+calc_ctrl_file() {
+	eval `sed -n 's/^\([A-Z]*\) = \([0-9]*\)$/\1=\2/p' $KERNELDIR/Makefile`
+	echo "Current kernel version is $VERSION.$PATCHLEVEL.$SUBLEVEL"
+	if [ -z "$CTRLNAME" ] ; then
+		CTRLNAME=v$VERSION.$PATCHLEVEL.$SUBLEVEL.ctrl
+		if [ -f $CTRLNAME ] ; then
+			return 0
+		fi
+		CTRLNAME=v$VERSION.$PATCHLEVEL.ctrl
+		if [ -f $CTRLNAME ] ; then
+			return 0
+		fi
+		CTRLNAME=default.ctrl
+	fi
+	if [ -f $CTRLNAME ] ; then
+		return 0
+	fi
+	echo "No control file found"
+	exit 1
+}
+
+#
+# Determine a version depend file name
+#
+calc_version_file() {
+	VERSION_NAME=$1.v$VERSION.$PATCHLEVEL.$SUBLEVEL
+	if [ -f $VERSION_NAME ] ; then
+		return 0
+	fi
+	VERSION_NAME=$1.v$VERSION.$PATCHLEVEL
+	if [ -f $VERSION_NAME ] ; then
+		return 0
+	fi
+	VERSION_NAME=""
+	return 1
+}
+
+while getopts :rhk:uc:w a ; do
+	case $a in
+		\?) case $OPTARG in
+			k)  echo "-k requires Kernel directory parameter"
+					;;
+			*)  echo "Unknown option: -$OPTARG"
+				echo "Try stddiff -h"
+				;;
+			esac
+			exit 1
+			;;
+		k)  checkkernel $OPTARG
+			KERNELDIR=$OPTARG
+			;;
+		c)  CTRLNAME=$OPTARG
+			;;
+		u)  UNIQUE=true
+			;;
+		r)  KERNFIRST=true
+			;;
+		w)  EXTRAOPT=-w
+			;;
+		h)  usage
+			;;
+	esac
+done
+shift `expr $OPTIND - 1`
+
+if [ -z "$VERSION" -o -z "$PATCHLEVEL" ] ; then
+    if ! [ -f $KERNELDIR/Makefile ] ; then
+	echo "VERSION/PATCHLEVEL not set and no Makefile to read from"
+	exit 1
+    fi
+    eval `sed -n 's/^\([A-Z]*\) = \([0-9]*\)$/\1=\2/p' $KERNELDIR/Makefile`
+fi
+echo "Current kernel version is $VERSION.$PATCHLEVEL.$SUBLEVEL"
+
+if $UNIQUE ; then
+	DODIFF=dodiffuni
+	calc_ctrl_file
+fi
+
+echo -n "Using $DODIFF $EXTRAOPT"
+
+if $UNIQUE ; then
+	echo " with controlfile $CTRLNAME"
+else
+	echo
+fi
+
+if [ $# != 0 ]; then
+	for i in $* ; do
+		$DODIFF $i $KERNELDIR/$i
+	done
+else
+	for i in drivers/isdn/hardware/mISDN/*.[ch] ; do
+		$DODIFF $i $KERNELDIR/$i
+	done
+	for i in include/linux/*.h ; do
+		if [ "$i" = "include/linux/isdn_compat.h" -a \
+		     "$UNIQUE" = "true" ] ; then
+			echo "$i skipped"
+		else
+			$DODIFF $i $KERNELDIR/$i
+		fi
+	done
+	
+	for i in drivers/isdn/hardware/Makefile \
+		drivers/isdn/hardware/Kconfig \
+		drivers/isdn/hardware/mISDN/Makefile \
+		drivers/isdn/hardware/mISDN/Rules.make \
+		drivers/isdn/hardware/mISDN/Kconfig ; do
+		calc_version_file $i 
+		if [ -n "$VERSION_NAME" ] ; then
+	    		dodiff $VERSION_NAME $KERNELDIR/$i
+		else
+			if [ -f $i ] ; then
+				echo "use version independ $i for version v$VERSION.$PATCHLEVEL.$SUBLEVEL"
+				$DODIFF $i $KERNELDIR/$i
+			else
+				echo "no $i for version v$VERSION.$PATCHLEVEL.$SUBLEVEL found -- skipped"
+			fi
+		fi
+	done
+fi
+


Property changes on: misdn-kernel/trunk/stddiff
___________________________________________________________________
Name: svn:executable
   + *




More information about the Pkg-voip-commits mailing list