Compare commits
337 Commits
mISDN_1_0_
...
master
Author | SHA1 | Date |
---|---|---|
Daniel Potts | cecb784778 | |
Andreas Eversberg | 19890b650c | |
Andreas Eversberg | f4a3d41cc4 | |
Andreas Eversberg | c4dd8765b4 | |
Andreas Eversberg | 34458d894d | |
Andreas Eversberg | c24e757ff4 | |
Nadi Sarrar | 4a64d3fbc2 | |
Chrisian Richter | fc245dc655 | |
Chrisian Richter | 81e9a9193e | |
Nadi Sarrar | 9d76bbabf0 | |
Andreas Eversberg | b70f8ddd1c | |
Chrisian Richter | c34e06a2dd | |
Chrisian Richter | 8afd39d035 | |
Chrisian Richter | 4b08981a7e | |
Chrisian Richter | 0981be2474 | |
Chrisian Richter | cfcd035054 | |
Chrisian Richter | 1fa5c5942f | |
Chrisian Richter | b87a76c616 | |
Chrisian Richter | 04c6a25a2c | |
Chrisian Richter | dcc1f604e9 | |
Chrisian Richter | b237b99a3e | |
Chrisian Richter | 140f0044d0 | |
Chrisian Richter | 1f4daf4e55 | |
Chrisian Richter | 26104aec84 | |
Nadi Sarrar | 2083ca73f1 | |
Chrisian Richter | 84116778c7 | |
Chrisian Richter | 6e6702b4df | |
Chrisian Richter | b6351ddb11 | |
Chrisian Richter | 7b172e73f0 | |
Chrisian Richter | 618cd071d2 | |
Chrisian Richter | d45c93792d | |
Chrisian Richter | 3f81fb08cb | |
Andreas Eversberg | 19a3869229 | |
Nadi Sarrar | d300bb238d | |
Nadi Sarrar | d1e673c815 | |
Chrisian Richter | 1c919ae75b | |
Nadi Sarrar | 440aacfdf4 | |
Nadi Sarrar | 6120cb8cc5 | |
Nadi Sarrar | 7fd00bc1bb | |
Nadi Sarrar | 183941be8c | |
Nadi Sarrar | cacd47333c | |
Günther Kelleter | a48dd57635 | |
Martin Bachem | c54ddc246d | |
Chrisian Richter | 106461e7d2 | |
Martin Bachem | 4c96e1925c | |
Martin Bachem | 2384b39092 | |
Martin Bachem | b1bec05514 | |
Martin Bachem | 001d02742d | |
Martin Bachem | 2a1c2e8207 | |
Martin Bachem | 926fa87208 | |
Chrisian Richter | 17e4ca93cd | |
Nadi Sarrar | c6e604b80f | |
Chrisian Richter | 88a4a4ec2a | |
Chrisian Richter | 4254384a53 | |
Chrisian Richter | 7dfe7cf810 | |
Chrisian Richter | 25aebcc9b4 | |
Chrisian Richter | f4e18a559d | |
Chrisian Richter | 6e66a0fb06 | |
Chrisian Richter | 8d515d2fdf | |
Martin Bachem | 51ecee1ea0 | |
Martin Bachem | a824a65c98 | |
Chrisian Richter | ae7ba0a377 | |
Chrisian Richter | a340296f95 | |
Chrisian Richter | 1b39ae1623 | |
srichter | b2f839bd51 | |
Chrisian Richter | 7baab3c770 | |
Chrisian Richter | 53e5e1d7c7 | |
Chrisian Richter | 1ed9289f48 | |
Chrisian Richter | 60be2d76f8 | |
Daniel Potts | 36ade5e5f5 | |
Chrisian Richter | 7de26421e1 | |
Günther Kelleter | fca2dd211f | |
Günther Kelleter | 643710ddbf | |
Günther Kelleter | 2b7e0b8e84 | |
Günther Kelleter | e42aada6cf | |
Günther Kelleter | d87bf83950 | |
Günther Kelleter | f85a2af479 | |
Günther Kelleter | 0f20f5bdc6 | |
Günther Kelleter | 15f0d65a7f | |
Günther Kelleter | 70914a8e6f | |
Chrisian Richter | 216a4b1edd | |
Chrisian Richter | 5787705119 | |
Martin Bachem | 89626fbade | |
Chrisian Richter | a9c1ddd31c | |
Chrisian Richter | 5d275ef7d7 | |
Chrisian Richter | 8ab0c38df3 | |
Nadi Sarrar | 18df072e60 | |
Martin Bachem | c9d11dda5f | |
Chrisian Richter | 01e13c7883 | |
Karsten Keil | 3606a753cd | |
Daniel Potts | 7fa0d32c3e | |
Karsten Keil | b2629bc4b7 | |
Karsten Keil | 71aa0d3dc1 | |
Chrisian Richter | cb7fbf931b | |
Chrisian Richter | 9d468d79be | |
Chrisian Richter | 6fa421dc88 | |
Chrisian Richter | a217cc8071 | |
Chrisian Richter | 7c9d3427c2 | |
Chrisian Richter | 50bfd90684 | |
Chrisian Richter | ab4597fde4 | |
Chrisian Richter | 1c93a4f475 | |
Chrisian Richter | fed7fcf52d | |
Chrisian Richter | 86beb33815 | |
Chrisian Richter | 25f37a1d92 | |
Chrisian Richter | 4d82d4de70 | |
Chrisian Richter | f15296da42 | |
Chrisian Richter | 3ead35f330 | |
Karsten Keil | 5036dcc9bc | |
Karsten Keil | 63a0047915 | |
Karsten Keil | 06b2b6d540 | |
Karsten Keil | 5d3fa852e7 | |
Daniel Potts | 5e56ba89ae | |
Daniel Potts | 419a1afba1 | |
Karsten Keil | 98c9e63081 | |
Daniel Potts | e862e5aac1 | |
Karsten Keil | 07a8ef6ac4 | |
Chrisian Richter | c2def45158 | |
Chrisian Richter | b5f2e62aa8 | |
Chrisian Richter | a7034bc3fc | |
Chrisian Richter | 90439f3b95 | |
Chrisian Richter | 2a7a305767 | |
Chrisian Richter | ba1f784186 | |
Chrisian Richter | ba46ac67a7 | |
Chrisian Richter | 958a2e6ae1 | |
Chrisian Richter | 74399516a9 | |
Chrisian Richter | cf9dc7a520 | |
Karsten Keil | 6a0e5e53be | |
Chrisian Richter | df8ef49812 | |
Chrisian Richter | 6f9233157a | |
Chrisian Richter | 8e7b38b15f | |
Chrisian Richter | 318b7a7912 | |
Chrisian Richter | fabc822d5f | |
Chrisian Richter | 08f6fd24ca | |
Chrisian Richter | 37c4b05c1c | |
Chrisian Richter | 83db9f7a92 | |
Chrisian Richter | 37527f5a1e | |
Chrisian Richter | 2b91aa829c | |
Chrisian Richter | dd8d5c47c1 | |
Chrisian Richter | f9a1f8a7c3 | |
Chrisian Richter | 17c5b66c32 | |
Chrisian Richter | bcf464c910 | |
Chrisian Richter | 0e9fc6c22e | |
Chrisian Richter | 150992561e | |
Chrisian Richter | 169c4dbded | |
Chrisian Richter | 82696e78fa | |
Martin Bachem | a32900b2b3 | |
Martin Bachem | 14774a420f | |
Martin Bachem | 7b48be70e0 | |
Chrisian Richter | 4e29b84aae | |
Martin Bachem | f95a570dbd | |
Martin Bachem | aba7cf20e8 | |
Martin Bachem | eda5eb22d6 | |
Chrisian Richter | 78503c4a80 | |
Chrisian Richter | 46c23e5ddc | |
Chrisian Richter | 790b0fb2e8 | |
Chrisian Richter | c684d5e96d | |
Chrisian Richter | 534a86348f | |
Martin Bachem | fafb8122bb | |
Chrisian Richter | 88b1be3d4c | |
Martin Bachem | b972326e3d | |
Martin Bachem | adb6cc7a2b | |
Chrisian Richter | 00a3255aa0 | |
Chrisian Richter | aa72af8460 | |
Chrisian Richter | 99fa436487 | |
Martin Bachem | 92e4c668ac | |
Martin Bachem | 755034c737 | |
Martin Bachem | 4e0f56832c | |
Chrisian Richter | 8e7e9cdf23 | |
Chrisian Richter | 28beb2274c | |
Chrisian Richter | 076a14607e | |
Karsten Keil | d5189f2f1e | |
Chrisian Richter | 9a3adc568d | |
Chrisian Richter | 851bbdceec | |
Martin Bachem | 7cac3cdb06 | |
Martin Bachem | ad79ac6564 | |
Martin Bachem | 46d8409e91 | |
Karsten Keil | d2bd2a6133 | |
Karsten Keil | d6dd9d2951 | |
Karsten Keil | ae3886bda9 | |
Chrisian Richter | 6c0f392d36 | |
Karsten Keil | 84beff43b5 | |
Karsten Keil | bec283bb85 | |
Karsten Keil | 273ea59911 | |
Karsten Keil | 3b80b6e75c | |
Martin Bachem | 104996ce94 | |
Martin Bachem | 6baa0d7b32 | |
Chrisian Richter | cd6e0aca4a | |
Martin Bachem | 7375a33587 | |
Chrisian Richter | 67b9799208 | |
Chrisian Richter | b7ce29e545 | |
Martin Bachem | ce4dbd587e | |
Chrisian Richter | 885ab66510 | |
Chrisian Richter | 445c147d01 | |
Chrisian Richter | 6a9d2d4907 | |
Martin Bachem | ebe6c8274c | |
Martin Bachem | 2a8655f939 | |
Karsten Keil | b267c6033f | |
Karsten Keil | 56f18961c0 | |
Karsten Keil | 44cf601712 | |
Martin Bachem | 229883dd7d | |
Karsten Keil | 726e2a033e | |
Karsten Keil | 0d1253ce86 | |
Karsten Keil | 21466f9b7b | |
Karsten Keil | 786ab881f8 | |
srichter | 24f62a4c3c | |
Karsten Keil | 65eaeb3579 | |
Martin Bachem | 514a4ab48c | |
Martin Bachem | ea21d7f00e | |
Andreas Eversberg | 5f5bbde7aa | |
Martin Bachem | c2faf5fcc0 | |
Karsten Keil | 00c2a28955 | |
Karsten Keil | 7b940e57d4 | |
Andreas Eversberg | 5892e8575e | |
Martin Bachem | 53ad00795a | |
Karsten Keil | 2929c9e213 | |
Karsten Keil | 8101522abc | |
Martin Bachem | 4e09c93764 | |
Martin Bachem | b49b5d512b | |
Martin Bachem | ad5d7ae143 | |
Karsten Keil | eb05f41960 | |
Karsten Keil | 5e7f03944c | |
Andreas Eversberg | 2476232664 | |
Karsten Keil | dc7d9402b8 | |
Andreas Eversberg | 8035c5e67b | |
Andreas Eversberg | c102bdedde | |
Andreas Eversberg | beb0f4faea | |
Andreas Eversberg | 17f2f8610b | |
Karsten Keil | d2726ff9e2 | |
Andreas Eversberg | 62079d9a77 | |
Andreas Eversberg | fdf3a2952b | |
Andreas Eversberg | 8beec5109d | |
Andreas Eversberg | 9e0fc751ff | |
Andreas Eversberg | 84921213dc | |
Andreas Eversberg | 3891628b0b | |
Andreas Eversberg | cf68d7e299 | |
Andreas Eversberg | 6a9dfe9e94 | |
Karsten Keil | 4e154aecee | |
Karsten Keil | 3d9f29d093 | |
Karsten Keil | b7b532ca9d | |
Andreas Eversberg | c5b8933b5b | |
Andreas Eversberg | 13a54f711d | |
Karsten Keil | 62c911e0cd | |
Karsten Keil | 918caa4018 | |
Andreas Eversberg | 818a365de2 | |
Karsten Keil | 1a7843297d | |
Andreas Eversberg | ebbb33b3de | |
Andreas Eversberg | cc28674787 | |
Andreas Eversberg | ea898aa233 | |
Andreas Eversberg | 342ebbf58f | |
Karsten Keil | 412a999cf3 | |
Andreas Eversberg | 23ae60a595 | |
Andreas Eversberg | f4d01aaa70 | |
Andreas Eversberg | d32e9d4184 | |
Andreas Eversberg | e8fae00343 | |
Karsten Keil | c86cad1c3c | |
Karsten Keil | 16ff314d9b | |
Karsten Keil | f947bb1dda | |
Karsten Keil | 4520efea23 | |
Karsten Keil | dc3f532e70 | |
Karsten Keil | 29755c5e2a | |
Karsten Keil | 534b91544a | |
Karsten Keil | 502df8c8cc | |
Karsten Keil | 687d208d8e | |
Karsten Keil | ba3087428b | |
Karsten Keil | 1212f1ac39 | |
Karsten Keil | 03381a45d2 | |
Paul Slootman | f26b3e2119 | |
Karsten Keil | 2099445d86 | |
Karsten Keil | a81680766c | |
Karsten Keil | bd02c3349f | |
Karsten Keil | 8c08d2452a | |
Karsten Keil | e16c026f52 | |
Karsten Keil | 5c8ff7788c | |
Karsten Keil | 71a70af6e4 | |
Karsten Keil | 54bf56649a | |
Karsten Keil | 095ce49d2a | |
Karsten Keil | e2da308e66 | |
Karsten Keil | db16534050 | |
Karsten Keil | 2723418266 | |
Karsten Keil | d69a999fa3 | |
Karsten Keil | e73f50283d | |
Karsten Keil | 7c3b38f64b | |
Karsten Keil | c361dcf36c | |
Karsten Keil | 69b589d9b1 | |
Karsten Keil | 2a5c1b4d35 | |
Karsten Keil | db2a923a8c | |
Karsten Keil | 5a6a9edc86 | |
Karsten Keil | e504373ebf | |
Karsten Keil | c4271592e3 | |
Karsten Keil | ee11c08ca9 | |
Karsten Keil | a23e7a864e | |
Karsten Keil | 376ee65136 | |
Karsten Keil | 8d5f6a65d3 | |
Karsten Keil | 85337c9851 | |
Karsten Keil | ffa91934b6 | |
Karsten Keil | 6b768b38be | |
Karsten Keil | 901de44f30 | |
Karsten Keil | 9875a66041 | |
Karsten Keil | 07bdf740c4 | |
Karsten Keil | 60271ca2c4 | |
Karsten Keil | 9dbe8ab580 | |
Karsten Keil | 61dc94dc12 | |
Karsten Keil | f981c59afa | |
Karsten Keil | a804c5e387 | |
Karsten Keil | 34c2231099 | |
Karsten Keil | ac245e4f03 | |
Karsten Keil | f5e8b76653 | |
Karsten Keil | 5b258f12f7 | |
Karsten Keil | 732742f5ae | |
Karsten Keil | 38b2c883d0 | |
Karsten Keil | 01eea674f4 | |
Karsten Keil | 9804ce04f3 | |
Karsten Keil | de3ed4b928 | |
Karsten Keil | a07bcdbc73 | |
Karsten Keil | 087341a247 | |
Karsten Keil | 1323cf35ec | |
Karsten Keil | 6b4f858edd | |
Karsten Keil | 3bfc0bfb97 | |
Karsten Keil | 21c4453091 | |
Karsten Keil | dbb4d39d89 | |
Karsten Keil | fdb4554989 | |
Karsten Keil | a668767214 | |
Karsten Keil | 21ba75f6fc | |
Karsten Keil | 1dd41139d7 | |
Karsten Keil | a027d30557 | |
Karsten Keil | a0230a1cd7 | |
Karsten Keil | 04e451b602 | |
Karsten Keil | fddc1475e7 | |
Karsten Keil | 90ab30a38d | |
Karsten Keil | 0dc7dd5c8c | |
Karsten Keil | cdc52fe430 | |
Karsten Keil | a34671a12e | |
Karsten Keil | 23bf3dfc13 | |
Karsten Keil | 4f4c070e39 | |
Karsten Keil | 002d7d9050 | |
Karsten Keil | 8f07adb55c | |
Karsten Keil | f79ff2f3f5 |
|
@ -0,0 +1,8 @@
|
|||
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
|
||||
- fix in CMX: sending is required even during PCM bridge, because sending data overrides bridging temporarily (for sending info tones during bridge)
|
||||
- enabled CMX audio processing for RX data in all cases, because it is essential
|
||||
- now it is save to free skb during interrupt, if memdebug is on
|
|
@ -0,0 +1,127 @@
|
|||
BASEDIR=$(shell pwd)
|
||||
|
||||
MAJOR=1
|
||||
MINOR=1
|
||||
SUBMINOR=2
|
||||
|
||||
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_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/
|
||||
|
||||
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:
|
||||
if cvs status Makefile | grep "Sticky Tag" | grep none > /dev/null ; then \
|
||||
echo $(MAJOR)_$(MINOR)_$(SUBMINOR)-$$(date +"20%y_%m_%d" | sed -e "s/\//_/g") > VERSION ; \
|
||||
else \
|
||||
echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION ; \
|
||||
fi
|
||||
|
||||
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
|
||||
|
|
@ -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
|
||||
|
13
add.config
13
add.config
|
@ -1,3 +1,10 @@
|
|||
# new mISDN driver as module
|
||||
CONFIG_ISDN_DRV_mISDN=m
|
||||
|
||||
#
|
||||
# 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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -0,0 +1,434 @@
|
|||
#!/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=''
|
||||
|
||||
AVMFRITZ_protocol=''
|
||||
AVMFRITZ_layermask=''
|
||||
|
||||
HFCPCI_protocol=''
|
||||
HFCPCI_layermask=''
|
||||
|
||||
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
|
||||
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_dsp*)
|
||||
MISDNDSP_options=${line:17}
|
||||
;;
|
||||
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'
|
||||
;;
|
||||
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})"
|
||||
;;
|
||||
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
|
||||
|
||||
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_dsp ${MISDNDSP_options}"
|
||||
}
|
||||
|
||||
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 | avmfritz)
|
||||
STOP_COMMANDS[0]="${STOP_COMMANDS[0]:-"${MODPROBE} -r --ignore-remove"} ${mod}"
|
||||
;;
|
||||
mISDN_core)
|
||||
STOP_COMMANDS[1]="${MODPROBE} -r --ignore-remove mISDN_core"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "-- Unloading mISDN modules --"
|
||||
while [ ! -z "${STOP_COMMANDS[${i}]}" ]; do
|
||||
echo ">> ${STOP_COMMANDS[${i}]}"
|
||||
eval "${STOP_COMMANDS[${i}]}"
|
||||
let "i = ${i} + 1"
|
||||
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}" | ${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
|
||||
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,131 @@
|
|||
<?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.hfcmulti.xsl' />
|
||||
<xsl:include href='mISDN.conf.bnx.xsl' />
|
||||
<xsl:include href='mISDN.conf.singlepci.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=".='mISDN_dsp'">
|
||||
<xsl:value-of select="concat('MODULE:',.)" />
|
||||
<xsl:call-template name="MISDNDSPmodule" />
|
||||
</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:',@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:',@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:',@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:',@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:',@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:choose>
|
||||
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
|
@ -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
|
|
@ -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)
|
|
@ -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"
|
||||
|
|
@ -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/
|
|
@ -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
|
|
@ -1,113 +1,113 @@
|
|||
L_OBJS :=
|
||||
M_OBJS :=
|
||||
LX_OBJS :=
|
||||
MX_OBJS :=
|
||||
O_OBJS :=
|
||||
OX_OBJS :=
|
||||
L_TARGET :=
|
||||
O_TARGET := vmlinux-obj.o
|
||||
# Makefile for the modular ISDN driver
|
||||
#
|
||||
EXTRA_CFLAGS += -ggdb
|
||||
#
|
||||
|
||||
# EXTRA_CFLAGS += -S -g
|
||||
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 debug.o helper.o fsm.o isar.o dchannel.o bchannel.o
|
||||
avmfritz-objs := avm_fritz.o debug.o helper.o fsm.o dchannel.o bchannel.o
|
||||
hfcpci-objs := hfc_pci.o debug.o helper.o dchannel.o bchannel.o
|
||||
mISDN_isac-objs := isac.o arcofi.o debug.o
|
||||
mISDN_core-objs := core.o stack.o udevice.o helper.o
|
||||
mISDN_l1-objs := layer1.o helper.o debug.o fsm.o
|
||||
mISDN_l2-objs := layer2.o tei.o helper.o debug.o fsm.o
|
||||
l3udss1-objs := layer3.o helper.o l3helper.o debug.o fsm.o l3_udss1.o
|
||||
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o cplci.o ncci.o asn1.o \
|
||||
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
|
||||
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 helper.o l3helper.o debug.o fsm.o
|
||||
mISDN_dtmf-objs := dtmf.o helper.o debug.o
|
||||
|
||||
ifdef CONFIG_I4L_CAPI_LAYER
|
||||
I4LmISDN-objs := i4l_mISDN.o helper.o l3helper.o debug.o fsm.o
|
||||
endif
|
||||
|
||||
LX_OBJS += core.o
|
||||
|
||||
ifdef MEMDBG
|
||||
EXTRA_CFLAGS += -DMEMDBG
|
||||
MX_OBJS += memdbg.o
|
||||
endif
|
||||
|
||||
#ifeq ($(CONFIG_ISDN_DRV_mISDN),y)
|
||||
# O_TARGET += mISDN.o
|
||||
#else
|
||||
# ifeq ($(CONFIG_ISDN_DRV_mISDN),m)
|
||||
# O_TARGET += mISDN.o
|
||||
# M_OBJS += mISDN.o
|
||||
# endif
|
||||
#endif
|
||||
|
||||
export-objs := core.o isac.o
|
||||
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) :=
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_core.o
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_isac.o
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += avmfritz.o
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += sedlfax.o
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += hfcpci.o
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_l1.o
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_l2.o
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += l3udss1.o
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_capi.o
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += mISDN_dtmf.o
|
||||
obj-$(CONFIG_ISDN_DRV_mISDN) += I4LmISDN.o
|
||||
|
||||
M_OBJS := $(obj-m)
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
||||
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_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 ,$^)
|
||||
|
||||
hfcpci.o: $(hfcpci-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 ,$^)
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,113 @@
|
|||
# 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
|
||||
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
|
||||
|
||||
|
|
@ -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 ,$^)
|
File diff suppressed because it is too large
Load Diff
|
@ -1,323 +1,535 @@
|
|||
/* $Id$
|
||||
*
|
||||
* 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 "capi.h"
|
||||
#include "m_capi.h"
|
||||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
#include "mISDNManufacturer.h"
|
||||
|
||||
#define applDebug(appl, lev, fmt, args...) \
|
||||
capidebug(lev, fmt, ## args)
|
||||
|
||||
void applConstr(Appl_t *appl, Contr_t *contr, __u16 ApplId, capi_register_params *rp)
|
||||
static struct list_head garbage_applications = LIST_HEAD_INIT(garbage_applications);
|
||||
|
||||
int
|
||||
ApplicationConstr(Controller_t *contr, __u16 ApplId, capi_register_params *rp)
|
||||
{
|
||||
memset(appl, 0, sizeof(Appl_t));
|
||||
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->rp, rp, sizeof(capi_register_params));
|
||||
listenConstr(&appl->listen, contr, ApplId);
|
||||
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);
|
||||
}
|
||||
|
||||
void applDestr(Appl_t *appl)
|
||||
/*
|
||||
* 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;
|
||||
int i, used = 0;
|
||||
AppPlci_t **aplci_p = appl->AppPlcis;
|
||||
|
||||
listenDestr(&appl->listen);
|
||||
for (i = 0; i < CAPI_MAXPLCI; i++) {
|
||||
if (appl->cplcis[i]) {
|
||||
cplciDestr(appl->cplcis[i]);
|
||||
kfree(appl->cplcis[i]);
|
||||
appl->cplcis[i] = NULL;
|
||||
}
|
||||
if (test_and_set_bit(APPL_STATE_DESTRUCTOR, &appl->state)) {
|
||||
// we are allready in this function
|
||||
return(-EBUSY);
|
||||
}
|
||||
}
|
||||
|
||||
Cplci_t *applAdr2cplci(Appl_t *appl, __u32 adr)
|
||||
{
|
||||
int i = (adr >> 8) & 0xff;
|
||||
|
||||
if ((i < 1) || (i > CAPI_MAXPLCI)) {
|
||||
int_error();
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
return appl->cplcis[i - 1];
|
||||
}
|
||||
|
||||
void applSendMessage(Appl_t *appl, struct sk_buff *skb)
|
||||
{
|
||||
Plci_t *plci;
|
||||
Cplci_t *cplci;
|
||||
|
||||
switch (CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data))) {
|
||||
|
||||
// for NCCI state machine
|
||||
case CAPI_DATA_B3_REQ:
|
||||
case CAPI_DATA_B3_RESP:
|
||||
case CAPI_CONNECT_B3_REQ:
|
||||
case CAPI_CONNECT_B3_RESP:
|
||||
case CAPI_CONNECT_B3_ACTIVE_RESP:
|
||||
case CAPI_DISCONNECT_B3_REQ:
|
||||
case CAPI_DISCONNECT_B3_RESP:
|
||||
cplci = applAdr2cplci(appl, CAPIMSG_CONTROL(skb->data));
|
||||
if (!cplci) {
|
||||
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
|
||||
goto free;
|
||||
}
|
||||
if (!cplci->ncci) {
|
||||
int_error();
|
||||
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
|
||||
goto free;
|
||||
}
|
||||
ncciSendMessage(cplci->ncci, 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:
|
||||
cplci = applAdr2cplci(appl, CAPIMSG_CONTROL(skb->data));
|
||||
if (!cplci) {
|
||||
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
|
||||
goto free;
|
||||
}
|
||||
cplciSendMessage(cplci, skb);
|
||||
break;
|
||||
case CAPI_CONNECT_REQ:
|
||||
plci = contrNewPlci(appl->contr);
|
||||
if (!plci) {
|
||||
contrAnswerMessage(appl->contr, skb, CapiNoPlciAvailable);
|
||||
goto free;
|
||||
}
|
||||
cplci = applNewCplci(appl, plci);
|
||||
if (!cplci) {
|
||||
contrDelPlci(appl->contr, plci);
|
||||
contrAnswerMessage(appl->contr, skb, CapiNoPlciAvailable);
|
||||
goto free;
|
||||
}
|
||||
cplciSendMessage(cplci, skb);
|
||||
break;
|
||||
|
||||
// for LISTEN state machine
|
||||
case CAPI_LISTEN_REQ:
|
||||
listenSendMessage(&appl->listen, skb);
|
||||
break;
|
||||
|
||||
// other
|
||||
case CAPI_FACILITY_REQ:
|
||||
applFacilityReq(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));
|
||||
if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_REQ)
|
||||
contrAnswerMessage(appl->contr, skb,
|
||||
CapiMessageNotSupportedInCurrentState);
|
||||
goto free;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
free:
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
void applFacilityReq(Appl_t *appl, struct sk_buff *skb)
|
||||
{
|
||||
_cmsg cmsg;
|
||||
Cplci_t *cplci;
|
||||
|
||||
capi_message2cmsg(&cmsg, skb->data);
|
||||
switch (cmsg.FacilitySelector) {
|
||||
case 0x0001: // DTMF
|
||||
cplci = applAdr2cplci(appl, CAPIMSG_CONTROL(skb->data));
|
||||
if (cplci && cplci->ncci) {
|
||||
ncciSendMessage(cplci->ncci, skb);
|
||||
return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
contrAnswerMessage(appl->contr, skb, CapiIllContrPlciNcci);
|
||||
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
|
||||
applSuppFacilityReq(appl, &cmsg);
|
||||
SupplementaryFacilityReq(appl, cmsg);
|
||||
break;
|
||||
default:
|
||||
int_error();
|
||||
contrAnswerMessage(appl->contr, skb, CapiFacilityNotSupported);
|
||||
SendCmsgAnswer2Application(appl, cmsg, CapiFacilityNotSupported);
|
||||
break;
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
Cplci_t *applNewCplci(Appl_t *appl, Plci_t *plci)
|
||||
void
|
||||
ApplicationSendMessage(Application_t *appl, struct sk_buff *skb)
|
||||
{
|
||||
Cplci_t *cplci;
|
||||
int i = (plci->adrPLCI >> 8);
|
||||
Plci_t *plci;
|
||||
AppPlci_t *aplci;
|
||||
__u16 ret;
|
||||
|
||||
if (appl->cplcis[i - 1]) {
|
||||
int_error();
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
cplci = kmalloc(sizeof(Cplci_t), GFP_ATOMIC);
|
||||
cplciConstr(cplci, appl, plci);
|
||||
appl->cplcis[i - 1] = cplci;
|
||||
plciAttachCplci(plci, cplci);
|
||||
return cplci;
|
||||
return;
|
||||
free:
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
void applDelCplci(Appl_t *appl, Cplci_t *cplci)
|
||||
AppPlci_t *
|
||||
ApplicationNewAppPlci(Application_t *appl, Plci_t *plci)
|
||||
{
|
||||
int i = cplci->adrPLCI >> 8;
|
||||
AppPlci_t *aplci;
|
||||
int plci_idx = (plci->addr >> 8) & 0xff;
|
||||
|
||||
if ((i < 1) || (i > CAPI_MAXPLCI)) {
|
||||
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->cplcis[i-1] != cplci) {
|
||||
if (appl->AppPlcis[plci_idx - 1] != aplci) {
|
||||
int_error();
|
||||
return;
|
||||
}
|
||||
cplciDestr(cplci);
|
||||
kfree(cplci);
|
||||
appl->cplcis[i-1] = NULL;
|
||||
appl->AppPlcis[plci_idx - 1] = NULL;
|
||||
if (test_bit(APPL_STATE_RELEASE, &appl->state) &&
|
||||
!test_bit(APPL_STATE_DESTRUCTOR, &appl->state))
|
||||
ApplicationDestr(appl, 0);
|
||||
}
|
||||
|
||||
#define CLASS_I4L 0x00
|
||||
#define FUNCTION_I4L_LEASED_IN 0x01
|
||||
#define FUNCTION_I4L_DEC_USE_COUNT 0x02
|
||||
#define FUNCTION_I4L_INC_USE_COUNT 0x03
|
||||
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;
|
||||
|
||||
#define CLASS_AVM 0x00
|
||||
#define FUNCTION_AVM_D2_TRACE 0x01
|
||||
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);
|
||||
}
|
||||
|
||||
struct I4LLeasedManuData {
|
||||
__u8 Length;
|
||||
__u8 BChannel;
|
||||
};
|
||||
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];
|
||||
};
|
||||
|
||||
struct ManufacturerReq {
|
||||
__u32 Class;
|
||||
__u32 Function;
|
||||
union {
|
||||
struct I4LLeasedManuData leased;
|
||||
struct AVMD2Trace d2trace;
|
||||
} f;
|
||||
};
|
||||
|
||||
void applManufacturerReqAVM(Appl_t *appl, struct sk_buff *skb)
|
||||
void applManufacturerReqAVM(Application_t *appl, _cmsg *cmsg, struct sk_buff *skb)
|
||||
{
|
||||
struct ManufacturerReq *manuReq;
|
||||
struct AVMD2Trace *at;
|
||||
|
||||
manuReq = (struct ManufacturerReq *)&skb->data[16];
|
||||
if (manuReq->Class != CLASS_AVM) {
|
||||
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown class %#x\n", manuReq->Class);
|
||||
goto out;
|
||||
}
|
||||
switch (manuReq->Function) {
|
||||
case FUNCTION_AVM_D2_TRACE:
|
||||
if (skb->len != 16 + 8 + 5)
|
||||
goto out;
|
||||
if (manuReq->f.d2trace.Length != 4)
|
||||
goto out;
|
||||
if (memcmp(manuReq->f.d2trace.data, "\200\014\000\000", 4) == 0) {
|
||||
test_and_set_bit(APPL_FLAG_D2TRACE, &appl->flags);
|
||||
} else if (memcmp(manuReq->f.d2trace.data, "\000\000\000\000", 4) == 0) {
|
||||
test_and_clear_bit(APPL_FLAG_D2TRACE, &appl->flags);
|
||||
} else {
|
||||
int_error();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown function %#x\n", manuReq->Function);
|
||||
}
|
||||
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
void applManufacturerReqI4L(Appl_t *appl, struct sk_buff *skb)
|
||||
{
|
||||
int bchannel;
|
||||
struct ManufacturerReq *manuReq;
|
||||
|
||||
manuReq = (struct ManufacturerReq *)&skb->data[16];
|
||||
if (manuReq->Class != CLASS_I4L) {
|
||||
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown class %#x\n", manuReq->Class);
|
||||
goto out;
|
||||
}
|
||||
switch (manuReq->Function) {
|
||||
case FUNCTION_I4L_LEASED_IN:
|
||||
if (skb->len < 16 + 8 + 2)
|
||||
goto out;
|
||||
if (manuReq->f.leased.Length != 2)
|
||||
goto out;
|
||||
bchannel = manuReq->f.leased.BChannel;
|
||||
if (bchannel < 1 || bchannel > 2)
|
||||
goto out;
|
||||
// FIXME
|
||||
// contrL4L3(appl->contr, CC_SETUP | INDICATION, &bchannel);
|
||||
break;
|
||||
case FUNCTION_I4L_DEC_USE_COUNT:
|
||||
break;
|
||||
case FUNCTION_I4L_INC_USE_COUNT:
|
||||
break;
|
||||
default:
|
||||
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown function %#x\n", manuReq->Function);
|
||||
}
|
||||
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
void applManufacturerReq(Appl_t *appl, struct sk_buff *skb)
|
||||
{
|
||||
if (skb->len < 16 + 8) {
|
||||
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;
|
||||
}
|
||||
if (memcmp(&skb->data[12], "AVM!", 4) == 0) {
|
||||
applManufacturerReqAVM(appl, skb);
|
||||
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);
|
||||
}
|
||||
if (memcmp(&skb->data[12], "I4L!", 4) == 0) {
|
||||
applManufacturerReqI4L(appl, skb);
|
||||
}
|
||||
return;
|
||||
cmsg_free(cmsg);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
void applD2Trace(Appl_t *appl, u_char *buf, int len)
|
||||
void applManufacturerReqmISDN(Application_t *appl, _cmsg *cmsg, struct sk_buff *skb)
|
||||
{
|
||||
_cmsg cmsg;
|
||||
__u8 manuData[255];
|
||||
AppPlci_t *aplci;
|
||||
Ncci_t *ncci;
|
||||
|
||||
if (!test_bit(APPL_FLAG_D2TRACE, &appl->flags))
|
||||
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;
|
||||
|
||||
memset(&cmsg, 0, sizeof(_cmsg));
|
||||
capi_cmsg_header(&cmsg, appl->ApplId, CAPI_MANUFACTURER, CAPI_IND,
|
||||
appl->MsgId++, appl->contr->adrController);
|
||||
cmsg.ManuID = 0x214D5641; // "AVM!"
|
||||
cmsg.Class = CLASS_AVM;
|
||||
cmsg.Function = FUNCTION_AVM_D2_TRACE;
|
||||
cmsg.ManuData = (_cstruct) &manuData;
|
||||
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);
|
||||
|
||||
contrRecvCmsg(appl->contr, &cmsg);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -8,20 +8,20 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define __NO_VERSION__
|
||||
#include "dchannel.h"
|
||||
#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(dchannel_t *dch) {
|
||||
add_arcofi_timer(channel_t *dch) {
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
if (test_and_set_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
|
||||
if (test_and_set_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
|
||||
del_timer(&isac->arcofitimer);
|
||||
}
|
||||
init_timer(&isac->arcofitimer);
|
||||
|
@ -30,7 +30,7 @@ add_arcofi_timer(dchannel_t *dch) {
|
|||
}
|
||||
|
||||
static void
|
||||
send_arcofi(dchannel_t *dch) {
|
||||
send_arcofi(channel_t *dch) {
|
||||
u_char val;
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
|
@ -46,23 +46,23 @@ send_arcofi(dchannel_t *dch) {
|
|||
}
|
||||
isac->mocr &= 0x0f;
|
||||
isac->mocr |= 0xa0;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
val = dch->read_reg(dch->inst.data, ISAC_MOSR);
|
||||
dch->write_reg(dch->inst.data, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
|
||||
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.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
}
|
||||
|
||||
int
|
||||
arcofi_fsm(dchannel_t *dch, int event, void *data) {
|
||||
arcofi_fsm(channel_t *dch, int event, void *data) {
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
if (dch->debug & L1_DEB_MONITOR) {
|
||||
debugprint(&dch->inst, "arcofi state %d event %d", isac->arcofi_state, event);
|
||||
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->DFlags);
|
||||
test_and_set_bit(FLG_ARCOFI_ERROR, &dch->Flags);
|
||||
wake_up(&isac->arcofi_wait);
|
||||
return(1);
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ arcofi_fsm(dchannel_t *dch, int event, void *data) {
|
|||
isac->arcofi_list->next;
|
||||
send_arcofi(dch);
|
||||
} else {
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
|
||||
del_timer(&isac->arcofitimer);
|
||||
}
|
||||
isac->arcofi_state = ARCOFI_NOP;
|
||||
|
@ -96,13 +96,20 @@ arcofi_fsm(dchannel_t *dch, int event, void *data) {
|
|||
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->DFlags)) {
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
|
||||
del_timer(&isac->arcofitimer);
|
||||
}
|
||||
isac->arcofi_state = ARCOFI_NOP;
|
||||
|
@ -111,28 +118,28 @@ arcofi_fsm(dchannel_t *dch, int event, void *data) {
|
|||
}
|
||||
break;
|
||||
default:
|
||||
debugprint(&dch->inst, "Arcofi unknown state %x", isac->arcofi_state);
|
||||
mISDN_debugprint(&dch->inst, "Arcofi unknown state %x", isac->arcofi_state);
|
||||
return(2);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void
|
||||
arcofi_timer(dchannel_t *dch) {
|
||||
arcofi_timer(channel_t *dch) {
|
||||
arcofi_fsm(dch, ARCOFI_TIMEOUT, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
clear_arcofi(dchannel_t *dch) {
|
||||
clear_arcofi(channel_t *dch) {
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
|
||||
del_timer(&isac->arcofitimer);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
init_arcofi(dchannel_t *dch) {
|
||||
init_arcofi(channel_t *dch) {
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
isac->arcofitimer.function = (void *) arcofi_timer;
|
||||
|
|
|
@ -27,6 +27,6 @@ struct arcofi_msg {
|
|||
u_char msg[10];
|
||||
};
|
||||
|
||||
extern int arcofi_fsm(dchannel_t *, int, void *);
|
||||
extern void init_arcofi(dchannel_t *);
|
||||
extern void clear_arcofi(dchannel_t *);
|
||||
extern int arcofi_fsm(channel_t *, int, void *);
|
||||
extern void init_arcofi(channel_t *);
|
||||
extern void clear_arcofi(channel_t *);
|
||||
|
|
|
@ -45,8 +45,8 @@ ParseASN1(u_char *p, u_char *end, int level)
|
|||
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_msg(PRT_DEBUG_DECODE, " ");
|
||||
print_msg(PRT_DEBUG_DECODE, "TAG 0x%02x LEN %3d\n", tag, len);
|
||||
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) {
|
||||
|
@ -65,15 +65,15 @@ ParseASN1(u_char *p, u_char *end, int level)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
for (j = 0; j < level*5; j++) print_msg(PRT_DEBUG_DECODE, " ");
|
||||
for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
|
||||
while (len--) {
|
||||
print_msg(PRT_DEBUG_DECODE, "%02x ", *p);
|
||||
print_asn1msg(PRT_DEBUG_DECODE, "%02x ", *p);
|
||||
p++;
|
||||
}
|
||||
print_msg(PRT_DEBUG_DECODE, "\n");
|
||||
print_asn1msg(PRT_DEBUG_DECODE, "\n");
|
||||
}
|
||||
for (j = 0; j < level*5; j++) print_msg(PRT_DEBUG_DECODE, " ");
|
||||
print_msg(PRT_DEBUG_DECODE, "END (%d)\n", p - beg - 2);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,13 @@ typedef enum {
|
|||
reject = 4,
|
||||
} asn1Component;
|
||||
|
||||
typedef enum {
|
||||
GeneralP = 0,
|
||||
InvokeP = 1,
|
||||
ReturnResultP= 2,
|
||||
ReturnErrorP = 3,
|
||||
} asn1Problem;
|
||||
|
||||
struct PublicPartyNumber {
|
||||
int publicTypeOfNumber;
|
||||
char numberDigits[30];
|
||||
|
@ -88,22 +95,30 @@ struct asn1ReturnError {
|
|||
__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_msg(dummy, fmt, args...) printk(fmt, ## args)
|
||||
#define print_asn1msg(dummy, fmt, args...) printk(KERN_DEBUG fmt, ## args)
|
||||
#else
|
||||
#define print_msg(dummy, fmt, args...)
|
||||
#define print_asn1msg(dummy, fmt, args...)
|
||||
#endif
|
||||
|
||||
int ParseASN1(u_char *p, u_char *end, int level);
|
||||
|
@ -146,7 +161,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
|
|||
int ret; \
|
||||
u_char *beg; \
|
||||
\
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> %s\n", __FUNCTION__); \
|
||||
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)); \
|
||||
|
@ -163,7 +178,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
|
|||
CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
|
||||
} else { \
|
||||
if (!((the_tag) & ASN1_TAG_OPT)) { \
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> err 1 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 1 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
return -1; \
|
||||
} \
|
||||
} \
|
||||
|
@ -176,7 +191,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
|
|||
CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
|
||||
} else { \
|
||||
if (!(the_tag) & ASN1_TAG_OPT) { \
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> err 2 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 2 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
return -1; \
|
||||
} \
|
||||
} \
|
||||
|
@ -185,7 +200,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
|
|||
CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
|
||||
} else { \
|
||||
if (!(the_tag) & ASN1_TAG_OPT) { \
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> err 3 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 3 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
return -1; \
|
||||
} \
|
||||
} \
|
||||
|
@ -193,8 +208,8 @@ int ParseLen(u_char *p, u_char *end, int *len);
|
|||
} \
|
||||
} else { \
|
||||
if (!(the_tag) & ASN1_TAG_OPT) { \
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> err 4 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
return -1; \
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 4 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
return -1; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
@ -222,7 +237,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
|
|||
#define XCHOICE(todo, act_tag, the_tag) XCHOICE_1(todo, act_tag, the_tag, -1)
|
||||
|
||||
#define XCHOICE_DEFAULT do {\
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> err 5 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 5 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
return -1; \
|
||||
} while (0)
|
||||
|
||||
|
|
|
@ -113,28 +113,90 @@ ParseReturnErrorComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dumm
|
|||
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_msg(PRT_DEBUG_DECODE, "ReturnError: %s\n", error);
|
||||
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;
|
||||
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
|
||||
|
@ -145,7 +207,17 @@ ParseComponent(struct asn1_parm *pc, u_char *p, u_char *end)
|
|||
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(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ ParseARGDeactivationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int
|
|||
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
|
||||
XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
|
||||
|
||||
print_msg(PRT_SHOWNUMBERS, "Deactivation Diversion %d (%d), \n",
|
||||
print_asn1msg(PRT_SHOWNUMBERS, "Deactivation Diversion %d (%d), \n",
|
||||
procedure, basicService);
|
||||
return p - beg;
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ ParseARGInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int
|
|||
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
|
||||
XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
|
||||
|
||||
print_msg(PRT_SHOWNUMBERS, "Interrogation Diversion %d (%d), \n",
|
||||
print_asn1msg(PRT_SHOWNUMBERS, "Interrogation Diversion %d (%d), \n",
|
||||
procedure, basicService);
|
||||
return p - beg;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ ParseARGInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int
|
|||
int
|
||||
ParseRESInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
|
||||
{
|
||||
print_msg(PRT_SHOWNUMBERS, "Interrogation Diversion Result\n");
|
||||
print_asn1msg(PRT_SHOWNUMBERS, "Interrogation Diversion Result\n");
|
||||
return ParseIntResultList(pc, p, end, &pc->u.retResult.o.resultList);
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ ParseRESInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int
|
|||
int
|
||||
ParseARGInterrogateServedUserNumbers(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
|
||||
{
|
||||
print_msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers\n");
|
||||
print_asn1msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -113,7 +113,7 @@ ParseRESInterrogateServedUserNumbers(struct asn1_parm *pc, u_char *p, u_char *en
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
print_msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers:\n");
|
||||
print_asn1msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers:\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ ParseARGDiversionInformation(struct asn1_parm *pc, u_char *p, u_char *end, int d
|
|||
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_msg(PRT_SHOWNUMBERS, "Diversion Information %s(%d) %s\n"
|
||||
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,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "capi.h"
|
||||
#include "m_capi.h"
|
||||
#include "helper.h"
|
||||
#include "asn1_enc.h"
|
||||
|
||||
|
@ -13,6 +13,14 @@ int encodeNull(__u8 *dest)
|
|||
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;
|
||||
|
@ -176,3 +184,18 @@ int encodeInterrogationDiversion(__u8 *dest, struct FacReqCFInterrogateParameter
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#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);
|
||||
|
@ -15,3 +16,4 @@ int encodeAddress(__u8 *dest, __u8 *facilityPartyNumber, __u8 *calledPartySubadd
|
|||
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);
|
||||
|
|
|
@ -19,7 +19,7 @@ ParseBoolean(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
|
|||
*i = (*i >> 8) + *p;
|
||||
p++;
|
||||
}
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> BOOL = %d %#x\n", *i, *i);
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> BOOL = %d %#x\n", *i, *i);
|
||||
return p - beg;
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ ParseInteger(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
|
|||
*i = (*i << 8) + *p;
|
||||
p++;
|
||||
}
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> INT = %d %#x\n", *i, *i);
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> INT = %d %#x\n", *i, *i);
|
||||
return p - beg;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ ParseEnum(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
|
|||
*i = (*i << 8) + *p;
|
||||
p++;
|
||||
}
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> ENUM = %d %#x\n", *i, *i);
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> ENUM = %d %#x\n", *i, *i);
|
||||
return p - beg;
|
||||
}
|
||||
|
||||
|
@ -67,14 +67,14 @@ ParseIA5String(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
|
|||
{
|
||||
INIT;
|
||||
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> IA5 = ");
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> IA5 = ");
|
||||
while (len--) {
|
||||
CHECK_P;
|
||||
print_msg(PRT_DEBUG_DECODE, "%c", *p);
|
||||
print_asn1msg(PRT_DEBUG_DECODE, "%c", *p);
|
||||
*str++ = *p;
|
||||
p++;
|
||||
}
|
||||
print_msg(PRT_DEBUG_DECODE, "\n");
|
||||
print_asn1msg(PRT_DEBUG_DECODE, "\n");
|
||||
*str = 0;
|
||||
return p - beg;
|
||||
}
|
||||
|
@ -85,14 +85,14 @@ ParseNumericString(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
|
|||
{
|
||||
INIT;
|
||||
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> NumStr = ");
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> NumStr = ");
|
||||
while (len--) {
|
||||
CHECK_P;
|
||||
print_msg(PRT_DEBUG_DECODE, "%c", *p);
|
||||
print_asn1msg(PRT_DEBUG_DECODE, "%c", *p);
|
||||
*str++ = *p;
|
||||
p++;
|
||||
}
|
||||
print_msg(PRT_DEBUG_DECODE, "\n");
|
||||
print_asn1msg(PRT_DEBUG_DECODE, "\n");
|
||||
*str = 0;
|
||||
return p - beg;
|
||||
}
|
||||
|
@ -102,14 +102,14 @@ ParseOctetString(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
|
|||
{
|
||||
INIT;
|
||||
|
||||
print_msg(PRT_DEBUG_DECODE, " DEBUG> Octets = ");
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> Octets = ");
|
||||
while (len--) {
|
||||
CHECK_P;
|
||||
print_msg(PRT_DEBUG_DECODE, " %02x", *p);
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " %02x", *p);
|
||||
*str++ = *p;
|
||||
p++;
|
||||
}
|
||||
print_msg(PRT_DEBUG_DECODE, "\n");
|
||||
print_asn1msg(PRT_DEBUG_DECODE, "\n");
|
||||
*str = 0;
|
||||
return p - beg;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,150 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Author Karsten Keil (keil@isdn4linux.de)
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#define __NO_VERSION__
|
||||
#include <linux/mISDNif.h>
|
||||
#include "layer1.h"
|
||||
#include "bchannel.h"
|
||||
#include "helper.h"
|
||||
|
||||
static void
|
||||
bchannel_bh(bchannel_t *bch)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u_int pr;
|
||||
int ret;
|
||||
mISDN_head_t *hh;
|
||||
mISDNif_t *hif;
|
||||
|
||||
if (!bch)
|
||||
return;
|
||||
if (!bch->inst.up.func) {
|
||||
printk(KERN_WARNING "%s: without up.func\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
printk(KERN_DEBUG "%s: event %x\n", __FUNCTION__, bch->event);
|
||||
if (bch->dev)
|
||||
printk(KERN_DEBUG "%s: rpflg(%x) wpflg(%x)\n", __FUNCTION__,
|
||||
bch->dev->rport.Flag, bch->dev->wport.Flag);
|
||||
#endif
|
||||
if (test_and_clear_bit(B_XMTBUFREADY, &bch->event)) {
|
||||
skb = bch->next_skb;
|
||||
if (skb) {
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
bch->next_skb = NULL;
|
||||
if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
|
||||
pr = DL_DATA | CONFIRM;
|
||||
else
|
||||
pr = PH_DATA | CONFIRM;
|
||||
if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
|
||||
&& bch->dev)
|
||||
hif = &bch->dev->rport.pif;
|
||||
else
|
||||
hif = &bch->inst.up;
|
||||
if (if_newhead(hif, pr, hh->dinfo, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
if (test_and_clear_bit(B_RCVBUFREADY, &bch->event)) {
|
||||
if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
|
||||
&& bch->dev)
|
||||
hif = &bch->dev->rport.pif;
|
||||
else
|
||||
hif = &bch->inst.up;
|
||||
while ((skb = skb_dequeue(&bch->rqueue))) {
|
||||
if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
|
||||
pr = DL_DATA | INDICATION;
|
||||
else
|
||||
pr = PH_DATA | INDICATION;
|
||||
ret = if_newhead(hif, pr, DINFO_SKB, skb);
|
||||
if (ret < 0) {
|
||||
printk(KERN_WARNING "%s: deliver err %d\n",
|
||||
__FUNCTION__, ret);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bch->hw_bh)
|
||||
bch->hw_bh(bch);
|
||||
}
|
||||
|
||||
int
|
||||
init_bchannel(bchannel_t *bch) {
|
||||
int devtyp = mISDN_RAW_DEVICE;
|
||||
|
||||
if (!(bch->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: No memory for blog\n");
|
||||
return(-ENOMEM);
|
||||
}
|
||||
if (!(bch->rx_buf = kmalloc(MAX_DATA_MEM, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: No memory for bchannel rx_buf\n");
|
||||
kfree(bch->blog);
|
||||
bch->blog = NULL;
|
||||
return (-ENOMEM);
|
||||
}
|
||||
if (!(bch->tx_buf = kmalloc(MAX_DATA_MEM, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: No memory for bchannel tx_buf\n");
|
||||
kfree(bch->blog);
|
||||
bch->blog = NULL;
|
||||
kfree(bch->rx_buf);
|
||||
bch->rx_buf = NULL;
|
||||
return (-ENOMEM);
|
||||
}
|
||||
skb_queue_head_init(&bch->rqueue);
|
||||
bch->next_skb = NULL;
|
||||
bch->Flag = 0;
|
||||
bch->event = 0;
|
||||
bch->rx_idx = 0;
|
||||
bch->tx_len = 0;
|
||||
bch->tx_idx = 0;
|
||||
bch->tqueue.data = bch;
|
||||
bch->tqueue.routine = (void *) (void *) bchannel_bh;
|
||||
bch->hw_bh = NULL;
|
||||
if (!bch->dev) {
|
||||
if (bch->inst.obj->ctrl(&bch->dev, MGR_GETDEVICE | REQUEST,
|
||||
&devtyp)) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: no raw device for bchannel\n");
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
free_bchannel(bchannel_t *bch) {
|
||||
|
||||
if (bch->tqueue.sync)
|
||||
printk(KERN_ERR"free_bchannel tqueue.sync\n");
|
||||
discard_queue(&bch->rqueue);
|
||||
if (bch->blog) {
|
||||
kfree(bch->blog);
|
||||
bch->blog = NULL;
|
||||
}
|
||||
if (bch->rx_buf) {
|
||||
kfree(bch->rx_buf);
|
||||
bch->rx_buf = NULL;
|
||||
}
|
||||
if (bch->tx_buf) {
|
||||
kfree(bch->tx_buf);
|
||||
bch->tx_buf = NULL;
|
||||
}
|
||||
if (bch->next_skb) {
|
||||
dev_kfree_skb(bch->next_skb);
|
||||
bch->next_skb = NULL;
|
||||
}
|
||||
if (bch->inst.obj->ctrl(bch->dev, MGR_DELDEVICE | REQUEST, NULL)) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: del raw device error\n");
|
||||
} else
|
||||
bch->dev = NULL;
|
||||
return(0);
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Basic declarations, defines for Bchannel hardware
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/mISDNif.h>
|
||||
#include <linux/tqueue.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/skbuff.h>
|
||||
#ifdef MEMDBG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
#define MAX_BLOG_SPACE 256
|
||||
|
||||
#define BC_FLG_INIT 1
|
||||
#define BC_FLG_ACTIV 2
|
||||
#define BC_FLG_TX_BUSY 3
|
||||
#define BC_FLG_NOFRAME 4
|
||||
#define BC_FLG_HALF 5
|
||||
#define BC_FLG_EMPTY 6
|
||||
#define BC_FLG_ORIG 7
|
||||
#define BC_FLG_DLEETX 8
|
||||
#define BC_FLG_LASTDLE 9
|
||||
#define BC_FLG_FIRST 10
|
||||
#define BC_FLG_LASTDATA 11
|
||||
#define BC_FLG_NMD_DATA 12
|
||||
#define BC_FLG_FTI_RUN 13
|
||||
#define BC_FLG_LL_OK 14
|
||||
#define BC_FLG_LL_CONN 15
|
||||
#define BC_FLG_TX_NEXT 16
|
||||
#define BC_FLG_DTMFSEND 17
|
||||
|
||||
typedef struct _bchannel_t {
|
||||
int channel;
|
||||
int protocol;
|
||||
int Flag;
|
||||
int debug;
|
||||
mISDNstack_t *st;
|
||||
mISDNinstance_t inst;
|
||||
mISDNdevice_t *dev;
|
||||
void *hw;
|
||||
u_char (*Read_Reg)(void *, int, u_char);
|
||||
void (*Write_Reg)(void *, int, u_char, u_char);
|
||||
struct sk_buff *next_skb;
|
||||
u_char *tx_buf;
|
||||
int tx_idx;
|
||||
int tx_len;
|
||||
u_char *rx_buf;
|
||||
int rx_idx;
|
||||
struct sk_buff_head rqueue; /* B-Channel receive Queue */
|
||||
u_char *blog;
|
||||
u_char *conmsg;
|
||||
struct timer_list transbusy;
|
||||
struct tq_struct tqueue;
|
||||
void (*hw_bh) (struct _bchannel_t *);
|
||||
int event;
|
||||
int err_crc;
|
||||
int err_tx;
|
||||
int err_rdo;
|
||||
int err_inv;
|
||||
} bchannel_t;
|
||||
|
||||
extern int init_bchannel(bchannel_t *);
|
||||
extern int free_bchannel(bchannel_t *);
|
||||
|
||||
static inline void
|
||||
bch_sched_event(bchannel_t *bch, int event)
|
||||
{
|
||||
test_and_set_bit(event, &bch->event);
|
||||
queue_task(&bch->tqueue, &tq_immediate);
|
||||
mark_bh(IMMEDIATE_BH);
|
||||
}
|
|
@ -3,9 +3,8 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include "capi.h"
|
||||
#include "core.h"
|
||||
#include "m_capi.h"
|
||||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
@ -14,7 +13,6 @@ static char *capi_revision = "$Revision$";
|
|||
static int debug = 0;
|
||||
static mISDNobject_t capi_obj;
|
||||
|
||||
|
||||
static char MName[] = "mISDN Capi 2.0";
|
||||
|
||||
#ifdef MODULE
|
||||
|
@ -22,8 +20,11 @@ MODULE_AUTHOR("Karsten Keil");
|
|||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
#ifdef OLD_MODULE_PARAM
|
||||
MODULE_PARM(debug, "1i");
|
||||
#define Capi20Init init_module
|
||||
#else
|
||||
module_param(debug, uint, S_IRUGO | S_IWUSR);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static char deb_buf[256];
|
||||
|
@ -40,222 +41,356 @@ void capidebug(int level, char *fmt, ...)
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// registration to kernelcapi
|
||||
#ifdef OLDCAPI_DRIVER_INTERFACE
|
||||
struct capi_driver_interface *cdrv_if;
|
||||
#endif
|
||||
|
||||
int mISDN_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
|
||||
kmem_cache_t *mISDN_cmsg_cp;
|
||||
kmem_cache_t *mISDN_AppPlci_cp;
|
||||
kmem_cache_t *mISDN_ncci_cp;
|
||||
kmem_cache_t *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)
|
||||
{
|
||||
Contr_t *contr = ctrl->driverdata;
|
||||
u_char *tmp;
|
||||
int retval;
|
||||
_kd_cmsg_t *ki = kmem_cache_alloc(mISDN_cmsg_cp, GFP_ATOMIC);
|
||||
|
||||
if (CAPI_DBG_INFO & debug) {
|
||||
printk(KERN_INFO "%s: firm user(%d) len(%d)\n", __FUNCTION__,
|
||||
data->firmware.user, data->firmware.len);
|
||||
printk(KERN_INFO "%s: cfg user(%d) len(%d)\n", __FUNCTION__,
|
||||
data->configuration.user, data->configuration.len);
|
||||
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;
|
||||
}
|
||||
if (data->firmware.user) {
|
||||
tmp = vmalloc(data->firmware.len);
|
||||
if (!tmp)
|
||||
return(-ENOMEM);
|
||||
retval = copy_from_user(tmp, data->firmware.data,
|
||||
data->firmware.len);
|
||||
if (retval)
|
||||
return(retval);
|
||||
} else
|
||||
tmp = data->firmware.data;
|
||||
contrLoadFirmware(contr, data->firmware.len, tmp);
|
||||
if (data->firmware.user)
|
||||
vfree(tmp);
|
||||
return 0;
|
||||
kdi = KDB_GET_KDI(cm);
|
||||
list_del(&kdi->head);
|
||||
kmem_cache_free(mISDN_cmsg_cp, kdi);
|
||||
}
|
||||
|
||||
void mISDN_reset_ctr(struct capi_ctr *ctrl)
|
||||
AppPlci_t *
|
||||
_kd_AppPlci_alloc(char *fn, int line)
|
||||
{
|
||||
Contr_t *contr = ctrl->driverdata;
|
||||
_kd_AppPlci_t *ki = kmem_cache_alloc(mISDN_AppPlci_cp, GFP_ATOMIC);
|
||||
|
||||
if (CAPI_DBG_INFO & debug)
|
||||
printk(KERN_DEBUG "%s\n", __FUNCTION__);
|
||||
contrReset(contr);
|
||||
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 mISDN_remove_ctr(struct capi_ctr *ctrl)
|
||||
void
|
||||
AppPlci_free(AppPlci_t *ap)
|
||||
{
|
||||
if (CAPI_DBG_INFO & debug)
|
||||
printk(KERN_DEBUG "%s\n", __FUNCTION__);
|
||||
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);
|
||||
}
|
||||
|
||||
static char *mISDN_procinfo(struct capi_ctr *ctrl)
|
||||
Ncci_t *
|
||||
_kd_ncci_alloc(char *fn, int line)
|
||||
{
|
||||
Contr_t *contr = (ctrl->driverdata);
|
||||
_kd_Ncci_t *ki = kmem_cache_alloc(mISDN_ncci_cp, GFP_ATOMIC);
|
||||
|
||||
if (CAPI_DBG_INFO & debug)
|
||||
printk(KERN_DEBUG "%s\n", __FUNCTION__);
|
||||
if (!contr)
|
||||
return "";
|
||||
sprintf(contr->infobuf, "-");
|
||||
return contr->infobuf;
|
||||
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 mISDN_register_appl(struct capi_ctr *ctrl,
|
||||
__u16 ApplId, capi_register_params *rp)
|
||||
void
|
||||
ncci_free(Ncci_t *ni)
|
||||
{
|
||||
Contr_t *contr = ctrl->driverdata;
|
||||
km_dbg_item_t *kdi;
|
||||
|
||||
if (CAPI_DBG_INFO & debug)
|
||||
printk(KERN_DEBUG "%s\n", __FUNCTION__);
|
||||
contrRegisterAppl(contr, ApplId, rp);
|
||||
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);
|
||||
}
|
||||
|
||||
void mISDN_release_appl(struct capi_ctr *ctrl, __u16 ApplId)
|
||||
SSProcess_t *
|
||||
_kd_SSProcess_alloc(char *fn, int line)
|
||||
{
|
||||
Contr_t *contr = ctrl->driverdata;
|
||||
_kd_SSProcess_t *ki = kmem_cache_alloc(mISDN_sspc_cp, GFP_ATOMIC);
|
||||
|
||||
if (CAPI_DBG_INFO & debug)
|
||||
printk(KERN_DEBUG "%s\n", __FUNCTION__);
|
||||
contrReleaseAppl(contr, ApplId);
|
||||
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 mISDN_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
|
||||
void
|
||||
SSProcess_free(SSProcess_t *sp)
|
||||
{
|
||||
Contr_t *contr = ctrl->driverdata;
|
||||
km_dbg_item_t *kdi;
|
||||
|
||||
contrSendMessage(contr, skb);
|
||||
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 int mISDN_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, struct capi_ctr *ctrl)
|
||||
static void
|
||||
free_garbage(void)
|
||||
{
|
||||
int len = 0;
|
||||
struct list_head *item, *next;
|
||||
_kd_all_t *kda;
|
||||
|
||||
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);
|
||||
};
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct capi_driver_interface *cdrv_if;
|
||||
#endif
|
||||
|
||||
struct capi_driver mISDN_driver = {
|
||||
"mISDN",
|
||||
"0.01",
|
||||
mISDN_load_firmware,
|
||||
mISDN_reset_ctr,
|
||||
mISDN_remove_ctr,
|
||||
mISDN_register_appl,
|
||||
mISDN_release_appl,
|
||||
mISDN_send_message,
|
||||
mISDN_procinfo,
|
||||
mISDN_read_proc,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
int CapiNew(void)
|
||||
static void CapiCachesFree(void)
|
||||
{
|
||||
printk(KERN_INFO "new %s instance\n", MName);
|
||||
#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_cplci();
|
||||
init_AppPlci();
|
||||
init_ncci();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
capi20_manager(void *data, u_int prim, void *arg) {
|
||||
mISDNinstance_t *inst = data;
|
||||
int found=0;
|
||||
BInst_t *binst = NULL;
|
||||
Contr_t *ctrl = (Contr_t *)capi_obj.ilist;
|
||||
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);
|
||||
while(ctrl) {
|
||||
spin_lock_irqsave(&capi_obj.lock, flags);
|
||||
list_for_each_entry(ctrl, &capi_obj.ilist, list) {
|
||||
if (&ctrl->inst == inst) {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
binst = ctrl->binst;
|
||||
while(binst) {
|
||||
if (&binst->inst == inst) {
|
||||
list_for_each_entry(plink, &ctrl->linklist, list) {
|
||||
if (&plink->inst == inst) {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
binst = binst->next;
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
ctrl = ctrl->next;
|
||||
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_NEWLAYER | REQUEST:
|
||||
if (!(ctrl = newContr(&capi_obj, data, arg)))
|
||||
return(-EINVAL);
|
||||
else
|
||||
ctrl->debug = debug;
|
||||
break;
|
||||
case MGR_CONNECT | REQUEST:
|
||||
if (!ctrl) {
|
||||
if (CAPI_DBG_WARN & debug)
|
||||
printk(KERN_WARNING "capi20_manager connect no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
return(ConnectIF(inst, arg));
|
||||
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) {
|
||||
if (CAPI_DBG_WARN & debug)
|
||||
printk(KERN_WARNING "capi20_manager setif no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
if (&ctrl->inst == inst)
|
||||
return(SetIF(inst, arg, prim, NULL, contrL3L4, ctrl));
|
||||
return(mISDN_SetIF(inst, arg, prim, NULL, ControllerL3L4, ctrl));
|
||||
else
|
||||
return(SetIF(inst, arg, prim, NULL, ncci_l3l4, inst->data));
|
||||
break;
|
||||
return(AppPlcimISDN_SetIF(inst->data, prim, arg));
|
||||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
if (!ctrl) {
|
||||
if (CAPI_DBG_WARN & debug)
|
||||
printk(KERN_WARNING "capi20_manager disconnect no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
return(DisConnectIF(inst, arg));
|
||||
break;
|
||||
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 (ctrl) {
|
||||
if (CAPI_DBG_INFO & debug)
|
||||
printk(KERN_DEBUG "release_capi20 id %x\n", ctrl->inst.st->id);
|
||||
contrDestr(ctrl);
|
||||
kfree(ctrl);
|
||||
} else if (CAPI_DBG_WARN & debug)
|
||||
printk(KERN_WARNING "capi20_manager release no instance\n");
|
||||
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 (!ctrl) {
|
||||
if (CAPI_DBG_WARN & debug)
|
||||
printk(KERN_WARNING "capi20_manager unreglayer no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
if (binst) {
|
||||
capi_obj.ctrl(binst->inst.down.peer, MGR_DISCONNECT | REQUEST,
|
||||
&binst->inst.down);
|
||||
capi_obj.ctrl(&binst->inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
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)
|
||||
if (CAPI_DBG_WARN & debug)
|
||||
printk(KERN_WARNING "capi20_manager prim %x not handled\n", prim);
|
||||
return(-EINVAL);
|
||||
}
|
||||
|
@ -267,46 +402,59 @@ int Capi20Init(void)
|
|||
int err;
|
||||
|
||||
printk(KERN_INFO "%s driver file version %s\n", MName, mISDN_getrev(capi_revision));
|
||||
SET_MODULE_OWNER(&capi_obj);
|
||||
#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;
|
||||
capi_obj.prev = NULL;
|
||||
capi_obj.next = NULL;
|
||||
capi_obj.ilist = NULL;
|
||||
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_cplci();
|
||||
free_AppPlci();
|
||||
free_ncci();
|
||||
}
|
||||
free_Application();
|
||||
} else
|
||||
mISDN_module_register(THIS_MODULE);
|
||||
return(err);
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
void cleanup_module(void)
|
||||
static void Capi20cleanup(void)
|
||||
{
|
||||
int err;
|
||||
Contr_t *contr;
|
||||
int err;
|
||||
Controller_t *contr, *next;
|
||||
|
||||
mISDN_module_unregister(THIS_MODULE);
|
||||
|
||||
if ((err = mISDN_unregister(&capi_obj))) {
|
||||
printk(KERN_ERR "Can't unregister User DSS1 error(%d)\n", err);
|
||||
printk(KERN_ERR "Can't unregister CAPI20 error(%d)\n", err);
|
||||
}
|
||||
if (capi_obj.ilist) {
|
||||
printk(KERN_WARNING "mISDNl3 contrlist not empty\n");
|
||||
while((contr = capi_obj.ilist)) {
|
||||
contrDestr(contr);
|
||||
kfree(contr);
|
||||
}
|
||||
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_cplci();
|
||||
free_AppPlci();
|
||||
free_ncci();
|
||||
}
|
||||
|
||||
module_init(Capi20Init);
|
||||
module_exit(Capi20cleanup);
|
||||
#endif
|
||||
|
|
|
@ -1,382 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#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>
|
||||
#include "../avmb1/capiutil.h"
|
||||
#include "../avmb1/capicmd.h"
|
||||
#include "../avmb1/capilli.h"
|
||||
#include "asn1.h"
|
||||
#include "fsm.h"
|
||||
#ifdef MEMDBG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// common stuff
|
||||
|
||||
#define CAPI_DBG_WARN 0x00000001
|
||||
#define CAPI_DBG_INFO 0x00000004
|
||||
#define CAPI_DBG_APPL 0x00000010
|
||||
#define CAPI_DBG_APPL_INFO 0x00000040
|
||||
#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_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
|
||||
|
||||
extern struct capi_driver_interface *cdrv_if;
|
||||
extern struct capi_driver mISDN_driver;
|
||||
|
||||
void init_listen(void);
|
||||
void init_cplci(void);
|
||||
void init_ncci(void);
|
||||
void free_listen(void);
|
||||
void free_cplci(void);
|
||||
void free_ncci(void);
|
||||
void capidebug(int, char *, ...);
|
||||
|
||||
#define SuppServiceCF 0x00000010
|
||||
#define SuppServiceTP 0x00000002
|
||||
#define mISDNSupportedServices (SuppServiceCF | SuppServiceTP)
|
||||
|
||||
#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 5
|
||||
#define CAPI_MAXDUMMYPCS 16
|
||||
|
||||
struct Bprotocol {
|
||||
__u16 B1protocol;
|
||||
__u16 B2protocol;
|
||||
__u16 B3protocol;
|
||||
};
|
||||
|
||||
__u16 q931CIPValue(Q931_info_t *);
|
||||
|
||||
typedef struct _DummyProcess {
|
||||
__u16 invokeId;
|
||||
__u16 Function;
|
||||
__u32 Handle;
|
||||
__u32 adrDummy;
|
||||
__u16 ApplId;
|
||||
struct _Contr *contr;
|
||||
struct timer_list tl;
|
||||
__u8 buf[128];
|
||||
} DummyProcess_t;
|
||||
|
||||
void dummyPcConstr(DummyProcess_t *dummy_pc, struct _Contr *contr, __u16 invokeId);
|
||||
void dummyPcDestr(DummyProcess_t *dummy_pc);
|
||||
void dummyPcAddTimer(DummyProcess_t *dummy_pc, int msec);
|
||||
|
||||
int capiEncodeFacIndSuspend(__u8 *dest, __u16 SupplementaryServiceReason);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#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;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct FacConfGetSupportedServices {
|
||||
__u16 SupplementaryServiceInfo;
|
||||
__u32 SupportedServices;
|
||||
};
|
||||
|
||||
struct FacConfInfo {
|
||||
__u16 SupplementaryServiceInfo;
|
||||
};
|
||||
|
||||
struct FacConfParm {
|
||||
__u16 Function;
|
||||
union {
|
||||
struct FacConfGetSupportedServices GetSupportedServices;
|
||||
struct FacConfInfo Info;
|
||||
} u;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// struct Contr
|
||||
|
||||
typedef struct _BInst {
|
||||
struct _BInst *prev;
|
||||
struct _BInst *next;
|
||||
mISDNstack_t *bst;
|
||||
mISDNinstance_t inst;
|
||||
} BInst_t;
|
||||
|
||||
typedef struct _Contr {
|
||||
struct _Contr *prev;
|
||||
struct _Contr *next;
|
||||
mISDNinstance_t inst;
|
||||
BInst_t *binst;
|
||||
struct capi_ctr *ctrl;
|
||||
__u32 adrController;
|
||||
int b3_mode;
|
||||
u_int debug;
|
||||
char infobuf[128];
|
||||
char msgbuf[128];
|
||||
struct _Plci *plcis[CAPI_MAXPLCI];
|
||||
struct _Appl *appls[CAPI_MAXAPPL];
|
||||
DummyProcess_t *dummy_pcs[CAPI_MAXDUMMYPCS];
|
||||
__u16 lastInvokeId;
|
||||
} Contr_t;
|
||||
|
||||
Contr_t *newContr(mISDNobject_t *, mISDNstack_t *, mISDN_pid_t *);
|
||||
int contrConstr(Contr_t *, mISDNstack_t *, mISDN_pid_t *, mISDNobject_t *);
|
||||
void contrDestr(Contr_t *contr);
|
||||
void contrDebug(Contr_t *contr, __u32 level, char *fmt, ...);
|
||||
void contrRegisterAppl(Contr_t *contr, __u16 ApplId, capi_register_params *rp);
|
||||
void contrReleaseAppl(Contr_t *contr, __u16 ApplId);
|
||||
void contrSendMessage(Contr_t *contr, struct sk_buff *skb);
|
||||
void contrLoadFirmware(Contr_t *, int, void *);
|
||||
void contrReset(Contr_t *contr);
|
||||
void contrRecvCmsg(Contr_t *contr, _cmsg *cmsg);
|
||||
void contrAnswerCmsg(Contr_t *contr, _cmsg *cmsg, __u16 Info);
|
||||
void contrAnswerMessage(Contr_t *contr, struct sk_buff *skb, __u16 Info);
|
||||
struct _Plci *contrNewPlci(Contr_t *contr);
|
||||
struct _Appl *contrId2appl(Contr_t *contr, __u16 ApplId);
|
||||
struct _Plci *contrAdr2plci(Contr_t *contr, __u32 adr);
|
||||
void contrDelPlci(Contr_t *contr, struct _Plci *plci);
|
||||
int contrDummyInd(Contr_t *, __u32, struct sk_buff *);
|
||||
DummyProcess_t *contrNewDummyPc(Contr_t *contr);
|
||||
DummyProcess_t *contrId2DummyPc(Contr_t *contr, __u16 invokeId);
|
||||
int contrL4L3(Contr_t *, u_int, int, struct sk_buff *);
|
||||
int contrL3L4(mISDNif_t *, struct sk_buff *);
|
||||
BInst_t *contrSelChannel(Contr_t *, u_int);
|
||||
// ---------------------------------------------------------------------------
|
||||
// struct Listen
|
||||
|
||||
#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)
|
||||
|
||||
typedef struct _Listen {
|
||||
Contr_t *contr;
|
||||
__u16 ApplId;
|
||||
__u32 InfoMask;
|
||||
__u32 CIPmask;
|
||||
__u32 CIPmask2;
|
||||
struct FsmInst listen_m;
|
||||
} Listen_t;
|
||||
|
||||
void listenConstr(Listen_t *listen, Contr_t *contr, __u16 ApplId);
|
||||
void listenDestr(Listen_t *listen);
|
||||
void listenDebug(Listen_t *listen, __u32 level, char *fmt, ...);
|
||||
void listenSendMessage(Listen_t *listen, struct sk_buff *skb);
|
||||
int listenHandle(Listen_t *listen, __u16 CIPValue);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// struct Appl
|
||||
|
||||
#define APPL_FLAG_D2TRACE 1
|
||||
|
||||
typedef struct _Appl {
|
||||
Contr_t *contr;
|
||||
__u16 ApplId;
|
||||
__u16 MsgId;
|
||||
Listen_t listen;
|
||||
struct _Cplci *cplcis[CAPI_MAXPLCI];
|
||||
__u32 NotificationMask;
|
||||
int flags;
|
||||
capi_register_params rp;
|
||||
} Appl_t;
|
||||
|
||||
void applConstr(Appl_t *appl, Contr_t *contr, __u16 ApplId, capi_register_params *rp);
|
||||
void applDestr(Appl_t *appl);
|
||||
void applDebug(Appl_t *appl, __u32 level, char *fmt, ...);
|
||||
void applSendMessage(Appl_t *appl, struct sk_buff *skb);
|
||||
void applFacilityReq(Appl_t *appl, struct sk_buff *skb);
|
||||
void applSuppFacilityReq(Appl_t *appl, _cmsg *cmsg);
|
||||
int applGetSupportedServices(Appl_t *appl, struct FacReqParm *facReqParm,
|
||||
struct FacConfParm *facConfParm);
|
||||
int applFacListen(Appl_t *appl, struct FacReqParm *facReqParm,
|
||||
struct FacConfParm *facConfParm);
|
||||
int applFacCFActivate(Appl_t *appl, struct FacReqParm *facReqParm,
|
||||
struct FacConfParm *facConfParm);
|
||||
int applFacCFDeactivate(Appl_t *appl, struct FacReqParm *facReqParm,
|
||||
struct FacConfParm *facConfParm);
|
||||
int applFacCFInterrogateNumbers(Appl_t *appl, struct FacReqParm *facReqParm,
|
||||
struct FacConfParm *facConfParm);
|
||||
int applFacCFInterrogateParameters(Appl_t *appl, struct FacReqParm *facReqParm,
|
||||
struct FacConfParm *facConfParm);
|
||||
void applManufacturerReq(Appl_t *appl, struct sk_buff *skb);
|
||||
void applD2Trace(Appl_t *appl, u_char *buf, int len);
|
||||
DummyProcess_t *applNewDummyPc(Appl_t *appl, __u16 Function, __u32 Handle);
|
||||
struct _Cplci *applNewCplci(Appl_t *appl, struct _Plci *plci);
|
||||
struct _Cplci *applAdr2cplci(Appl_t *appl, __u32 adr);
|
||||
void applDelCplci(Appl_t *appl, struct _Cplci *cplci);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// struct Plci
|
||||
|
||||
#define PLCI_FLAG_ALERTING 1
|
||||
#define PLCI_FLAG_OUTGOING 2
|
||||
|
||||
typedef struct _Plci {
|
||||
Contr_t *contr;
|
||||
__u32 adrPLCI;
|
||||
int flags;
|
||||
int nAppl;
|
||||
struct _Cplci *cplcis[CAPI_MAXAPPL];
|
||||
} Plci_t;
|
||||
|
||||
void plciConstr(Plci_t *plci, Contr_t *contr, __u32 adrPLCI);
|
||||
void plciDestr(Plci_t *plci);
|
||||
void plciDebug(Plci_t *plci, __u32 level, char *fmt, ...);
|
||||
int plci_l3l4(Plci_t *, int, struct sk_buff *);
|
||||
void plciAttachCplci(Plci_t *plci, struct _Cplci *cplci);
|
||||
void plciDetachCplci(Plci_t *plci, struct _Cplci *cplci);
|
||||
void plciNewCrInd(Plci_t *plci, void *);
|
||||
void plciNewCrReq(Plci_t *plci);
|
||||
int plciL4L3(Plci_t *, __u32, struct sk_buff *);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// struct Cplci
|
||||
|
||||
typedef struct _Cplci {
|
||||
__u32 adrPLCI;
|
||||
Plci_t *plci;
|
||||
Appl_t *appl;
|
||||
struct _Ncci *ncci;
|
||||
Contr_t *contr;
|
||||
struct FsmInst plci_m;
|
||||
u_char cause[4]; // we may get a cause from l3 DISCONNECT message
|
||||
// which we'll need send in DISCONNECT_IND caused by
|
||||
// l3 RELEASE message
|
||||
u_int bchannel;
|
||||
struct Bprotocol Bprotocol;
|
||||
} Cplci_t;
|
||||
|
||||
void cplciConstr(Cplci_t *cplci, Appl_t *appl, Plci_t *plci);
|
||||
void cplciDestr(Cplci_t *cplci);
|
||||
void cplciDebug(Cplci_t *cplci, __u32 level, char *fmt, ...);
|
||||
void cplci_l3l4(Cplci_t *cplci, int pr, void *arg);
|
||||
void cplciSendMessage(Cplci_t *cplci, struct sk_buff *skb);
|
||||
void cplciClearOtherApps(Cplci_t *cplci);
|
||||
void cplciInfoIndMsg(Cplci_t *, __u32, unsigned char);
|
||||
void cplciInfoIndIE(Cplci_t *, unsigned char, __u32, Q931_info_t *);
|
||||
void cplciRecvCmsg(Cplci_t *cplci, _cmsg *cmsg);
|
||||
void cplciCmsgHeader(Cplci_t *cplci, _cmsg *cmsg, __u8 cmd, __u8 subcmd);
|
||||
void cplciLinkUp(Cplci_t *cplci);
|
||||
void cplciLinkDown(Cplci_t *cplci);
|
||||
int cplciFacSuspendReq(Cplci_t *cplci, struct FacReqParm *facReqParm,
|
||||
struct FacConfParm *facConfParm);
|
||||
int cplciFacResumeReq(Cplci_t *cplci, struct FacReqParm *facReqParm,
|
||||
struct FacConfParm *facConfParm);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Ncci_t
|
||||
|
||||
typedef struct _Ncci {
|
||||
BInst_t *binst;
|
||||
__u32 adrNCCI;
|
||||
Contr_t *contr;
|
||||
Cplci_t *cplci;
|
||||
Appl_t *appl;
|
||||
struct FsmInst ncci_m;
|
||||
int window;
|
||||
u_long Flags;
|
||||
struct {
|
||||
struct sk_buff *skb;
|
||||
__u16 DataHandle;
|
||||
__u16 MsgId;
|
||||
} xmit_skb_handles[CAPI_MAXDATAWINDOW];
|
||||
struct sk_buff *recv_skb_handles[CAPI_MAXDATAWINDOW];
|
||||
struct sk_buff_head squeue;
|
||||
_cmsg tmpmsg;
|
||||
} Ncci_t;
|
||||
|
||||
#define NCCI_FLG_FCTRL 1
|
||||
#define NCCI_FLG_BUSY 2
|
||||
|
||||
void ncciConstr(Ncci_t *ncci, Cplci_t *cplci);
|
||||
void ncciDestr(Ncci_t *ncci);
|
||||
void ncciSendMessage(Ncci_t *, struct sk_buff *);
|
||||
int ncci_l3l4(mISDNif_t *, struct sk_buff *);
|
||||
void ncciLinkUp(Ncci_t *ncci);
|
||||
void ncciLinkDown(Ncci_t *ncci);
|
||||
void ncciInitSt(Ncci_t *ncci);
|
||||
void ncciReleaseSt(Ncci_t *ncci);
|
||||
__u16 ncciSelectBprotocol(Ncci_t *ncci);
|
||||
void ncciRecvCmsg(Ncci_t *ncci, _cmsg *cmsg);
|
||||
void ncciCmsgHeader(Ncci_t *ncci, _cmsg *cmsg, __u8 cmd, __u8 subcmd);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "capi.h"
|
||||
#include "m_capi.h"
|
||||
#include "asn1.h"
|
||||
|
||||
int capiEncodeWord(__u8 *p, __u16 i)
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Author (c) Karsten Keil <kkeil@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);
|
|
@ -0,0 +1,163 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Basic declarations for a mISDN HW channel
|
||||
*
|
||||
* Author (c) Karsten Keil <kkeil@suse.de>
|
||||
*
|
||||
* This file is released under the GPLv2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MISDN_CHANNEL_H
|
||||
#define MISDN_CHANNEL_H
|
||||
#include <linux/mISDNif.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include "helper.h"
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
#ifdef CONFIG_MISDN_NETDEV
|
||||
#include "core.h"
|
||||
#endif
|
||||
|
||||
#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
|
||||
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
|
||||
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
|
||||
queue_ch_frame(ch, CONFIRM, di, NULL);
|
||||
return(skb->len);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -8,8 +8,8 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include "core.h"
|
||||
#ifdef CONFIG_KMOD
|
||||
#include <linux/kmod.h>
|
||||
|
@ -18,12 +18,25 @@
|
|||
#include <linux/smp_lock.h>
|
||||
#endif
|
||||
|
||||
static char *mISDN_core_revision = "$Revision$";
|
||||
static char *mISDN_core_revision = "$Revision$";
|
||||
static char *mISDN_core_version = MISDNVERSION ;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
mISDNobject_t *mISDN_objects = NULL;
|
||||
int core_debug;
|
||||
|
||||
static int debug;
|
||||
static u_char entityarray[MISDN_MAX_ENTITY/8];
|
||||
static spinlock_t entity_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static uint debug;
|
||||
static int obj_id;
|
||||
|
||||
#ifdef MODULE
|
||||
|
@ -31,10 +44,12 @@ MODULE_AUTHOR("Karsten Keil");
|
|||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
#ifdef OLD_MODULE_PARAM
|
||||
MODULE_PARM(debug, "1i");
|
||||
EXPORT_SYMBOL(mISDN_register);
|
||||
EXPORT_SYMBOL(mISDN_unregister);
|
||||
#define mISDNInit init_module
|
||||
#else
|
||||
module_param (debug, uint, S_IRUGO | S_IWUSR);
|
||||
#endif
|
||||
MODULE_PARM_DESC (debug, "mISDN core debug mask");
|
||||
#endif
|
||||
|
||||
typedef struct _mISDN_thread {
|
||||
|
@ -42,14 +57,14 @@ typedef struct _mISDN_thread {
|
|||
struct task_struct *thread;
|
||||
wait_queue_head_t waitq;
|
||||
struct semaphore *notify;
|
||||
u_int Flags;
|
||||
u_long Flags;
|
||||
struct sk_buff_head workq;
|
||||
} mISDN_thread_t;
|
||||
|
||||
#define mISDN_TFLAGS_STARTED 1
|
||||
#define mISDN_TFLAGS_RMMOD 2
|
||||
#define mISDN_TFLAGS_ACTIV 3
|
||||
#define mISDN_TFLAGS_TEST 4
|
||||
#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;
|
||||
|
||||
|
@ -75,14 +90,13 @@ mISDNd(void *data)
|
|||
#ifdef CONFIG_SMP
|
||||
lock_kernel();
|
||||
#endif
|
||||
daemonize();
|
||||
MAKEDAEMON("mISDNd");
|
||||
sigfillset(¤t->blocked);
|
||||
strcpy(current->comm,"mISDNd");
|
||||
hkt->thread = current;
|
||||
#ifdef CONFIG_SMP
|
||||
unlock_kernel();
|
||||
#endif
|
||||
printk(KERN_DEBUG "mISDNd: kernel daemon started\n");
|
||||
printk(KERN_DEBUG "mISDNd: kernel daemon started (current:%p)\n", current);
|
||||
|
||||
test_and_set_bit(mISDN_TFLAGS_STARTED, &hkt->Flags);
|
||||
|
||||
|
@ -95,37 +109,40 @@ mISDNd(void *data)
|
|||
break;
|
||||
if (hkt->notify != NULL)
|
||||
up(hkt->notify);
|
||||
interruptible_sleep_on(&hkt->waitq);
|
||||
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->what) {
|
||||
switch (hhe->addr) {
|
||||
case MGR_FUNCTION:
|
||||
err=hhe->func.ctrl(hhe->data[0], hhe->prim, skb->data);
|
||||
err = hhe->func.ctrl(hhe->data[0], hhe->prim,
|
||||
skb->len ? skb->data : NULL);
|
||||
if (err) {
|
||||
printk(KERN_WARNING "mISDNd: what(%x) prim(%x) failed err(%x)\n",
|
||||
hhe->what, hhe->prim, 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: what(%x) prim(%x) success\n",
|
||||
hhe->what, hhe->prim);
|
||||
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: what(%x) prim(%x) failed err(%x)\n",
|
||||
hhe->what, hhe->prim, 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: what(%x) prim(%x) unknown\n",
|
||||
hhe->what, hhe->prim);
|
||||
printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) unknown\n",
|
||||
hhe->addr, hhe->prim);
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
@ -137,7 +154,7 @@ mISDNd(void *data)
|
|||
printk(KERN_DEBUG "mISDNd: test event done\n");
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "mISDNd: daemon exit now\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);
|
||||
|
@ -149,37 +166,44 @@ mISDNd(void *data)
|
|||
|
||||
mISDNobject_t *
|
||||
get_object(int id) {
|
||||
mISDNobject_t *obj = mISDN_objects;
|
||||
mISDNobject_t *obj;
|
||||
|
||||
while(obj) {
|
||||
if (obj->id == id)
|
||||
read_lock(&mISDN_objects_lock);
|
||||
list_for_each_entry(obj, &mISDN_objectlist, list)
|
||||
if (obj->id == id) {
|
||||
read_unlock(&mISDN_objects_lock);
|
||||
return(obj);
|
||||
obj = obj->next;
|
||||
}
|
||||
}
|
||||
read_unlock(&mISDN_objects_lock);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
static mISDNobject_t *
|
||||
find_object(int protocol) {
|
||||
mISDNobject_t *obj = mISDN_objects;
|
||||
int err;
|
||||
mISDNobject_t *obj;
|
||||
int err;
|
||||
|
||||
while (obj) {
|
||||
read_lock(&mISDN_objects_lock);
|
||||
list_for_each_entry(obj, &mISDN_objectlist, list) {
|
||||
err = obj->own_ctrl(NULL, MGR_HASPROTOCOL | REQUEST, &protocol);
|
||||
if (!err)
|
||||
return(obj);
|
||||
goto unlock;
|
||||
if (err != -ENOPROTOOPT) {
|
||||
if (0 == HasProtocol(obj, protocol))
|
||||
return(obj);
|
||||
if (0 == mISDN_HasProtocol(obj, protocol))
|
||||
goto unlock;
|
||||
}
|
||||
obj = obj->next;
|
||||
}
|
||||
return(NULL);
|
||||
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;
|
||||
|
||||
|
@ -188,8 +212,8 @@ find_object_module(int protocol) {
|
|||
#ifdef CONFIG_KMOD
|
||||
if (debug)
|
||||
printk(KERN_DEBUG
|
||||
"find_object_module %s - trying to load in_irq(%d)\n",
|
||||
m->name, in_interrupt());
|
||||
"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",
|
||||
|
@ -209,31 +233,7 @@ find_object_module(int protocol) {
|
|||
return(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_object(mISDNobject_t *obj) {
|
||||
mISDNstack_t *st = mISDN_stacklist;
|
||||
mISDNlayer_t *layer;
|
||||
mISDNinstance_t *inst, *tmp;
|
||||
|
||||
while (st) {
|
||||
layer = st->lstack;
|
||||
while(layer) {
|
||||
inst = layer->inst;
|
||||
while (inst) {
|
||||
if (inst->obj == obj) {
|
||||
tmp = inst->next;
|
||||
inst->obj->own_ctrl(st, MGR_RELEASE
|
||||
| INDICATION, inst);
|
||||
inst = tmp;
|
||||
} else
|
||||
inst = inst->next;
|
||||
}
|
||||
layer = layer->next;
|
||||
}
|
||||
st = st->next;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FIXME
|
||||
static int
|
||||
dummy_if(mISDNif_t *hif, struct sk_buff *skb)
|
||||
{
|
||||
|
@ -251,6 +251,7 @@ dummy_if(mISDNif_t *hif, struct sk_buff *skb)
|
|||
dev_kfree_skb_any(skb);
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
mISDNinstance_t *
|
||||
get_next_instance(mISDNstack_t *st, mISDN_pid_t *pid)
|
||||
|
@ -260,7 +261,7 @@ get_next_instance(mISDNstack_t *st, mISDN_pid_t *pid)
|
|||
int layer, proto;
|
||||
mISDNobject_t *obj;
|
||||
|
||||
layer = get_lowlayer(pid->layermask);
|
||||
layer = mISDN_get_lowlayer(pid->layermask);
|
||||
proto = pid->protocol[layer];
|
||||
next = get_instance(st, layer, proto);
|
||||
if (!next) {
|
||||
|
@ -287,7 +288,7 @@ get_next_instance(mISDNstack_t *st, mISDN_pid_t *pid)
|
|||
static int
|
||||
sel_channel(mISDNstack_t *st, channel_info_t *ci)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (!ci)
|
||||
return(err);
|
||||
|
@ -305,26 +306,37 @@ sel_channel(mISDNstack_t *st, channel_info_t *ci)
|
|||
printk(KERN_WARNING "%s: no mgr st(%p)\n", __FUNCTION__, st);
|
||||
}
|
||||
if (err) {
|
||||
mISDNstack_t *cst = st->child;
|
||||
int nr = 0;
|
||||
mISDNstack_t *cst;
|
||||
u_int nr = 0;
|
||||
|
||||
ci->st.p = NULL;
|
||||
if (!(ci->channel & (~CHANNEL_NUMBER))) {
|
||||
/* only number is set */
|
||||
while(cst) {
|
||||
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;
|
||||
err = 0;
|
||||
break;
|
||||
return(0);
|
||||
}
|
||||
cst = cst->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(err);
|
||||
}
|
||||
|
||||
#ifdef FIXME
|
||||
static int
|
||||
disconnect_if(mISDNinstance_t *inst, u_int prim, mISDNif_t *hif) {
|
||||
int err = 0;
|
||||
|
@ -354,10 +366,14 @@ add_if(mISDNinstance_t *inst, u_int prim, mISDNif_t *hif) {
|
|||
myif = &inst->up;
|
||||
} else
|
||||
return(-EINVAL);
|
||||
APPEND_TO_LIST(hif, myif);
|
||||
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
|
||||
|
@ -381,27 +397,132 @@ get_hdevice(mISDNdevice_t **dev, int *typ)
|
|||
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->what = prim;
|
||||
hhe->addr = prim;
|
||||
skb_queue_tail(&mISDN_thread.workq, skb);
|
||||
wake_up_interruptible(&mISDN_thread.waitq);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int central_manager(void *data, u_int prim, void *arg) {
|
||||
#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) {
|
||||
|
@ -409,6 +530,11 @@ static int central_manager(void *data, u_int prim, void *arg) {
|
|||
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:
|
||||
|
@ -419,55 +545,65 @@ static int central_manager(void *data, u_int prim, void *arg) {
|
|||
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 */
|
||||
if (in_interrupt()) {
|
||||
struct sk_buff *skb;
|
||||
mISDN_headext_t *hhe;
|
||||
|
||||
skb = alloc_skb(sizeof(mISDN_pid_t), GFP_ATOMIC);
|
||||
hhe = mISDN_HEADEXT_P(skb);
|
||||
hhe->prim = prim;
|
||||
hhe->what = MGR_FUNCTION;
|
||||
hhe->data[0] = st;
|
||||
/* FIXME: handling of optional pid parameters */
|
||||
memcpy(skb_put(skb, sizeof(mISDN_pid_t)), arg, sizeof(mISDN_pid_t));
|
||||
hhe->func.ctrl = central_manager;
|
||||
skb_queue_tail(&mISDN_thread.workq, skb);
|
||||
wake_up_interruptible(&mISDN_thread.waitq);
|
||||
return(0);
|
||||
} else
|
||||
return(set_stack(st, arg));
|
||||
break;
|
||||
/* 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));
|
||||
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(ConnectIF(data, arg));
|
||||
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;
|
||||
break;
|
||||
case MGR_DEBUGDATA | REQUEST:
|
||||
return(debugout(data, arg));
|
||||
return(debugout(data, arg));
|
||||
default:
|
||||
if (debug)
|
||||
printk(KERN_WARNING "manager prim %x not handled\n", prim);
|
||||
|
@ -477,35 +613,90 @@ static int central_manager(void *data, u_int prim, void *arg) {
|
|||
}
|
||||
|
||||
void
|
||||
mISDNlock_core(void) {
|
||||
#ifdef MODULE
|
||||
MOD_INC_USE_COUNT;
|
||||
#endif
|
||||
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);
|
||||
|
||||
printk(KERN_DEBUG "mISDN_register_module(%p)\n", module);
|
||||
}
|
||||
|
||||
void
|
||||
mISDNunlock_core(void) {
|
||||
#ifdef MODULE
|
||||
MOD_DEC_USE_COUNT;
|
||||
#endif
|
||||
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);
|
||||
printk(KERN_DEBUG "mISDN_unregister_module(%p)\n", module);
|
||||
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++;
|
||||
APPEND_TO_LIST(obj, mISDN_objects);
|
||||
obj->ctrl = central_manager;
|
||||
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);
|
||||
return(0);
|
||||
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)
|
||||
|
@ -514,8 +705,15 @@ int mISDN_unregister(mISDNobject_t *obj) {
|
|||
if (obj->DPROTO.protocol[0])
|
||||
release_stacks(obj);
|
||||
else
|
||||
remove_object(obj);
|
||||
REMOVE_FROM_LISTBASE(obj, mISDN_objects);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -525,11 +723,25 @@ mISDNInit(void)
|
|||
DECLARE_MUTEX_LOCKED(sem);
|
||||
int err;
|
||||
|
||||
printk(KERN_INFO "Modular ISDN Stack core %s\n", mISDN_core_revision);
|
||||
printk(KERN_INFO "Modular ISDN Stack core version (%s) revision (%s)\n", mISDN_core_version, mISDN_core_revision);
|
||||
core_debug = debug;
|
||||
err = init_mISDNdev(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;
|
||||
|
@ -539,13 +751,24 @@ mISDNInit(void)
|
|||
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);
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
void cleanup_module(void) {
|
||||
void mISDN_cleanup(void) {
|
||||
DECLARE_MUTEX_LOCKED(sem);
|
||||
mISDNstack_t *st;
|
||||
|
||||
free_mISDNdev();
|
||||
if (!list_empty(&mISDN_objectlist)) {
|
||||
printk(KERN_WARNING "mISDNcore mISDN_objects not empty\n");
|
||||
}
|
||||
check_stacklist();
|
||||
if (mISDN_thread.thread) {
|
||||
/* abort mISDNd kernel thread */
|
||||
mISDN_thread.notify = &sem;
|
||||
|
@ -554,23 +777,29 @@ void cleanup_module(void) {
|
|||
down(&sem);
|
||||
mISDN_thread.notify = NULL;
|
||||
}
|
||||
free_mISDNdev();
|
||||
if (mISDN_objects) {
|
||||
printk(KERN_WARNING "mISDNcore mISDN_objects not empty\n");
|
||||
}
|
||||
if (mISDN_stacklist) {
|
||||
printk(KERN_WARNING "mISDNcore mISDN_stacklist not empty\n");
|
||||
st = mISDN_stacklist;
|
||||
while (st) {
|
||||
printk(KERN_WARNING "mISDNcore st %x in list\n",
|
||||
st->id);
|
||||
if (st == st->next) {
|
||||
printk(KERN_WARNING "mISDNcore st == next\n");
|
||||
break;
|
||||
}
|
||||
st = st->next;
|
||||
}
|
||||
}
|
||||
#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);
|
||||
#ifdef CONFIG_MISDN_NETDEV
|
||||
EXPORT_SYMBOL(misdn_log_frame);
|
||||
#endif
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/mISDNif.h>
|
||||
#include "helper.h"
|
||||
#ifdef MEMDBG
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
|
@ -17,49 +17,91 @@
|
|||
#define mISDN_MINOR_RAW_MIN 128
|
||||
#define mISDN_MINOR_RAW_MAX 255
|
||||
|
||||
#define mISDN_DEVBUF_SIZE 8192
|
||||
|
||||
/* debugging */
|
||||
#define DEBUG_CORE_FUNC 0x0001
|
||||
#define DEBUG_DUMMY_FUNC 0x0002
|
||||
//#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 mISDN_dev.c */
|
||||
|
||||
/* 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 mISDN_stack.c */
|
||||
|
||||
extern mISDNstack_t *mISDN_stacklist;
|
||||
extern mISDNinstance_t *mISDN_instlist;
|
||||
|
||||
extern void get_stack_info(iframe_t *);
|
||||
/* from stack.c */
|
||||
extern void get_stack_info(struct sk_buff *);
|
||||
extern int get_stack_cnt(void);
|
||||
extern mISDNstack_t *get_stack4id(int);
|
||||
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 *);
|
||||
extern mISDNlayer_t *getlayer4lay(mISDNstack_t *, int);
|
||||
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 mISDN_core.c */
|
||||
/* from sysfs_obj.c */
|
||||
extern int mISDN_register_sysfs_obj(mISDNobject_t *);
|
||||
extern int mISDN_sysfs_init(void);
|
||||
extern void mISDN_sysfs_cleanup(void);
|
||||
|
||||
extern mISDNobject_t *mISDN_objects;
|
||||
/* 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 void mISDNlock_core(void);
|
||||
extern void mISDNunlock_core(void);
|
||||
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(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);
|
||||
|
||||
|
||||
#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
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,109 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Author Karsten Keil (keil@isdn4linux.de)
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#define __NO_VERSION__
|
||||
#include <linux/mISDNif.h>
|
||||
#include "layer1.h"
|
||||
#include "helper.h"
|
||||
#include "dchannel.h"
|
||||
|
||||
static void
|
||||
dchannel_bh(dchannel_t *dch)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
if (!dch)
|
||||
return;
|
||||
if (dch->debug)
|
||||
printk(KERN_DEBUG "%s: event %x\n", __FUNCTION__, dch->event);
|
||||
#if 0
|
||||
if (test_and_clear_bit(D_CLEARBUSY, &dch->event)) {
|
||||
if (dch->debug)
|
||||
debugprint(&dch->inst, "D-Channel Busy cleared");
|
||||
stptr = dch->stlist;
|
||||
while (stptr != NULL) {
|
||||
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
|
||||
stptr = stptr->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (test_and_clear_bit(D_XMTBUFREADY, &dch->event)) {
|
||||
if ((skb = dch->next_skb)) {
|
||||
dch->next_skb = NULL;
|
||||
skb_trim(skb, 0);
|
||||
if (if_newhead(&dch->inst.up, PH_DATA_CNF, DINFO_SKB, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(D_RCVBUFREADY, &dch->event)) {
|
||||
while ((skb = skb_dequeue(&dch->rqueue))) {
|
||||
err = if_newhead(&dch->inst.up, PH_DATA_IND, DINFO_SKB, skb);
|
||||
if (err < 0) {
|
||||
printk(KERN_WARNING "%s: deliver err %d\n", __FUNCTION__, err);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dch->hw_bh)
|
||||
dch->hw_bh(dch);
|
||||
}
|
||||
|
||||
int
|
||||
init_dchannel(dchannel_t *dch) {
|
||||
if (!(dch->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: No memory for dlog\n");
|
||||
return(-ENOMEM);
|
||||
}
|
||||
if (!(dch->tx_buf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: No memory for dchannel tx_buf\n");
|
||||
kfree(dch->dlog);
|
||||
dch->dlog = NULL;
|
||||
return(-ENOMEM);
|
||||
}
|
||||
dch->hw = NULL;
|
||||
dch->rx_skb = NULL;
|
||||
dch->tx_idx = 0;
|
||||
dch->next_skb = NULL;
|
||||
dch->event = 0;
|
||||
dch->tqueue.data = dch;
|
||||
dch->tqueue.routine = (void *) (void *) dchannel_bh;
|
||||
dch->hw_bh = NULL;
|
||||
skb_queue_head_init(&dch->rqueue);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
free_dchannel(dchannel_t *dch) {
|
||||
|
||||
if (dch->tqueue.sync)
|
||||
printk(KERN_ERR"free_dchannel tqueue.sync\n");
|
||||
discard_queue(&dch->rqueue);
|
||||
if (dch->rx_skb) {
|
||||
dev_kfree_skb(dch->rx_skb);
|
||||
dch->rx_skb = NULL;
|
||||
}
|
||||
if (dch->tx_buf) {
|
||||
kfree(dch->tx_buf);
|
||||
dch->tx_buf = NULL;
|
||||
}
|
||||
if (dch->next_skb) {
|
||||
dev_kfree_skb(dch->next_skb);
|
||||
dch->next_skb = NULL;
|
||||
}
|
||||
if (dch->dlog) {
|
||||
kfree(dch->dlog);
|
||||
dch->dlog = NULL;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Basic declarations for dchannel HW
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/mISDNif.h>
|
||||
#include <linux/tqueue.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/skbuff.h>
|
||||
#ifdef MEMDBG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
#define MAX_DFRAME_LEN_L1 300
|
||||
#define MAX_MON_FRAME 32
|
||||
#define MAX_DLOG_SPACE 2048
|
||||
|
||||
#define FLG_TWO_DCHAN 4
|
||||
#define FLG_TX_BUSY 5
|
||||
#define FLG_TX_NEXT 6
|
||||
#define FLG_L1_DBUSY 7
|
||||
#define FLG_DBUSY_TIMER 8
|
||||
#define FLG_LOCK_ATOMIC 9
|
||||
#define FLG_ARCOFI_TIMER 10
|
||||
#define FLG_ARCOFI_ERROR 11
|
||||
#define FLG_HW_L1_UINT 12
|
||||
#define FLG_HW_INIT 13
|
||||
|
||||
typedef struct _dchannel_t {
|
||||
mISDNinstance_t inst;
|
||||
u_int DFlags;
|
||||
u_int type;
|
||||
u_int ph_state;
|
||||
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);
|
||||
char *dlog;
|
||||
int debug;
|
||||
struct sk_buff *rx_skb;
|
||||
struct sk_buff *next_skb;
|
||||
u_char *tx_buf;
|
||||
int tx_idx;
|
||||
int tx_len;
|
||||
int err_crc;
|
||||
int err_tx;
|
||||
int err_rx;
|
||||
void *hw;
|
||||
struct timer_list dbusytimer;
|
||||
u_int event;
|
||||
struct sk_buff_head rqueue; /* D-channel receive queue */
|
||||
struct tq_struct tqueue;
|
||||
void (*hw_bh) (struct _dchannel_t *);
|
||||
} dchannel_t;
|
||||
|
||||
#define MON0_RX 1
|
||||
#define MON1_RX 2
|
||||
#define MON0_TX 4
|
||||
#define MON1_TX 8
|
||||
|
||||
extern int init_dchannel(dchannel_t *);
|
||||
extern int free_dchannel(dchannel_t *);
|
||||
|
||||
static inline void
|
||||
dchannel_sched_event(dchannel_t *dch, int event)
|
||||
{
|
||||
test_and_set_bit(event, &dch->event);
|
||||
queue_task(&dch->tqueue, &tq_immediate);
|
||||
mark_bh(IMMEDIATE_BH);
|
||||
}
|
||||
|
||||
#ifdef __powerpc__
|
||||
#include <linux/pci.h>
|
||||
static inline int pci_enable_device(struct pci_dev *dev)
|
||||
{
|
||||
u16 cmd;
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_SERR;
|
||||
cmd &= ~PCI_COMMAND_FAST_BACK;
|
||||
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
||||
return(0);
|
||||
}
|
||||
#else
|
||||
#define pci_enable_device(dev) !dev
|
||||
#endif /* __powerpc__ */
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define __NO_VERSION__
|
||||
#include <linux/module.h>
|
||||
#include <linux/mISDNif.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
|
@ -17,7 +17,7 @@
|
|||
static char tmpbuf[mISDN_STATUS_BUFSIZE];
|
||||
|
||||
void
|
||||
vmISDNdebug(int id, char *head, char *fmt, va_list args)
|
||||
vmISDN_debug(int id, char *head, char *fmt, va_list args)
|
||||
{
|
||||
/* if head == NULL the fmt contains the full info */
|
||||
char *p = tmpbuf;
|
||||
|
@ -30,24 +30,24 @@ vmISDNdebug(int id, char *head, char *fmt, va_list args)
|
|||
}
|
||||
|
||||
void
|
||||
mISDNdebug(int id, char *head, char *fmt, ...)
|
||||
mISDN_debug(int id, char *head, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vmISDNdebug(id, head, fmt, args);
|
||||
vmISDN_debug(id, head, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
debugprint(mISDNinstance_t *inst, char *fmt, ...)
|
||||
mISDN_debugprint(mISDNinstance_t *inst, char *fmt, ...)
|
||||
{
|
||||
logdata_t log;
|
||||
|
||||
va_start(log.args, fmt);
|
||||
log.head = inst->name;
|
||||
log.fmt = fmt;
|
||||
inst->obj->ctrl(inst, MGR_DEBUGDATA | REQUEST, &log);
|
||||
mISDN_ctrl(inst, MGR_DEBUGDATA | REQUEST, &log);
|
||||
va_end(log.args);
|
||||
}
|
||||
|
||||
|
@ -60,14 +60,15 @@ mISDN_getrev(const char *revision)
|
|||
if ((p = strchr(revision, ':'))) {
|
||||
rev = p + 2;
|
||||
p = strchr(rev, '$');
|
||||
*--p = 0;
|
||||
if (p)
|
||||
*--p = 0;
|
||||
} else
|
||||
rev = "???";
|
||||
return rev;
|
||||
}
|
||||
|
||||
int
|
||||
QuickHex(char *txt, u_char * p, int cnt)
|
||||
mISDN_QuickHex(char *txt, u_char * p, int cnt)
|
||||
{
|
||||
register int i;
|
||||
register char *t = txt;
|
||||
|
@ -89,3 +90,9 @@ QuickHex(char *txt, u_char * p, int cnt)
|
|||
*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);
|
||||
|
|
|
@ -5,9 +5,13 @@
|
|||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
#ifndef MISDN_DEBUG_H
|
||||
|
||||
extern void vmISDNdebug(int id, char *head, char *fmt, va_list args);
|
||||
extern void mISDNdebug(int id, char *head, char *fmt, ...);
|
||||
#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 debugprint(mISDNinstance_t *inst, char *fmt, ...);
|
||||
extern int QuickHex(char *, u_char *, int);
|
||||
extern void mISDN_debugprint(mISDNinstance_t *inst, char *fmt, ...);
|
||||
extern int mISDN_QuickHex(char *, u_char *, int);
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,298 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Audio support data for ISDN4Linux.
|
||||
*
|
||||
* Copyright 2002/2003 by Andreas Eversberg (jolly@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 queue_dtmf; /* flags enabled dtmf, prior feature reply */
|
||||
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; /* stores conf id prior feature reply */
|
||||
|
||||
/* 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]; /* stores cancel values prior feature reply */
|
||||
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);
|
||||
|
||||
|
|
@ -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 */
|
|
@ -0,0 +1,583 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Audio support data for mISDN_dsp.
|
||||
*
|
||||
* Copyright 2002/2003 by Andreas Eversberg (jolly@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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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@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 ------------------------------------------------------------*/
|
|
@ -0,0 +1,658 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Blowfish encryption/decryption for mISDN_dsp.
|
||||
*
|
||||
* Copyright Andreas Eversberg (jolly@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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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), ¶m, 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************/
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,249 @@
|
|||
/* $Id$
|
||||
*
|
||||
* DTMF decoder.
|
||||
*
|
||||
* Copyright by Andreas Eversberg (jolly@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;
|
||||
}
|
||||
|
||||
|
|
@ -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@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 ------------------------------------------------------------*/
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -0,0 +1,546 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Audio support data for ISDN4Linux.
|
||||
*
|
||||
* Copyright Andreas Eversberg (jolly@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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -16,13 +16,18 @@
|
|||
/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
|
||||
/* This makes some tests easier and quicker */
|
||||
#define T309 40000
|
||||
#define T310 30000
|
||||
/* 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
|
||||
|
@ -36,6 +41,8 @@
|
|||
#define CC_T318 0x031801
|
||||
#define CC_T319 0x031901
|
||||
#define CC_TCTRL 0x031f01
|
||||
#define CC_THOLD 0x03a001
|
||||
#define CC_TRETRIEVE 0x03a101
|
||||
/*
|
||||
* Message-Types
|
||||
*/
|
||||
|
@ -47,6 +54,12 @@
|
|||
#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
|
||||
|
@ -96,6 +109,7 @@
|
|||
#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
|
||||
|
@ -106,6 +120,7 @@
|
|||
#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
|
||||
|
@ -137,6 +152,16 @@
|
|||
|
||||
#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 */
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include "core.h"
|
||||
#include "layer1.h"
|
||||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
|
@ -24,20 +24,19 @@
|
|||
#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
|
||||
|
||||
typedef struct _dtmf {
|
||||
struct _dtmf *prev;
|
||||
struct _dtmf *next;
|
||||
int Flags;
|
||||
int debug;
|
||||
char last;
|
||||
int idx;
|
||||
int buf[DTMF_NPOINTS];
|
||||
mISDNinstance_t inst;
|
||||
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 int debug = 0;
|
||||
static u_int debug = 0;
|
||||
|
||||
#define DEBUG_DTMF_MGR 0x001
|
||||
#define DEBUG_DTMF_TONE 0x010
|
||||
|
@ -351,7 +350,7 @@ isdn_audio_goertzel(dtmf_t *dtmf)
|
|||
if (dtmf->debug & DEBUG_DTMF_TONE)
|
||||
printk(KERN_DEBUG "DTMF: tone='%c'\n", what);
|
||||
k = what | DTMF_TONE_VAL;
|
||||
if_link(&dtmf->inst.up, PH_CONTROL | INDICATION,
|
||||
mISDN_queue_data(&dtmf->inst, FLG_MSG_UP, PH_CONTROL | INDICATION,
|
||||
0, sizeof(int), &k, 0);
|
||||
}
|
||||
dtmf->last = what;
|
||||
|
@ -398,24 +397,20 @@ dtmf_reset(dtmf_t *dtmf)
|
|||
dtmf->idx = 0;
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE
|
||||
static int
|
||||
dtmf_from_up(mISDNif_t *hif, struct sk_buff *skb)
|
||||
dtmf_from_up(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
dtmf_t *dtmf;
|
||||
mISDN_head_t *hh;
|
||||
int *data;
|
||||
int err = 0;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
return(-EINVAL);
|
||||
dtmf = hif->fdata;
|
||||
if (!dtmf->inst.down.func) {
|
||||
return(-ENXIO);
|
||||
}
|
||||
dtmf = inst->privat;
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
switch(hh->prim) {
|
||||
case (PH_CONTROL | REQUEST):
|
||||
if (skb->len >= sizeof(int)) {
|
||||
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",
|
||||
|
@ -423,34 +418,30 @@ dtmf_from_up(mISDNif_t *hif, struct sk_buff *skb)
|
|||
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;
|
||||
}
|
||||
break;
|
||||
} else
|
||||
printk(KERN_ERR "dtmf_from_up: skb too shoort %d\n",
|
||||
skb->len);
|
||||
}
|
||||
/* Fall trough in case of not handled function */
|
||||
default:
|
||||
return(dtmf->inst.down.func(&dtmf->inst.down, skb));
|
||||
return(mISDN_queue_down(inst, 0, skb));
|
||||
}
|
||||
if (!err)
|
||||
dev_kfree_skb(skb);
|
||||
return(err);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
dtmf_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
||||
dtmf_function(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
dtmf_t *dtmf;
|
||||
mISDN_head_t *hh;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
return(-EINVAL);
|
||||
dtmf = hif->fdata;
|
||||
if (!dtmf->inst.up.func) {
|
||||
return(-ENXIO);
|
||||
}
|
||||
dtmf = inst->privat;
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
switch(hh->prim) {
|
||||
case (PH_DATA | CONFIRM):
|
||||
|
@ -462,6 +453,25 @@ dtmf_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
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;
|
||||
|
@ -475,30 +485,26 @@ dtmf_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
hh->prim = DL_RELEASE | INDICATION;
|
||||
break;
|
||||
}
|
||||
return(dtmf->inst.up.func(&dtmf->inst.up, skb));
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
REMOVE_FROM_LISTBASE(dtmf, ((dtmf_t *)dtmf_obj.ilist));
|
||||
dtmf_obj.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
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;
|
||||
dtmf_t *n_dtmf;
|
||||
int err;
|
||||
u_long flags;
|
||||
|
||||
if (!st || !pid)
|
||||
return(-EINVAL);
|
||||
|
@ -508,19 +514,19 @@ new_dtmf(mISDNstack_t *st, mISDN_pid_t *pid) {
|
|||
}
|
||||
memset(n_dtmf, 0, sizeof(dtmf_t));
|
||||
memcpy(&n_dtmf->inst.pid, pid, sizeof(mISDN_pid_t));
|
||||
n_dtmf->inst.obj = &dtmf_obj;
|
||||
n_dtmf->inst.data = n_dtmf;
|
||||
if (!SetHandledPID(&dtmf_obj, &n_dtmf->inst.pid)) {
|
||||
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;
|
||||
n_dtmf->inst.up.owner = &n_dtmf->inst;
|
||||
n_dtmf->inst.down.owner = &n_dtmf->inst;
|
||||
APPEND_TO_LIST(n_dtmf, ((dtmf_t *)dtmf_obj.ilist));
|
||||
err = dtmf_obj.ctrl(st, MGR_REGLAYER | INDICATION, &n_dtmf->inst);
|
||||
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) {
|
||||
REMOVE_FROM_LISTBASE(n_dtmf, ((dtmf_t *)dtmf_obj.ilist));
|
||||
list_del(&n_dtmf->list);
|
||||
kfree(n_dtmf);
|
||||
}
|
||||
return(err);
|
||||
|
@ -553,7 +559,12 @@ 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
|
||||
|
@ -561,55 +572,51 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
static int
|
||||
dtmf_manager(void *data, u_int prim, void *arg) {
|
||||
mISDNinstance_t *inst = data;
|
||||
dtmf_t *dtmf_l = dtmf_obj.ilist;
|
||||
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(-EINVAL);
|
||||
while(dtmf_l) {
|
||||
if (&dtmf_l->inst == inst)
|
||||
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;
|
||||
dtmf_l = dtmf_l->next;
|
||||
}
|
||||
}
|
||||
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_NEWLAYER | REQUEST:
|
||||
return(new_dtmf(data, arg));
|
||||
case MGR_CLRSTPARA | INDICATION:
|
||||
break;
|
||||
#ifdef OBSOLETE
|
||||
case MGR_CLONELAYER | REQUEST:
|
||||
break;
|
||||
case MGR_CONNECT | REQUEST:
|
||||
if (!dtmf_l) {
|
||||
printk(KERN_WARNING "dtmf_manager connect no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
return(ConnectIF(inst, arg));
|
||||
return(mISDN_ConnectIF(inst, arg));
|
||||
case MGR_SETIF | REQUEST:
|
||||
case MGR_SETIF | INDICATION:
|
||||
if (!dtmf_l) {
|
||||
printk(KERN_WARNING "dtmf_manager setif no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
return(SetIF(inst, arg, prim, dtmf_from_up, dtmf_from_down, dtmf_l));
|
||||
return(mISDN_SetIF(inst, arg, prim, dtmf_from_up, dtmf_from_down, dtmf_l));
|
||||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
if (!dtmf_l) {
|
||||
printk(KERN_WARNING "dtmf_manager disconnect no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
return(DisConnectIF(inst, arg));
|
||||
return(mISDN_DisConnectIF(inst, arg));
|
||||
#endif
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
case MGR_RELEASE | INDICATION:
|
||||
if (dtmf_l) {
|
||||
if (debug & DEBUG_DTMF_MGR)
|
||||
printk(KERN_DEBUG "release_dtmf id %x\n", dtmf_l->inst.st->id);
|
||||
release_dtmf(dtmf_l);
|
||||
} else
|
||||
printk(KERN_WARNING "dtmf_manager release no instance\n");
|
||||
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:
|
||||
// if (!dtmf_l) {
|
||||
// printk(KERN_WARNING "dtmf_manager status dtmf no instance\n");
|
||||
// return(-EINVAL);
|
||||
// }
|
||||
// return(dtmf_status(dtmf_l, arg));
|
||||
default:
|
||||
if (debug & DEBUG_DTMF_MGR)
|
||||
|
@ -624,30 +631,35 @@ static int dtmf_init(void)
|
|||
int err;
|
||||
|
||||
printk(KERN_INFO "DTMF modul version %s\n", mISDN_getrev(mISDN_dtmf_revision));
|
||||
SET_MODULE_OWNER(&dtmf_obj);
|
||||
#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;
|
||||
dtmf_obj.prev = NULL;
|
||||
dtmf_obj.next = NULL;
|
||||
dtmf_obj.ilist = NULL;
|
||||
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;
|
||||
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(dtmf_obj.ilist) {
|
||||
if (!list_empty(&dtmf_obj.ilist)) {
|
||||
printk(KERN_WARNING "dtmf inst list not empty\n");
|
||||
while(dtmf_obj.ilist)
|
||||
release_dtmf(dtmf_obj.ilist);
|
||||
list_for_each_entry_safe(dtmf, nd, &dtmf_obj.ilist, list)
|
||||
release_dtmf(dtmf);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,15 +8,20 @@
|
|||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
#define __NO_VERSION__
|
||||
#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
|
||||
FsmNew(struct Fsm *fsm,
|
||||
mISDN_FsmNew(struct Fsm *fsm,
|
||||
struct FsmNode *fnlist, int fncount)
|
||||
{
|
||||
int i;
|
||||
|
@ -27,7 +32,7 @@ FsmNew(struct Fsm *fsm,
|
|||
|
||||
for (i = 0; i < fncount; i++)
|
||||
if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) {
|
||||
printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
|
||||
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
|
||||
|
@ -36,18 +41,18 @@ FsmNew(struct Fsm *fsm,
|
|||
}
|
||||
|
||||
void
|
||||
FsmFree(struct Fsm *fsm)
|
||||
mISDN_FsmFree(struct Fsm *fsm)
|
||||
{
|
||||
kfree((void *) fsm->jumpmatrix);
|
||||
}
|
||||
|
||||
int
|
||||
FsmEvent(struct FsmInst *fi, int event, void *arg)
|
||||
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 "FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
|
||||
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);
|
||||
}
|
||||
|
@ -69,7 +74,7 @@ FsmEvent(struct FsmInst *fi, int event, void *arg)
|
|||
}
|
||||
|
||||
void
|
||||
FsmChangeState(struct FsmInst *fi, int newstate)
|
||||
mISDN_FsmChangeState(struct FsmInst *fi, int newstate)
|
||||
{
|
||||
fi->state = newstate;
|
||||
if (fi->debug)
|
||||
|
@ -84,46 +89,48 @@ FsmExpireTimer(struct FsmTimer *ft)
|
|||
if (ft->fi->debug)
|
||||
ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
|
||||
#endif
|
||||
FsmEvent(ft->fi, ft->event, ft->arg);
|
||||
mISDN_FsmEvent(ft->fi, ft->event, ft->arg);
|
||||
}
|
||||
|
||||
void
|
||||
FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
|
||||
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, "FsmInitTimer %lx", (long) ft);
|
||||
ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft);
|
||||
#endif
|
||||
init_timer(&ft->tl);
|
||||
}
|
||||
|
||||
void
|
||||
FsmDelTimer(struct FsmTimer *ft, int where)
|
||||
mISDN_FsmDelTimer(struct FsmTimer *ft, int where)
|
||||
{
|
||||
#if FSM_TIMER_DEBUG
|
||||
if (ft->fi->debug)
|
||||
ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
|
||||
ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d", (long) ft, where);
|
||||
#endif
|
||||
del_timer(&ft->tl);
|
||||
}
|
||||
|
||||
int
|
||||
FsmAddTimer(struct FsmTimer *ft,
|
||||
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, "FsmAddTimer %lx %d %d",
|
||||
ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d",
|
||||
(long) ft, millisec, where);
|
||||
#endif
|
||||
|
||||
if (timer_pending(&ft->tl)) {
|
||||
printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
|
||||
ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
|
||||
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);
|
||||
|
@ -135,13 +142,13 @@ FsmAddTimer(struct FsmTimer *ft,
|
|||
}
|
||||
|
||||
void
|
||||
FsmRestartTimer(struct FsmTimer *ft,
|
||||
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, "FsmRestartTimer %lx %d %d",
|
||||
ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d",
|
||||
(long) ft, millisec, where);
|
||||
#endif
|
||||
|
||||
|
@ -153,3 +160,12 @@ FsmRestartTimer(struct FsmTimer *ft,
|
|||
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);
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef _MISDN_FSM_H
|
||||
#define _MISDN_FSM_H
|
||||
|
||||
#include <linux/timer.h>
|
||||
|
||||
/* Statemachine */
|
||||
|
@ -39,11 +42,13 @@ struct FsmTimer {
|
|||
void *arg;
|
||||
};
|
||||
|
||||
extern void FsmNew(struct Fsm *, struct FsmNode *, int);
|
||||
extern void FsmFree(struct Fsm *);
|
||||
extern int FsmEvent(struct FsmInst *, int , void *);
|
||||
extern void FsmChangeState(struct FsmInst *, int);
|
||||
extern void FsmInitTimer(struct FsmInst *, struct FsmTimer *);
|
||||
extern int FsmAddTimer(struct FsmTimer *, int, int, void *, int);
|
||||
extern void FsmRestartTimer(struct FsmTimer *, int, int, void *, int);
|
||||
extern void FsmDelTimer(struct FsmTimer *, int);
|
||||
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
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define __NO_VERSION__
|
||||
#include <linux/module.h>
|
||||
#include <linux/mISDNif.h>
|
||||
#include "helper.h"
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
#undef DEBUG_IF
|
||||
|
||||
void
|
||||
set_dchannel_pid(mISDN_pid_t *pid, int protocol, int layermask)
|
||||
mISDN_set_dchannel_pid(mISDN_pid_t *pid, int protocol, int layermask)
|
||||
{
|
||||
if (!layermask)
|
||||
layermask = ISDN_LAYER(0)| ISDN_LAYER(1) | ISDN_LAYER(2) |
|
||||
|
@ -26,36 +26,78 @@ set_dchannel_pid(mISDN_pid_t *pid, int protocol, int layermask)
|
|||
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))
|
||||
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 == 2)
|
||||
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
|
||||
bprotocol2pid(void *bp, mISDN_pid_t *pid)
|
||||
mISDN_add_pid_parameter(mISDN_pid_t *pid, int layer, u_char *para)
|
||||
{
|
||||
__u8 *p = bp;
|
||||
__u16 *w = bp;
|
||||
int i;
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
pid->protocol[i] = (1 <<*w) | ISDN_PID_LAYER(i) |
|
||||
ISDN_PID_BCHANNEL_BIT;
|
||||
if (*p)
|
||||
pid->param[i] = p;
|
||||
else
|
||||
pid->param[i] = NULL;
|
||||
ret = mISDN_add_pid_parameter(pid, i, p);
|
||||
if (ret)
|
||||
return ret;
|
||||
w++;
|
||||
p += *p;
|
||||
p++;
|
||||
|
@ -63,17 +105,17 @@ bprotocol2pid(void *bp, mISDN_pid_t *pid)
|
|||
pid->global = 0;
|
||||
if (*p == 2) { // len of 1 word
|
||||
p++;
|
||||
w = (__u16 *)p;
|
||||
w = (u16 *)p;
|
||||
pid->global = *w;
|
||||
}
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
HasProtocol(mISDNobject_t *obj, int protocol)
|
||||
mISDN_HasProtocol(mISDNobject_t *obj, u_int protocol)
|
||||
{
|
||||
int layer;
|
||||
int pmask;
|
||||
u_int pmask;
|
||||
|
||||
if (!obj) {
|
||||
int_error();
|
||||
|
@ -97,7 +139,7 @@ HasProtocol(mISDNobject_t *obj, int protocol)
|
|||
}
|
||||
|
||||
int
|
||||
SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
|
||||
mISDN_SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
|
||||
{
|
||||
int layer;
|
||||
int ret = 0;
|
||||
|
@ -112,6 +154,9 @@ SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
|
|||
#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__);
|
||||
|
@ -124,7 +169,7 @@ SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
|
|||
else
|
||||
continue;
|
||||
}
|
||||
if (0 == HasProtocol(obj, sav.protocol[layer])) {
|
||||
if (0 == mISDN_HasProtocol(obj, sav.protocol[layer])) {
|
||||
ret++;
|
||||
pid->protocol[layer] = sav.protocol[layer];
|
||||
pid->param[layer] = sav.param[layer];
|
||||
|
@ -136,7 +181,7 @@ SetHandledPID(mISDNobject_t *obj, mISDN_pid_t *pid)
|
|||
}
|
||||
|
||||
void
|
||||
RemoveUsedPID(mISDN_pid_t *pid, mISDN_pid_t *used)
|
||||
mISDN_RemoveUsedPID(mISDN_pid_t *pid, mISDN_pid_t *used)
|
||||
{
|
||||
int layer;
|
||||
|
||||
|
@ -151,13 +196,13 @@ RemoveUsedPID(mISDN_pid_t *pid, mISDN_pid_t *used)
|
|||
if (!(ISDN_LAYER(layer) & used->layermask))
|
||||
continue;
|
||||
pid->protocol[layer] = ISDN_PID_NONE;
|
||||
pid->param[layer] = NULL;
|
||||
pid->param[layer] = 0;
|
||||
pid->layermask &= ~(ISDN_LAYER(layer));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
layermask2layer(int layermask) {
|
||||
mISDN_layermask2layer(int layermask) {
|
||||
switch(layermask) {
|
||||
case ISDN_LAYER(0): return(0);
|
||||
case ISDN_LAYER(1): return(1);
|
||||
|
@ -173,7 +218,7 @@ layermask2layer(int layermask) {
|
|||
}
|
||||
|
||||
int
|
||||
get_protocol(mISDNstack_t *st, int layer)
|
||||
mISDN_get_protocol(mISDNstack_t *st, int layer)
|
||||
{
|
||||
|
||||
if (!st){
|
||||
|
@ -188,7 +233,7 @@ get_protocol(mISDNstack_t *st, int layer)
|
|||
}
|
||||
|
||||
int
|
||||
get_lowlayer(int layermask)
|
||||
mISDN_get_lowlayer(int layermask)
|
||||
{
|
||||
int layer;
|
||||
|
||||
|
@ -201,7 +246,7 @@ get_lowlayer(int layermask)
|
|||
}
|
||||
|
||||
int
|
||||
get_down_layer(int layermask)
|
||||
mISDN_get_down_layer(int layermask)
|
||||
{
|
||||
int downlayer = 1;
|
||||
|
||||
|
@ -218,7 +263,8 @@ get_down_layer(int layermask)
|
|||
return(downlayer);
|
||||
}
|
||||
|
||||
int get_up_layer(int layermask) {
|
||||
int
|
||||
mISDN_get_up_layer(int layermask) {
|
||||
int uplayer = MAX_LAYER_NR;
|
||||
|
||||
if (layermask>=128) {
|
||||
|
@ -234,8 +280,9 @@ int get_up_layer(int layermask) {
|
|||
return(uplayer);
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE
|
||||
int
|
||||
SetIF(mISDNinstance_t *owner, mISDNif_t *hif, u_int prim, void *upfunc,
|
||||
mISDN_SetIF(mISDNinstance_t *owner, mISDNif_t *hif, u_int prim, void *upfunc,
|
||||
void *downfunc, void *data)
|
||||
{
|
||||
mISDNif_t *own_hif;
|
||||
|
@ -284,7 +331,7 @@ SetIF(mISDNinstance_t *owner, mISDNif_t *hif, u_int prim, void *upfunc,
|
|||
}
|
||||
|
||||
int
|
||||
ConnectIF(mISDNinstance_t *owner, mISDNinstance_t *peer)
|
||||
mISDN_ConnectIF(mISDNinstance_t *owner, mISDNinstance_t *peer)
|
||||
{
|
||||
mISDNif_t *hif;
|
||||
|
||||
|
@ -312,12 +359,13 @@ ConnectIF(mISDNinstance_t *owner, mISDNinstance_t *peer)
|
|||
return(peer->obj->own_ctrl(peer, MGR_SETIF | REQUEST, hif));
|
||||
}
|
||||
|
||||
int DisConnectIF(mISDNinstance_t *inst, mISDNif_t *hif) {
|
||||
|
||||
int
|
||||
mISDN_DisConnectIF(mISDNinstance_t *inst, mISDNif_t *hif) {
|
||||
if (hif) {
|
||||
if (hif->next && hif->next->owner) {
|
||||
hif->next->owner->obj->ctrl(hif->next->owner,
|
||||
MGR_DISCONNECT | REQUEST, hif->next);
|
||||
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)
|
||||
|
@ -332,4 +380,33 @@ int DisConnectIF(mISDNinstance_t *inst, mISDNif_t *hif) {
|
|||
}
|
||||
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);
|
||||
|
|
|
@ -2,60 +2,27 @@
|
|||
*
|
||||
* Basic declarations, defines and prototypes
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
* This file is released under the GPLv2
|
||||
*
|
||||
*/
|
||||
#ifndef _mISDN_HELPER_H
|
||||
#define _mISDN_HELPER_H
|
||||
#include <linux/kernel.h>
|
||||
#ifdef MEMDBG
|
||||
#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)
|
||||
|
||||
#define APPEND_TO_LIST(item,base) \
|
||||
if (item->prev || item->next) \
|
||||
int_errtxt("APPEND not clean %p<-%p->%p", \
|
||||
item->prev, item, item->next); \
|
||||
item->next = NULL; \
|
||||
item->prev = base; \
|
||||
while (item->prev && item->prev->next) \
|
||||
item->prev = item->prev->next; \
|
||||
if (item->prev == item) { \
|
||||
int_errtxt("APPEND DUP %p", item); \
|
||||
} else \
|
||||
if (base) { \
|
||||
item->prev->next = item; \
|
||||
} else \
|
||||
base = item
|
||||
|
||||
#define INSERT_INTO_LIST(newi,nexti,base) \
|
||||
newi->next = nexti; \
|
||||
newi->prev = nexti->prev; \
|
||||
if (newi->prev) \
|
||||
newi->prev->next = newi; \
|
||||
nexti->prev = newi; \
|
||||
if (base == nexti) \
|
||||
base = newi
|
||||
|
||||
#define REMOVE_FROM_LIST(item) \
|
||||
if (item->prev) \
|
||||
item->prev->next = item->next; \
|
||||
if (item->next) \
|
||||
item->next->prev = item->prev
|
||||
|
||||
#define REMOVE_FROM_LISTBASE(item,base) \
|
||||
REMOVE_FROM_LIST(item); \
|
||||
if (item == base) \
|
||||
base = item->next
|
||||
|
||||
/* cleanup SKB queues, return count of dropped packets */
|
||||
static inline int
|
||||
discard_queue(struct sk_buff_head *q)
|
||||
{
|
||||
|
@ -69,39 +36,139 @@ discard_queue(struct sk_buff_head *q)
|
|||
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 *
|
||||
alloc_uplinkD_skb(size_t size)
|
||||
__mid_alloc_stack_skb(u_int size, u_int reserve, char *fn, int line)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!(skb = alloc_skb(size + L3_EXTRA_SIZE, GFP_ATOMIC)))
|
||||
printk(KERN_WARNING "%s(%d): no skb size\n", __FUNCTION__,
|
||||
size);
|
||||
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, L3_EXTRA_SIZE);
|
||||
skb_reserve(skb, reserve);
|
||||
return(skb);
|
||||
}
|
||||
|
||||
extern void set_dchannel_pid(mISDN_pid_t *, int, int);
|
||||
extern int get_lowlayer(int);
|
||||
extern int get_up_layer(int);
|
||||
extern int get_down_layer(int);
|
||||
extern int layermask2layer(int);
|
||||
extern int get_protocol(mISDNstack_t *, int);
|
||||
extern int HasProtocol(mISDNobject_t *, int);
|
||||
extern int SetHandledPID(mISDNobject_t *, mISDN_pid_t *);
|
||||
extern void RemoveUsedPID(mISDN_pid_t *, mISDN_pid_t *);
|
||||
/*
|
||||
* 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);
|
||||
|
||||
static inline int HasProtocolP(mISDNobject_t *obj, int *PP)
|
||||
/*
|
||||
* 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(HasProtocol(obj, *PP));
|
||||
return(mISDN_HasProtocol(obj, *PP));
|
||||
}
|
||||
|
||||
extern __inline__ void mISDN_sethead(u_int prim, int dinfo, struct sk_buff *skb)
|
||||
/* 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);
|
||||
|
||||
|
@ -109,45 +176,89 @@ extern __inline__ void mISDN_sethead(u_int prim, int dinfo, struct sk_buff *skb)
|
|||
hh->dinfo = dinfo;
|
||||
}
|
||||
|
||||
extern __inline__ int if_newhead(mISDNif_t *i, u_int prim, int dinfo,
|
||||
struct sk_buff *skb)
|
||||
#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)
|
||||
{
|
||||
if (!i->func || !skb)
|
||||
return(-ENXIO);
|
||||
mISDN_sethead(prim, dinfo, skb);
|
||||
return(i->func(i, 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));
|
||||
}
|
||||
|
||||
|
||||
extern __inline__ struct sk_buff *create_link_skb(u_int prim, int dinfo,
|
||||
int len, void *arg, int reserve)
|
||||
/* 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), arg, len);
|
||||
mISDN_sethead(prim, dinfo, skb);
|
||||
memcpy(skb_put(skb, len), dp, len);
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
hh->prim = prim;
|
||||
hh->dinfo = dinfo;
|
||||
hh->len = len;
|
||||
return(skb);
|
||||
}
|
||||
|
||||
extern __inline__ int if_link(mISDNif_t *i, u_int prim, int dinfo, int len,
|
||||
void *arg, int reserve)
|
||||
/* 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 = create_link_skb(prim, dinfo, len, arg, reserve)))
|
||||
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);
|
||||
if (!i)
|
||||
err = -ENXIO;
|
||||
else
|
||||
err = i->func(i, skb);
|
||||
err = mISDN_queue_message(inst, aflag, skb);
|
||||
if (err)
|
||||
kfree_skb(skb);
|
||||
return(err);
|
||||
|
@ -155,12 +266,33 @@ extern __inline__ int if_link(mISDNif_t *i, u_int prim, int dinfo, int len,
|
|||
|
||||
/* L3 data struct helper functions */
|
||||
|
||||
extern signed int l3_ie2pos(u_char);
|
||||
extern unsigned char l3_pos2ie(int);
|
||||
extern void initQ931_info(Q931_info_t *);
|
||||
extern struct sk_buff *alloc_l3msg(int, u_char);
|
||||
extern void AddvarIE(struct sk_buff *, u_char *);
|
||||
extern void AddIE(struct sk_buff *, u_char, u_char *);
|
||||
extern void LogL3Msg(struct sk_buff *);
|
||||
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 */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,187 @@
|
|||
/* $Id$
|
||||
*
|
||||
* mISDN driver for Colognechip HFC-S mini Evaluation Card
|
||||
*
|
||||
* Authors : Martin Bachem, Joerg Ciesielski
|
||||
* Contact : info@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__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* hfcs_usb.h, HFC-S USB mISDN driver
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#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__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,182 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* hw_lock.h Hardware locking inline routines
|
||||
*
|
||||
* Author Karsten Keil (keil@isdn4linux.de)
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
/* Description of the locking mechanism
|
||||
*
|
||||
* The locking must grant serialisized and atomic
|
||||
* access to the ISDN hardware registers, if the lock
|
||||
* is aquired no other process or IRQ is alloed to
|
||||
* access ISDN hardware registers.
|
||||
*
|
||||
* In general here are 3 possible entry points:
|
||||
* 1. the ISDN interrupt routine
|
||||
* 2. ISDN timer routines in the hardware module
|
||||
* 3. messages that came from upper layers
|
||||
*
|
||||
* Since most work must be do in the interrupt routine
|
||||
* (to grant minimum IRQ latency) and only few things with
|
||||
* need direct HW access must be done for messages from upper
|
||||
* layers, we should allow other IRQs in our IRQ routines and
|
||||
* only block our own routines in this case. Since the common IRQ
|
||||
* routines allready mask the same IRQ, we only need to protect us
|
||||
* from timer and uper layers. The disadvantage is, that we need to
|
||||
* disable local IRQ for the 2. and 3. points, but since the routines
|
||||
* which need hardware access are well known and small, the impact
|
||||
* is very small.
|
||||
*
|
||||
* We have a two stage locking to make this working:
|
||||
* A spinlock which protect the state LOCK Flag (STATE_FLAG_BUSY) and
|
||||
* also protect us from local IRQs from the entry points 2 and 3.
|
||||
*
|
||||
* In the hardware IRQ we aquire the spinlock, set the STATE_FLAG_BUSY
|
||||
* LOCK Flag and then release the spinlock. It can never happen that
|
||||
* the STATE_FLAG_BUSY is allready set in this case, see later.
|
||||
*
|
||||
* In the other cases (from timer or upper layers) we aquire the spinlock
|
||||
* test_and_set the STATE_FLAG_BUSY LOCK Flag, if it was allready set
|
||||
* (a ISDN IRQ is running on the other CPU) we schedule timeout or add a other
|
||||
* small timeout.
|
||||
* If it was not set, we have the lock and we don't release the spinlock until we have
|
||||
* done the harware work.
|
||||
*
|
||||
* To avoid any kind of deadlocking, it is important that we release the lock
|
||||
* before we call functions that deliver to upper layers.
|
||||
* To leave the impact of disabled local IRQ small, it is important to only protect
|
||||
* small areas where hardware is accessed.
|
||||
*
|
||||
* The following routines handle the lock in the entry point from upper layers and other
|
||||
* none IRQ cases (module init/exit stuff).
|
||||
*
|
||||
* They never called directly, but via the wrappers assigned to the instance
|
||||
* inst.lock / inst.unlock pointers.
|
||||
*
|
||||
* Here are two defines which can be used for DEBUGING and PROFILING
|
||||
* SPIN_DEBUG and LOCK_STATISTIC
|
||||
*
|
||||
*/
|
||||
#ifndef __hw_lock__
|
||||
#define __hw_lock__
|
||||
|
||||
typedef struct _mISDN_HWlock {
|
||||
u_long flags;
|
||||
spinlock_t lock;
|
||||
#ifdef SPIN_DEBUG
|
||||
void *spin_adr;
|
||||
void *busy_adr;
|
||||
#endif
|
||||
volatile u_int state;
|
||||
#ifdef LOCK_STATISTIC
|
||||
u_int try_ok;
|
||||
u_int try_wait;
|
||||
u_int try_inirq;
|
||||
u_int try_mult;
|
||||
u_int irq_ok;
|
||||
u_int irq_fail;
|
||||
#endif
|
||||
} mISDN_HWlock_t;
|
||||
|
||||
#define STATE_FLAG_BUSY 1
|
||||
#define STATE_FLAG_INIRQ 2
|
||||
|
||||
|
||||
/*
|
||||
* returns 0 if the lock was aquired
|
||||
* returns 1 if nowait != 0 and the lock is not aquired
|
||||
*/
|
||||
static inline int lock_HW(mISDN_HWlock_t *lock, int nowait)
|
||||
{
|
||||
register u_long flags;
|
||||
#ifdef LOCK_STATISTIC
|
||||
int wait = 0;
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&lock->lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->spin_adr = __builtin_return_address(0);
|
||||
#endif
|
||||
while (test_and_set_bit(STATE_FLAG_BUSY, &lock->state)) {
|
||||
/* allready busy so we delay */
|
||||
spin_unlock_irqrestore(&lock->lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->spin_adr = NULL;
|
||||
#endif
|
||||
if (nowait) {
|
||||
#ifdef LOCK_STATISTIC
|
||||
lock->try_wait++;
|
||||
#endif
|
||||
return(1);
|
||||
}
|
||||
/* delay 1 jiffie is enought */
|
||||
if (in_interrupt()) {
|
||||
/* Should never happen */
|
||||
#ifdef LOCK_STATISTIC
|
||||
lock->try_inirq++;
|
||||
#endif
|
||||
printk(KERN_ERR "lock_HW: try to schedule in IRQ state(%x)\n",
|
||||
lock->state);
|
||||
mdelay(1);
|
||||
} else {
|
||||
#ifdef LOCK_STATISTIC
|
||||
if (wait++)
|
||||
lock->try_mult++;
|
||||
else
|
||||
lock->try_wait++;
|
||||
#endif
|
||||
schedule_timeout(1);
|
||||
}
|
||||
spin_lock_irqsave(&lock->lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->spin_adr = __builtin_return_address(0);
|
||||
#endif
|
||||
}
|
||||
/* get the LOCK */
|
||||
lock->flags = flags;
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->busy_adr = __builtin_return_address(0);
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
if (!wait)
|
||||
lock->try_ok++;
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
static inline void unlock_HW(mISDN_HWlock_t *lock)
|
||||
{
|
||||
if (!test_and_clear_bit(STATE_FLAG_BUSY, &lock->state)) {
|
||||
printk(KERN_ERR "lock_HW: STATE_FLAG_BUSY not locked state(%x)\n",
|
||||
lock->state);
|
||||
}
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->busy_adr = NULL;
|
||||
lock->spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&lock->lock, lock->flags);
|
||||
}
|
||||
|
||||
static inline void lock_HW_init(mISDN_HWlock_t *lock)
|
||||
{
|
||||
spin_lock_init(&lock->lock);
|
||||
lock->state = 0;
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->busy_adr = NULL;
|
||||
lock->spin_adr = NULL;
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
lock->try_ok = 0;
|
||||
lock->try_wait = 0;
|
||||
lock->try_inirq = 0;
|
||||
lock->try_mult = 0;
|
||||
lock->irq_ok = 0;
|
||||
lock->irq_fail = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
|
@ -10,7 +10,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/isdnif.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -157,7 +156,7 @@ MODULE_AUTHOR("Karsten Keil");
|
|||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
MODULE_PARM(debug, "1i");
|
||||
module_param(debug, uint, S_IRUGO | S_IWUSR);
|
||||
#endif
|
||||
|
||||
static void
|
||||
|
@ -217,7 +216,7 @@ init_channel(i4l_capi_t *ic, int nr)
|
|||
ch->inst.pid.layermask = ISDN_LAYER(0);
|
||||
ch->inst.up.owner = &ch->inst;
|
||||
ch->inst.down.owner = &ch->inst;
|
||||
I4Lcapi.ctrl(NULL, MGR_DISCONNECT | REQUEST, &ch->inst.down);
|
||||
mISDN_ctrl(NULL, MGR_DISCONNECT | REQUEST, &ch->inst.down);
|
||||
sprintf(ch->inst.name, "%s B%d", ic->inst.name, nr+1);
|
||||
}
|
||||
|
||||
|
@ -283,7 +282,7 @@ sendup(i4l_channel_t *ch, int Dchannel, int prim, struct sk_buff *skb)
|
|||
hhe->prim = prim;
|
||||
hhe->dinfo = ch->l4id;
|
||||
if (ch->drv->debug & 0x4)
|
||||
LogL3Msg(skb);
|
||||
mISDN_LogL3Msg(skb);
|
||||
if (Dchannel)
|
||||
I = &ch->drv->inst;
|
||||
else
|
||||
|
@ -516,7 +515,7 @@ i4l_l1err(struct FsmInst *fi, int event, void *arg)
|
|||
|
||||
sendup(ch, 1, DL_RELEASE | INDICATION, NULL);
|
||||
reset_channel(ch);
|
||||
FsmChangeState(fi, ST_NULL);
|
||||
mISDN_FsmChangeState(fi, ST_NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -526,7 +525,7 @@ i4l_dhup(struct FsmInst *fi, int event, void *arg)
|
|||
struct sk_buff *skb;
|
||||
u_char tmp[8];
|
||||
|
||||
skb = alloc_l3msg(8, MT_RELEASE);
|
||||
skb = mISDN_alloc_l3msg(8, MT_RELEASE);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
|
@ -539,10 +538,10 @@ i4l_dhup(struct FsmInst *fi, int event, void *arg)
|
|||
tmp[2] = 0x80;
|
||||
tmp[3] = 0x9f; /* normal, unspecified */
|
||||
}
|
||||
AddvarIE(skb, tmp);
|
||||
mISDN_AddvarIE(skb, tmp);
|
||||
sendup(ch, 1, CC_RELEASE | INDICATION, skb);
|
||||
reset_channel(ch);
|
||||
FsmChangeState(fi, ST_NULL);
|
||||
mISDN_FsmChangeState(fi, ST_NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -572,7 +571,7 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
|
|||
printk(KERN_DEBUG "%s: l4id(%x) ch(%p)->nr %d\n", __FUNCTION__, ch->l4id, ch, ch->nr);
|
||||
} else
|
||||
return;
|
||||
skb = alloc_l3msg(260, MT_SETUP);
|
||||
skb = mISDN_alloc_l3msg(260, MT_SETUP);
|
||||
if (!skb)
|
||||
return;
|
||||
p = tmp;
|
||||
|
@ -593,11 +592,11 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
|
|||
*p++ = 0x90; /* Circuit-Mode 64kbps */
|
||||
break;
|
||||
}
|
||||
AddvarIE(skb, tmp);
|
||||
mISDN_AddvarIE(skb, tmp);
|
||||
tmp[0] = IE_CHANNEL_ID;
|
||||
tmp[1] = 1;
|
||||
tmp[2] = 0x85 + ch->nr;
|
||||
AddvarIE(skb, tmp);
|
||||
mISDN_AddvarIE(skb, tmp);
|
||||
if (setup->phone[0]) {
|
||||
i = 1;
|
||||
if (setup->plan) {
|
||||
|
@ -613,7 +612,7 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
|
|||
tmp[i++] = setup->phone[j++];
|
||||
}
|
||||
tmp[0] = i-1;
|
||||
AddIE(skb, IE_CALLING_PN, tmp);
|
||||
mISDN_AddIE(skb, IE_CALLING_PN, tmp);
|
||||
if (setup->phone[j] == '.') {
|
||||
i = 1;
|
||||
tmp[i++] = 0x80;
|
||||
|
@ -621,7 +620,7 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
|
|||
while (setup->phone[j])
|
||||
tmp[i++] = setup->phone[j++];
|
||||
tmp[0] = i-1;
|
||||
AddIE(skb, IE_CALLING_SUB, tmp);
|
||||
mISDN_AddIE(skb, IE_CALLING_SUB, tmp);
|
||||
}
|
||||
}
|
||||
if (setup->eazmsn[0]) {
|
||||
|
@ -634,7 +633,7 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
|
|||
tmp[i++] = setup->eazmsn[j++];
|
||||
}
|
||||
tmp[0] = i-1;
|
||||
AddIE(skb, IE_CALLED_PN, tmp);
|
||||
mISDN_AddIE(skb, IE_CALLED_PN, tmp);
|
||||
if (setup->eazmsn[j] == '.') {
|
||||
i = 1;
|
||||
tmp[i++] = 0x80;
|
||||
|
@ -642,7 +641,7 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
|
|||
while (setup->eazmsn[j])
|
||||
tmp[i++] = setup->eazmsn[j++];
|
||||
tmp[0] = i-1;
|
||||
AddIE(skb, IE_CALLED_SUB, tmp);
|
||||
mISDN_AddIE(skb, IE_CALLED_SUB, tmp);
|
||||
}
|
||||
}
|
||||
p = tmp;
|
||||
|
@ -688,8 +687,8 @@ i4l_icall(struct FsmInst *fi, int event, void *arg)
|
|||
break;
|
||||
}
|
||||
}
|
||||
AddvarIE(skb, tmp);
|
||||
FsmChangeState(fi, ST_ICALL);
|
||||
mISDN_AddvarIE(skb, tmp);
|
||||
mISDN_FsmChangeState(fi, ST_ICALL);
|
||||
sendup(ch, 1, CC_SETUP | INDICATION, skb);
|
||||
}
|
||||
|
||||
|
@ -700,16 +699,16 @@ i4l_dconn_out(struct FsmInst *fi, int event, void *arg)
|
|||
struct sk_buff *skb;
|
||||
u_char tmp[4];
|
||||
|
||||
skb = alloc_l3msg(4, MT_CONNECT);
|
||||
skb = mISDN_alloc_l3msg(4, MT_CONNECT);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
tmp[0] = IE_CHANNEL_ID;
|
||||
tmp[1] = 1;
|
||||
tmp[2] = 0x85 + ch->nr;
|
||||
AddvarIE(skb, tmp);
|
||||
mISDN_AddvarIE(skb, tmp);
|
||||
sendup(ch, 1, CC_CONNECT | INDICATION, skb);
|
||||
FsmChangeState(fi, ST_ACTIVD);
|
||||
mISDN_FsmChangeState(fi, ST_ACTIVD);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -718,7 +717,7 @@ i4l_dconn_in(struct FsmInst *fi, int event, void *arg)
|
|||
i4l_channel_t *ch = fi->userdata;
|
||||
|
||||
sendup(ch, 1, CC_CONNECT_ACKNOWLEDGE | INDICATION, NULL);
|
||||
FsmChangeState(fi, ST_ACTIVD);
|
||||
mISDN_FsmChangeState(fi, ST_ACTIVD);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -737,7 +736,7 @@ i4l_bconn(struct FsmInst *fi, int event, void *arg)
|
|||
|
||||
sendup(ch, 0, prim | INDICATION, NULL);
|
||||
test_and_set_bit(I4L_FLG_BCONN, &ch->Flags);
|
||||
FsmChangeState(fi, ST_ACTIVB);
|
||||
mISDN_FsmChangeState(fi, ST_ACTIVB);
|
||||
if (skb_queue_len(&ch->sendq))
|
||||
sendqueued(ch);
|
||||
}
|
||||
|
@ -748,7 +747,7 @@ 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;
|
||||
|
||||
FsmChangeState(fi, ST_ACTIVD);
|
||||
mISDN_FsmChangeState(fi, ST_ACTIVD);
|
||||
sendup(ch, 0, prim | INDICATION, NULL);
|
||||
}
|
||||
|
||||
|
@ -757,10 +756,10 @@ stackready(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
i4l_channel_t *ch = fi->userdata;
|
||||
|
||||
FsmChangeState(fi, ST_BREADY);
|
||||
mISDN_FsmChangeState(fi, ST_BREADY);
|
||||
test_and_set_bit(I4L_FLG_BREADY, &ch->Flags);
|
||||
if (test_bit(I4L_FLG_BCONN, &ch->Flags))
|
||||
FsmEvent(&ch->i4lm, EV_I4L_BCONN, NULL);
|
||||
mISDN_FsmEvent(&ch->i4lm, EV_I4L_BCONN, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -773,7 +772,7 @@ capi_ocall(struct FsmInst *fi, int event, void *arg)
|
|||
isdn_ctrl ctrl;
|
||||
int i,l;
|
||||
|
||||
FsmChangeState(fi, ST_OCALL);
|
||||
mISDN_FsmChangeState(fi, ST_OCALL);
|
||||
test_and_set_bit(I4L_FLG_LOCK, &ch->Flags);
|
||||
i4l_lock_drv(ch->drv);
|
||||
ps += L3_EXTRA_SIZE;
|
||||
|
@ -894,7 +893,7 @@ capi_alert(struct FsmInst *fi, int event, void *arg)
|
|||
i4l_channel_t *ch = fi->userdata;
|
||||
struct sk_buff *skb = arg;
|
||||
|
||||
FsmChangeState(fi, ST_ALERT);
|
||||
mISDN_FsmChangeState(fi, ST_ALERT);
|
||||
i4l_cmd(ch->drv, ch->nr, ISDN_CMD_ALERT);
|
||||
if (skb)
|
||||
dev_kfree_skb(skb);
|
||||
|
@ -913,7 +912,7 @@ capi_connect(struct FsmInst *fi, int event, void *arg)
|
|||
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);
|
||||
}
|
||||
FsmChangeState(fi, ST_WAITDCONN);
|
||||
mISDN_FsmChangeState(fi, ST_WAITDCONN);
|
||||
i4l_cmd(ch->drv, ch->nr, ISDN_CMD_ACCEPTD);
|
||||
if (skb)
|
||||
dev_kfree_skb(skb);
|
||||
|
@ -925,7 +924,7 @@ capi_disconnect(struct FsmInst *fi, int event, void *arg)
|
|||
i4l_channel_t *ch = fi->userdata;
|
||||
struct sk_buff *skb = arg;
|
||||
|
||||
FsmChangeState(fi, ST_HANGUP);
|
||||
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)
|
||||
|
@ -943,7 +942,7 @@ capi_release(struct FsmInst *fi, int event, void *arg)
|
|||
if (skb)
|
||||
dev_kfree_skb(skb);
|
||||
reset_channel(ch);
|
||||
FsmChangeState(fi, ST_NULL);
|
||||
mISDN_FsmChangeState(fi, ST_NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -960,7 +959,7 @@ capi_releaseb(struct FsmInst *fi, int event, void *arg)
|
|||
i4l_channel_t *ch = fi->userdata;
|
||||
|
||||
test_and_clear_bit(I4L_FLG_BREADY, &ch->Flags);
|
||||
FsmChangeState(fi, ST_ACTIVD);
|
||||
mISDN_FsmChangeState(fi, ST_ACTIVD);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1018,23 +1017,23 @@ Dchannel_i4l(mISDNif_t *hif, struct sk_buff *skb)
|
|||
return(ret);
|
||||
}
|
||||
if (ch->drv->debug & 0x4)
|
||||
LogL3Msg(skb);
|
||||
mISDN_LogL3Msg(skb);
|
||||
switch(hh->prim) {
|
||||
case CC_SETUP | REQUEST:
|
||||
ret = FsmEvent(&ch->i4lm, EV_CAPI_OCALL, skb);
|
||||
ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_OCALL, skb);
|
||||
break;
|
||||
case CC_ALERTING | REQUEST:
|
||||
ret = FsmEvent(&ch->i4lm, EV_CAPI_ALERT, skb);
|
||||
ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_ALERT, skb);
|
||||
break;
|
||||
case CC_CONNECT | REQUEST:
|
||||
ret = FsmEvent(&ch->i4lm, EV_CAPI_DCONNECT, skb);
|
||||
ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_DCONNECT, skb);
|
||||
break;
|
||||
case CC_DISCONNECT | REQUEST:
|
||||
case CC_RELEASE | REQUEST:
|
||||
ret = FsmEvent(&ch->i4lm, EV_CAPI_DISCONNECT, skb);
|
||||
ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_DISCONNECT, skb);
|
||||
break;
|
||||
case CC_RELEASE_COMPLETE | REQUEST:
|
||||
ret = FsmEvent(&ch->i4lm, EV_CAPI_RELEASE, skb);
|
||||
ret = mISDN_FsmEvent(&ch->i4lm, EV_CAPI_RELEASE, skb);
|
||||
break;
|
||||
default:
|
||||
if (debug)
|
||||
|
@ -1061,13 +1060,13 @@ Bchannel_i4l(mISDNif_t *hif, struct sk_buff *skb)
|
|||
switch(hh->prim) {
|
||||
case PH_ACTIVATE | REQUEST:
|
||||
case DL_ESTABLISH | REQUEST:
|
||||
FsmEvent(&ch->i4lm, EV_CAPI_ESTABLISHB, NULL);
|
||||
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:
|
||||
FsmEvent(&ch->i4lm, EV_CAPI_RELEASEB, NULL);
|
||||
mISDN_FsmEvent(&ch->i4lm, EV_CAPI_RELEASEB, NULL);
|
||||
skb_trim(skb, 0);
|
||||
ret = if_newhead(&ch->inst.up, hh->prim | CONFIRM, 0, skb);
|
||||
break;
|
||||
|
@ -1128,10 +1127,10 @@ static int
|
|||
i4l_stat_run(i4l_capi_t *ic) {
|
||||
int err;
|
||||
|
||||
err = I4Lcapi.ctrl(ic->inst.st, MGR_SETSTACK | REQUEST, &ic->pid);
|
||||
err = mISDN_ctrl(ic->inst.st, MGR_SETSTACK | REQUEST, &ic->pid);
|
||||
if (err) {
|
||||
printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", err);
|
||||
I4Lcapi.ctrl(ic->inst.st, MGR_DELSTACK | REQUEST, NULL);
|
||||
mISDN_ctrl(ic->inst.st, MGR_DELSTACK | REQUEST, NULL);
|
||||
return(err);
|
||||
}
|
||||
return(0);
|
||||
|
@ -1225,7 +1224,7 @@ I4Lcapi_status_callback(isdn_ctrl *c)
|
|||
if (c->arg < 0)
|
||||
return -1;
|
||||
ch += c->arg;
|
||||
ret = FsmEvent(&ch->i4lm, EV_I4L_ICALL, &c->parm.setup);
|
||||
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_ICALL, &c->parm.setup);
|
||||
break;
|
||||
case ISDN_STAT_CINF:
|
||||
if (c->arg < 0)
|
||||
|
@ -1257,32 +1256,32 @@ I4Lcapi_status_callback(isdn_ctrl *c)
|
|||
if (c->arg < 0)
|
||||
return -1;
|
||||
ch += c->arg;
|
||||
ret = FsmEvent(&ch->i4lm, EV_I4L_DCONN, NULL);
|
||||
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_DCONN, NULL);
|
||||
break;
|
||||
case ISDN_STAT_DHUP:
|
||||
if (c->arg < 0)
|
||||
return -1;
|
||||
ch += c->arg;
|
||||
ret = FsmEvent(&ch->i4lm, EV_I4L_DHUP, NULL);
|
||||
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_DHUP, NULL);
|
||||
break;
|
||||
case ISDN_STAT_BCONN:
|
||||
if (c->arg < 0)
|
||||
return -1;
|
||||
ch += c->arg;
|
||||
ret = FsmEvent(&ch->i4lm, EV_I4L_BCONN, NULL);
|
||||
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_BCONN, NULL);
|
||||
break;
|
||||
case ISDN_STAT_BHUP:
|
||||
if (c->arg < 0)
|
||||
return -1;
|
||||
ch += c->arg;
|
||||
ret = FsmEvent(&ch->i4lm, EV_I4L_BHUP, NULL);
|
||||
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 = FsmEvent(&ch->i4lm, EV_I4L_L1ERR, NULL);
|
||||
ret = mISDN_FsmEvent(&ch->i4lm, EV_I4L_L1ERR, NULL);
|
||||
break;
|
||||
case ISDN_STAT_ADDCH:
|
||||
case ISDN_STAT_DISCH:
|
||||
|
@ -1290,7 +1289,7 @@ I4Lcapi_status_callback(isdn_ctrl *c)
|
|||
ret = 0;
|
||||
break;
|
||||
case ISDN_STAT_UNLOAD:
|
||||
ret = I4Lcapi.ctrl(drv->inst.st, MGR_DELSTACK | REQUEST, NULL);
|
||||
ret = mISDN_ctrl(drv->inst.st, MGR_DELSTACK | REQUEST, NULL);
|
||||
MOD_DEC_USE_COUNT;
|
||||
break;
|
||||
case CAPI_PUT_MESSAGE:
|
||||
|
@ -1323,7 +1322,7 @@ I4Lcapi_manager(void *data, u_int prim, void *arg) {
|
|||
printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n",
|
||||
__FUNCTION__, data, prim, arg);
|
||||
if (prim == (MGR_HASPROTOCOL | REQUEST))
|
||||
return(HasProtocolP(&I4Lcapi, arg));
|
||||
return(mISDN_HasProtocolP(&I4Lcapi, arg));
|
||||
if (!data) {
|
||||
printk(KERN_ERR "I4Lcapi_manager no data prim %x arg %p\n",
|
||||
prim, arg);
|
||||
|
@ -1355,8 +1354,8 @@ I4Lcapi_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_REGLAYER | CONFIRM:
|
||||
break;
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
I4Lcapi.ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up);
|
||||
I4Lcapi.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
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) {
|
||||
|
@ -1366,21 +1365,21 @@ I4Lcapi_manager(void *data, u_int prim, void *arg) {
|
|||
}
|
||||
break;
|
||||
case MGR_CONNECT | REQUEST:
|
||||
return(ConnectIF(inst, arg));
|
||||
return(mISDN_ConnectIF(inst, arg));
|
||||
case MGR_SETIF | REQUEST:
|
||||
case MGR_SETIF | INDICATION:
|
||||
if (nr_ch == -1)
|
||||
return(SetIF(inst, arg, prim, Dchannel_i4l, NULL, card));
|
||||
return(mISDN_SetIF(inst, arg, prim, Dchannel_i4l, NULL, card));
|
||||
else
|
||||
return(SetIF(inst, arg, prim, Bchannel_i4l, NULL, channel));
|
||||
return(mISDN_SetIF(inst, arg, prim, Bchannel_i4l, NULL, channel));
|
||||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
return(DisConnectIF(inst, arg));
|
||||
case MGR_SETSTACK | CONFIRM:
|
||||
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);
|
||||
FsmEvent(&channel->i4lm, EV_STACKREADY, NULL);
|
||||
mISDN_FsmEvent(&channel->i4lm, EV_STACKREADY, NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1435,32 +1434,28 @@ I4Lcapi_register(isdn_if *iif)
|
|||
|
||||
APPEND_TO_LIST(drvmap[drvidx], ((i4l_capi_t *)I4Lcapi.ilist));
|
||||
drvmap[drvidx]->debug = debug;
|
||||
drvmap[drvidx]->inst.obj = &I4Lcapi;
|
||||
drvmap[drvidx]->inst.data = drvmap[drvidx];
|
||||
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;
|
||||
drvmap[drvidx]->inst.up.owner = &drvmap[drvidx]->inst;
|
||||
drvmap[drvidx]->inst.down.owner = &drvmap[drvidx]->inst;
|
||||
I4Lcapi.ctrl(NULL, MGR_DISCONNECT | REQUEST, &drvmap[drvidx]->inst.down);
|
||||
mISDN_init_instance(&drvmap[drvidx]->inst, &I4Lcapi, drvmap[drvidx]);
|
||||
sprintf(drvmap[drvidx]->inst.name, "Fritz%d", drvidx+1);
|
||||
set_dchannel_pid(&drvmap[drvidx]->pid, 2, 0);
|
||||
mISDN_set_dchannel_pid(&drvmap[drvidx]->pid, 2, 0);
|
||||
for (i=0; i < drvmap[drvidx]->nr_ch; i++) {
|
||||
init_channel(drvmap[drvidx], i);
|
||||
}
|
||||
err = I4Lcapi.ctrl(NULL, MGR_NEWSTACK | REQUEST, &drvmap[drvidx]->inst);
|
||||
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 = I4Lcapi.ctrl(drvmap[drvidx]->inst.st, MGR_NEWSTACK | REQUEST, &ch->inst);
|
||||
err = mISDN_ctrl(drvmap[drvidx]->inst.st, MGR_NEWSTACK | REQUEST, &ch->inst);
|
||||
if (err) {
|
||||
printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
|
||||
I4Lcapi.ctrl(drvmap[drvidx]->inst.st, MGR_DELSTACK | REQUEST, NULL);
|
||||
mISDN_ctrl(drvmap[drvidx]->inst.st, MGR_DELSTACK | REQUEST, NULL);
|
||||
return(err);
|
||||
}
|
||||
ch++;
|
||||
|
@ -1534,7 +1529,9 @@ I4Lcapi_init(void)
|
|||
int err;
|
||||
|
||||
printk(KERN_INFO "I4L CAPI interface modul version %s\n", mISDN_getrev(i4lcapi_revision));
|
||||
SET_MODULE_OWNER(&I4Lcapi);
|
||||
#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;
|
||||
|
@ -1550,10 +1547,10 @@ I4Lcapi_init(void)
|
|||
i4lfsm_s.event_count = EVENT_COUNT;
|
||||
i4lfsm_s.strEvent = strI4LEvent;
|
||||
i4lfsm_s.strState = strI4LState;
|
||||
FsmNew(&i4lfsm_s, I4LFnList, I4L_FN_COUNT);
|
||||
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);
|
||||
FsmFree(&i4lfsm_s);
|
||||
mISDN_FsmFree(&i4lfsm_s);
|
||||
return(err);
|
||||
}
|
||||
I4Lcapireg.register_func = I4Lcapi_register;
|
||||
|
@ -1578,7 +1575,7 @@ I4Lcapi_cleanup(void)
|
|||
I4Lcapi.refcnt);
|
||||
release_card(((i4l_capi_t *)I4Lcapi.ilist)->idx);
|
||||
}
|
||||
FsmFree(&i4lfsm_s);
|
||||
mISDN_FsmFree(&i4lfsm_s);
|
||||
unregister_i4lcapi();
|
||||
return;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -128,9 +128,9 @@ typedef struct isac_chip {
|
|||
|
||||
/* interface for the isac module */
|
||||
|
||||
extern int ISAC_init(dchannel_t *);
|
||||
extern void ISAC_free(dchannel_t *);
|
||||
extern int mISDN_isac_init(channel_t *);
|
||||
extern void mISDN_isac_free(channel_t *);
|
||||
|
||||
extern void ISAC_interrupt(dchannel_t *, u_char);
|
||||
extern void ISAC_clear_pending_ints(dchannel_t *);
|
||||
extern int ISAC_l1hw(mISDNif_t *, struct sk_buff *);
|
||||
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 *);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
typedef struct _isar_reg {
|
||||
unsigned int Flags;
|
||||
unsigned long Flags;
|
||||
volatile u_char bstat;
|
||||
volatile u_char iis;
|
||||
volatile u_char cmsb;
|
||||
|
@ -230,9 +230,9 @@ typedef struct _isar_hw {
|
|||
#define STFAX_ESCAPE 5
|
||||
#define STFAX_SILDET 6
|
||||
|
||||
extern int ISARVersion(bchannel_t *bch, char *s);
|
||||
extern void isar_int_main(bchannel_t *bch);
|
||||
extern int init_isar(bchannel_t *bch);
|
||||
extern void free_isar(bchannel_t *bch);
|
||||
extern int isar_down(mISDNif_t *, struct sk_buff *);
|
||||
extern int isar_load_firmware(bchannel_t *bch, u_char *buf, int size);
|
||||
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);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -8,13 +8,13 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define __NO_VERSION__
|
||||
#include <linux/module.h>
|
||||
#include <linux/mISDNif.h>
|
||||
#include "dss1.h"
|
||||
#include "helper.h"
|
||||
|
||||
|
||||
static signed char _l3_ie2pos[128] = {
|
||||
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,
|
||||
|
@ -22,58 +22,66 @@ static signed char _l3_ie2pos[128] = {
|
|||
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,-1,-1,27,28,-1,-1,29,30,31,-1
|
||||
24,25,-1,-1,26,-1,27,-1,28,29,-1,-1,30,31,32,-1
|
||||
};
|
||||
|
||||
static unsigned char _l3_pos2ie[32] = {
|
||||
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, 0x78, 0x79, 0x7c, 0x7d, 0x7e
|
||||
0x70, 0x71, 0x74, 0x76, 0x78, 0x79, 0x7c, 0x7d,
|
||||
0x7e
|
||||
};
|
||||
|
||||
signed int
|
||||
l3_ie2pos(u_char c)
|
||||
mISDN_l3_ie2pos(u_char c)
|
||||
{
|
||||
if (c>0x7f)
|
||||
return(-1);
|
||||
return(_l3_ie2pos[c]);
|
||||
return(_mISDN_l3_ie2pos[c]);
|
||||
}
|
||||
|
||||
unsigned char
|
||||
l3_pos2ie(int pos)
|
||||
mISDN_l3_pos2ie(int pos)
|
||||
{
|
||||
return(_l3_pos2ie[pos]);
|
||||
return(_mISDN_l3_pos2ie[pos]);
|
||||
}
|
||||
|
||||
void
|
||||
initQ931_info(Q931_info_t *qi) {
|
||||
mISDN_initQ931_info(Q931_info_t *qi) {
|
||||
memset(qi, 0, sizeof(Q931_info_t));
|
||||
};
|
||||
|
||||
struct sk_buff *
|
||||
alloc_l3msg(int len, u_char type)
|
||||
#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;
|
||||
|
||||
if (!(skb = alloc_skb(len + MAX_HEADER_LEN + L3_EXTRA_SIZE, GFP_ATOMIC))) {
|
||||
#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);
|
||||
}
|
||||
skb_reserve(skb, MAX_HEADER_LEN);
|
||||
qi = (Q931_info_t *)skb_put(skb, L3_EXTRA_SIZE +1);
|
||||
initQ931_info(qi);
|
||||
mISDN_initQ931_info(qi);
|
||||
qi->type = type;
|
||||
return (skb);
|
||||
}
|
||||
|
||||
void AddvarIE(struct sk_buff *skb, u_char *ie)
|
||||
void mISDN_AddvarIE(struct sk_buff *skb, u_char *ie)
|
||||
{
|
||||
u_char *p, *ps;
|
||||
u16 *ies;
|
||||
int l;
|
||||
Q931_info_t *qi = (Q931_info_t *)skb->data;
|
||||
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;
|
||||
|
@ -89,26 +97,45 @@ void AddvarIE(struct sk_buff *skb, u_char *ie)
|
|||
int_error();
|
||||
return;
|
||||
}
|
||||
l = 1;
|
||||
} else {
|
||||
if (_l3_ie2pos[*ie]<0) {
|
||||
if (ies->off) { /* already used, no dupes for single octett */
|
||||
int_error();
|
||||
return;
|
||||
}
|
||||
ies += _l3_ie2pos[*ie];
|
||||
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 = (u16)(p - ps);
|
||||
ies->off = (u16)(p - ps);
|
||||
memcpy(p, ie, l);
|
||||
}
|
||||
|
||||
void AddIE(struct sk_buff *skb, u_char ie, u_char *iep)
|
||||
void mISDN_AddIE(struct sk_buff *skb, u_char ie, u_char *iep)
|
||||
{
|
||||
u_char *p, *ps;
|
||||
u16 *ies;
|
||||
int l;
|
||||
Q931_info_t *qi = (Q931_info_t *)skb->data;
|
||||
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)
|
||||
|
@ -121,31 +148,69 @@ void AddIE(struct sk_buff *skb, u_char ie, u_char *iep)
|
|||
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 (_l3_ie2pos[ie]<0) {
|
||||
if (_mISDN_l3_ie2pos[ie]<0) {
|
||||
int_error();
|
||||
return;
|
||||
}
|
||||
ies += _l3_ie2pos[ie];
|
||||
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 = (u16)(p - ps);
|
||||
ies->off = (u16)(p - ps);
|
||||
*p++ = ie;
|
||||
if (l)
|
||||
memcpy(p, iep, l);
|
||||
}
|
||||
|
||||
void LogL3Msg(struct sk_buff *skb)
|
||||
ie_info_t *mISDN_get_last_repeated_ie(Q931_info_t *qi, ie_info_t *ie)
|
||||
{
|
||||
u_char *p,*ps, *t, tmp[32];
|
||||
u16 *ies;
|
||||
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;
|
||||
|
@ -160,19 +225,64 @@ void LogL3Msg(struct sk_buff *skb)
|
|||
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<32;i++) {
|
||||
if (ies[i]) {
|
||||
p = ps + ies[i];
|
||||
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>9) {
|
||||
if (j>40) {
|
||||
sprintf(t, " ...");
|
||||
break;
|
||||
}
|
||||
t += sprintf(t, " %02x", p[j+2]);
|
||||
}
|
||||
printk(KERN_DEBUG "L3Msg ies[%d] off(%d) ie(%02x/%02x) len(%d) %s\n",
|
||||
i, ies[i], _l3_pos2ie[i], *p, p[1], tmp);
|
||||
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);
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* vISDN LAPD/q.921 protocol implementation
|
||||
*
|
||||
* Copyright (C) 2004-2006 Daniele Orlandi
|
||||
*
|
||||
* Authors: Daniele "Vihai" Orlandi <daniele@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
|
|
@ -1,32 +1,29 @@
|
|||
/* $Id$
|
||||
*
|
||||
* mISDN_l1.c common low level stuff for I.430 layer1
|
||||
* mISDN_l1.c common low level stuff for I.430 layer1 TE mode
|
||||
*
|
||||
* Author Karsten Keil (keil@isdn4linux.de)
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
* For changes and modifications please read
|
||||
* ../../../Documentation/isdn/mISDN.cert
|
||||
* This file is released under the GPLv2
|
||||
*
|
||||
*/
|
||||
|
||||
static char *l1_revision = "$Revision$";
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include "core.h"
|
||||
#include "layer1.h"
|
||||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct _layer1 {
|
||||
struct _layer1 *prev;
|
||||
struct _layer1 *next;
|
||||
int Flags;
|
||||
struct FsmInst l1m;
|
||||
struct FsmTimer timer;
|
||||
int debug;
|
||||
int delay;
|
||||
mISDNinstance_t inst;
|
||||
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 */
|
||||
|
@ -36,7 +33,7 @@ typedef struct _status_info_l1 {
|
|||
int protocol;
|
||||
int status;
|
||||
int state;
|
||||
int Flags;
|
||||
u_long Flags;
|
||||
int T3;
|
||||
int delay;
|
||||
int debug;
|
||||
|
@ -47,9 +44,11 @@ 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 =
|
||||
|
@ -101,6 +100,7 @@ static char *strL1UState[] =
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef OBSOLETE
|
||||
enum {
|
||||
ST_L1_NULL,
|
||||
ST_L1_WAIT_ACT,
|
||||
|
@ -117,7 +117,7 @@ static char *strL1BState[] =
|
|||
"ST_L1_WAIT_DEACT",
|
||||
"ST_L1_ACTIV",
|
||||
};
|
||||
|
||||
#endif
|
||||
enum {
|
||||
EV_PH_ACTIVATE,
|
||||
EV_PH_DEACTIVATE,
|
||||
|
@ -125,7 +125,7 @@ enum {
|
|||
EV_DEACT_CNF,
|
||||
EV_DEACT_IND,
|
||||
EV_POWER_UP,
|
||||
EV_ANYSIG_IND,
|
||||
EV_ANYSIG_IND,
|
||||
EV_INFO2_IND,
|
||||
EV_INFO4_IND,
|
||||
EV_TIMER_DEACT,
|
||||
|
@ -143,7 +143,7 @@ static char *strL1Event[] =
|
|||
"EV_DEACT_CNF",
|
||||
"EV_DEACT_IND",
|
||||
"EV_POWER_UP",
|
||||
"EV_ANYSIG_IND",
|
||||
"EV_ANYSIG_IND",
|
||||
"EV_INFO2_IND",
|
||||
"EV_INFO4_IND",
|
||||
"EV_TIMER_DEACT",
|
||||
|
@ -160,26 +160,26 @@ l1m_debug(struct FsmInst *fi, char *fmt, ...)
|
|||
va_start(log.args, fmt);
|
||||
log.fmt = fmt;
|
||||
log.head = l1->inst.name;
|
||||
l1->inst.obj->ctrl(&l1->inst, MGR_DEBUGDATA | REQUEST, &log);
|
||||
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(if_link(&l1->inst.up, prim, dinfo, len, arg, 0));
|
||||
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(if_link(&l1->inst.down, prim, dinfo, len, arg, 0));
|
||||
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)
|
||||
{
|
||||
FsmChangeState(fi, ST_L1_F3);
|
||||
mISDN_FsmChangeState(fi, ST_L1_F3);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -187,7 +187,7 @@ l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer1_t *l1 = fi->userdata;
|
||||
|
||||
FsmChangeState(fi, ST_L1_F3);
|
||||
mISDN_FsmChangeState(fi, ST_L1_F3);
|
||||
if (test_bit(FLG_L1_ACTIVATING, &l1->Flags))
|
||||
l1down(l1, PH_CONTROL | REQUEST, HW_POWERUP, 0, NULL);
|
||||
}
|
||||
|
@ -197,8 +197,8 @@ l1_deact_req_s(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer1_t *l1 = fi->userdata;
|
||||
|
||||
FsmChangeState(fi, ST_L1_F3);
|
||||
FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -208,24 +208,22 @@ l1_power_up_s(struct FsmInst *fi, int event, void *arg)
|
|||
layer1_t *l1 = fi->userdata;
|
||||
|
||||
if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) {
|
||||
FsmChangeState(fi, ST_L1_F4);
|
||||
mISDN_FsmChangeState(fi, ST_L1_F4);
|
||||
l1down(l1, PH_SIGNAL | REQUEST, INFO3_P8, 0, NULL);
|
||||
FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
|
||||
test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
|
||||
} else
|
||||
FsmChangeState(fi, ST_L1_F3);
|
||||
mISDN_FsmChangeState(fi, ST_L1_F3);
|
||||
}
|
||||
|
||||
static void
|
||||
l1_go_F5(struct FsmInst *fi, int event, void *arg)
|
||||
{
|
||||
FsmChangeState(fi, ST_L1_F5);
|
||||
mISDN_FsmChangeState(fi, ST_L1_F5);
|
||||
}
|
||||
|
||||
static void
|
||||
l1_go_F8(struct FsmInst *fi, int event, void *arg)
|
||||
{
|
||||
FsmChangeState(fi, ST_L1_F8);
|
||||
mISDN_FsmChangeState(fi, ST_L1_F8);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -235,10 +233,10 @@ l1_info2_ind(struct FsmInst *fi, int event, void *arg)
|
|||
|
||||
#ifdef mISDN_UINTERFACE
|
||||
if (test_bit(FLG_L1_UINT, &l1->Flags))
|
||||
FsmChangeState(fi, ST_L1_SYNC2);
|
||||
mISDN_FsmChangeState(fi, ST_L1_SYNC2);
|
||||
else
|
||||
#endif
|
||||
FsmChangeState(fi, ST_L1_F6);
|
||||
mISDN_FsmChangeState(fi, ST_L1_F6);
|
||||
l1down(l1, PH_SIGNAL | REQUEST, INFO3_P8, 0, NULL);
|
||||
}
|
||||
|
||||
|
@ -249,17 +247,17 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg)
|
|||
|
||||
#ifdef mISDN_UINTERFACE
|
||||
if (test_bit(FLG_L1_UINT, &l1->Flags))
|
||||
FsmChangeState(fi, ST_L1_TRANS);
|
||||
mISDN_FsmChangeState(fi, ST_L1_TRANS);
|
||||
else
|
||||
#endif
|
||||
FsmChangeState(fi, ST_L1_F7);
|
||||
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))
|
||||
FsmDelTimer(&l1->timer, 4);
|
||||
mISDN_FsmDelTimer(&l1->timer, 4);
|
||||
if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) {
|
||||
if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags))
|
||||
FsmDelTimer(&l1->timer, 3);
|
||||
FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2);
|
||||
mISDN_FsmDelTimer(&l1->timer, 3);
|
||||
mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2);
|
||||
test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags);
|
||||
}
|
||||
}
|
||||
|
@ -270,17 +268,20 @@ 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);
|
||||
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) {
|
||||
FsmChangeState(fi, ST_L1_F3);
|
||||
mISDN_FsmChangeState(fi, ST_L1_F3);
|
||||
l1down(l1, PH_CONTROL | REQUEST, HW_POWERUP, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -296,6 +297,9 @@ l1_timer_act(struct FsmInst *fi, int event, void *arg)
|
|||
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
|
||||
|
@ -310,6 +314,9 @@ l1_timer_deact(struct FsmInst *fi, int event, void *arg)
|
|||
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
|
||||
|
@ -317,6 +324,8 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -390,8 +399,8 @@ l1_deact_req_u(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer1_t *l1 = fi->userdata;
|
||||
|
||||
FsmChangeState(fi, ST_L1_RESET);
|
||||
FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2);
|
||||
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);
|
||||
}
|
||||
|
@ -401,14 +410,14 @@ l1_power_up_u(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer1_t *l1 = fi->userdata;
|
||||
|
||||
FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
|
||||
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)
|
||||
{
|
||||
FsmChangeState(fi, ST_L1_DEACT);
|
||||
mISDN_FsmChangeState(fi, ST_L1_DEACT);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -444,14 +453,14 @@ static struct FsmNode L1UFnList[] =
|
|||
#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;
|
||||
|
||||
FsmChangeState(fi, ST_L1_WAIT_ACT);
|
||||
FsmRestartTimer(&l1->timer, l1->delay, EV_TIMER_ACT, NULL, 2);
|
||||
mISDN_FsmChangeState(fi, ST_L1_WAIT_ACT);
|
||||
mISDN_FsmRestartTimer(&l1->timer, l1->delay, EV_TIMER_ACT, NULL, 2);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -459,8 +468,8 @@ l1b_deactivate(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer1_t *l1 = fi->userdata;
|
||||
|
||||
FsmChangeState(fi, ST_L1_WAIT_DEACT);
|
||||
FsmRestartTimer(&l1->timer, 10, EV_TIMER_DEACT, NULL, 2);
|
||||
mISDN_FsmChangeState(fi, ST_L1_WAIT_DEACT);
|
||||
mISDN_FsmRestartTimer(&l1->timer, 10, EV_TIMER_DEACT, NULL, 2);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -468,7 +477,7 @@ l1b_timer_act(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer1_t *l1 = fi->userdata;
|
||||
|
||||
FsmChangeState(fi, ST_L1_ACTIV);
|
||||
mISDN_FsmChangeState(fi, ST_L1_ACTIV);
|
||||
l1up(l1, PH_ACTIVATE | CONFIRM, 0, 0, NULL);
|
||||
}
|
||||
|
||||
|
@ -477,7 +486,7 @@ l1b_timer_deact(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer1_t *l1 = fi->userdata;
|
||||
|
||||
FsmChangeState(fi, ST_L1_NULL);
|
||||
mISDN_FsmChangeState(fi, ST_L1_NULL);
|
||||
l1up(l1, PH_DEACTIVATE | CONFIRM, 0, 0, NULL);
|
||||
}
|
||||
|
||||
|
@ -490,44 +499,32 @@ static struct FsmNode L1BFnList[] =
|
|||
};
|
||||
|
||||
#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
|
||||
#endif
|
||||
|
||||
static int
|
||||
l1from_up(mISDNif_t *hif, struct sk_buff *skb)
|
||||
l1from_up(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
|
||||
{
|
||||
layer1_t *l1;
|
||||
mISDN_head_t *hh;
|
||||
int err = 0;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
return(-EINVAL);
|
||||
l1 = hif->fdata;
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
switch(hh->prim) {
|
||||
case (PH_DATA | REQUEST):
|
||||
case (PH_CONTROL | REQUEST):
|
||||
if (l1->inst.down.func)
|
||||
return(l1->inst.down.func(&l1->inst.down,
|
||||
skb));
|
||||
else
|
||||
err = -ENXIO;
|
||||
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);
|
||||
FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL);
|
||||
mISDN_FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL);
|
||||
}
|
||||
break;
|
||||
case (MDL_FINDTEI | REQUEST):
|
||||
if (l1->inst.up.func)
|
||||
return(l1->inst.up.func(&l1->inst.up, skb));
|
||||
else
|
||||
err = -ENXIO;
|
||||
return(mISDN_queue_up(&l1->inst, 0, skb));
|
||||
break;
|
||||
default:
|
||||
if (l1->debug)
|
||||
mISDNdebug(l1->inst.st->id, NULL,
|
||||
mISDN_debug(l1->inst.st->id, NULL,
|
||||
"l1from_up msg %x unhandled", hh->prim);
|
||||
err = -EINVAL;
|
||||
break;
|
||||
|
@ -538,61 +535,49 @@ l1from_up(mISDNif_t *hif, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
static int
|
||||
l1from_down(mISDNif_t *hif, struct sk_buff *skb)
|
||||
l1from_down(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
|
||||
{
|
||||
layer1_t *l1;
|
||||
mISDN_head_t *hh;
|
||||
int err = 0;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
return(-EINVAL);
|
||||
l1 = hif->fdata;
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
if (hh->prim == PH_DATA_IND) {
|
||||
if (test_bit(FLG_L1_ACTTIMER, &l1->Flags))
|
||||
FsmEvent(&l1->l1m, EV_TIMER_ACT, NULL);
|
||||
if (l1->inst.up.func)
|
||||
return(l1->inst.up.func(&l1->inst.up, skb));
|
||||
else
|
||||
err = -ENXIO;
|
||||
mISDN_FsmEvent(&l1->l1m, EV_TIMER_ACT, NULL);
|
||||
return(mISDN_queue_up(&l1->inst, 0, skb));
|
||||
} else if (hh->prim == PH_DATA_CNF) {
|
||||
if (l1->inst.up.func)
|
||||
return(l1->inst.up.func(&l1->inst.up, skb));
|
||||
else
|
||||
err = -ENXIO;
|
||||
return(mISDN_queue_up(&l1->inst, 0, skb));
|
||||
} else if (hh->prim == (PH_CONTROL | INDICATION)) {
|
||||
if (hh->dinfo == HW_RESET)
|
||||
FsmEvent(&l1->l1m, EV_RESET_IND, NULL);
|
||||
mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL);
|
||||
else if (hh->dinfo == HW_DEACTIVATE)
|
||||
FsmEvent(&l1->l1m, EV_DEACT_IND, NULL);
|
||||
mISDN_FsmEvent(&l1->l1m, EV_DEACT_IND, NULL);
|
||||
else if (hh->dinfo == HW_POWERUP)
|
||||
FsmEvent(&l1->l1m, EV_POWER_UP, NULL);
|
||||
mISDN_FsmEvent(&l1->l1m, EV_POWER_UP, NULL);
|
||||
else if (l1->debug)
|
||||
mISDNdebug(l1->inst.st->id, NULL,
|
||||
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)
|
||||
FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL);
|
||||
if (hh->dinfo == HW_DEACTIVATE)
|
||||
mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL);
|
||||
else if (l1->debug)
|
||||
mISDNdebug(l1->inst.st->id, NULL,
|
||||
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)
|
||||
FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
|
||||
mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
|
||||
else if (hh->dinfo == LOSTFRAMING)
|
||||
FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
|
||||
mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);
|
||||
else if (hh->dinfo == INFO2)
|
||||
FsmEvent(&l1->l1m, EV_INFO2_IND, NULL);
|
||||
mISDN_FsmEvent(&l1->l1m, EV_INFO2_IND, NULL);
|
||||
else if (hh->dinfo == INFO4_P8)
|
||||
FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
|
||||
mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
|
||||
else if (hh->dinfo == INFO4_P10)
|
||||
FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
|
||||
mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);
|
||||
else if (l1->debug)
|
||||
mISDNdebug(l1->inst.st->id, NULL,
|
||||
mISDN_debug(l1->inst.st->id, NULL,
|
||||
"l1from_down sig %x unhandled", hh->dinfo);
|
||||
} else {
|
||||
if (l1->debug)
|
||||
mISDNdebug(l1->inst.st->id, NULL,
|
||||
mISDN_debug(l1->inst.st->id, NULL,
|
||||
"l1from_down msg %x unhandled", hh->prim);
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
@ -601,11 +586,67 @@ l1from_down(mISDNif_t *hif, struct sk_buff *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;
|
||||
|
||||
FsmDelTimer(&l1->timer, 0);
|
||||
mISDN_FsmDelTimer(&l1->timer, 0);
|
||||
#ifdef OBSOLETE
|
||||
if (inst->up.peer) {
|
||||
inst->up.peer->obj->ctrl(inst->up.peer,
|
||||
MGR_DISCONNECT | REQUEST, &inst->up);
|
||||
|
@ -614,15 +655,19 @@ release_l1(layer1_t *l1) {
|
|||
inst->down.peer->obj->ctrl(inst->down.peer,
|
||||
MGR_DISCONNECT | REQUEST, &inst->down);
|
||||
}
|
||||
REMOVE_FROM_LISTBASE(l1, ((layer1_t *)isdnl1.ilist));
|
||||
isdnl1.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
#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;
|
||||
layer1_t *nl1;
|
||||
int err;
|
||||
u_long flags;
|
||||
|
||||
if (!st || !pid)
|
||||
return(-EINVAL);
|
||||
|
@ -632,15 +677,14 @@ new_l1(mISDNstack_t *st, mISDN_pid_t *pid) {
|
|||
}
|
||||
memset(nl1, 0, sizeof(layer1_t));
|
||||
memcpy(&nl1->inst.pid, pid, sizeof(mISDN_pid_t));
|
||||
nl1->inst.obj = &isdnl1;
|
||||
nl1->inst.data = nl1;
|
||||
if (!SetHandledPID(&isdnl1, &nl1->inst.pid)) {
|
||||
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 %d", st->id);
|
||||
sprintf(nl1->inst.name, "l1TES0 %x", st->id >> 8);
|
||||
nl1->l1m.fsm = &l1fsm_s;
|
||||
nl1->l1m.state = ST_L1_F3;
|
||||
nl1->Flags = 0;
|
||||
|
@ -656,14 +700,14 @@ new_l1(mISDNstack_t *st, mISDN_pid_t *pid) {
|
|||
nl1->l1m.userdata = nl1;
|
||||
nl1->l1m.userint = 0;
|
||||
nl1->l1m.printdebug = l1m_debug;
|
||||
FsmInitTimer(&nl1->l1m, &nl1->timer);
|
||||
nl1->inst.up.owner = &nl1->inst;
|
||||
nl1->inst.down.owner = &nl1->inst;
|
||||
APPEND_TO_LIST(nl1, ((layer1_t *)isdnl1.ilist));
|
||||
err = isdnl1.ctrl(st, MGR_REGLAYER | INDICATION, &nl1->inst);
|
||||
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) {
|
||||
FsmDelTimer(&nl1->timer, 0);
|
||||
REMOVE_FROM_LISTBASE(nl1, ((layer1_t *)isdnl1.ilist));
|
||||
mISDN_FsmDelTimer(&nl1->timer, 0);
|
||||
list_del(&nl1->list);
|
||||
kfree(nl1);
|
||||
}
|
||||
return(err);
|
||||
|
@ -693,7 +737,11 @@ 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
|
||||
|
@ -702,62 +750,64 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
static int
|
||||
l1_manager(void *data, u_int prim, void *arg) {
|
||||
mISDNinstance_t *inst = data;
|
||||
layer1_t *l1l = isdnl1.ilist;
|
||||
mISDNinstance_t *inst = data;
|
||||
layer1_t *l1l;
|
||||
int err = -EINVAL;
|
||||
u_long flags;
|
||||
|
||||
printk(KERN_DEBUG "l1_manager data:%p prim:%x arg:%p\n", data, prim, arg);
|
||||
if (debug & 0x10000)
|
||||
printk(KERN_DEBUG "%s: data(%p) prim(%x) arg(%p)\n",
|
||||
__FUNCTION__, data, prim, arg);
|
||||
if (!data)
|
||||
return(-EINVAL);
|
||||
while(l1l) {
|
||||
if (&l1l->inst == inst)
|
||||
return(err);
|
||||
spin_lock_irqsave(&isdnl1.lock, flags);
|
||||
list_for_each_entry(l1l, &isdnl1.ilist, list) {
|
||||
if (&l1l->inst == inst) {
|
||||
err = 0;
|
||||
break;
|
||||
l1l = l1l->next;
|
||||
}
|
||||
}
|
||||
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:
|
||||
return(new_l1(data, arg));
|
||||
err = new_l1(data, arg);
|
||||
break;
|
||||
#ifdef OBSOLETE
|
||||
case MGR_CONNECT | REQUEST:
|
||||
if (!l1l) {
|
||||
printk(KERN_WARNING "l1_manager connect no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
return(ConnectIF(inst, arg));
|
||||
err = mISDN_ConnectIF(inst, arg);
|
||||
break;
|
||||
case MGR_SETIF | REQUEST:
|
||||
case MGR_SETIF | INDICATION:
|
||||
if (!l1l) {
|
||||
printk(KERN_WARNING "l1_manager setif no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
return(SetIF(inst, arg, prim, l1from_up, l1from_down, l1l));
|
||||
err = mISDN_SetIF(inst, arg, prim, l1from_up, l1from_down, l1l);
|
||||
break;
|
||||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
if (!l1l) {
|
||||
printk(KERN_WARNING "l1_manager disconnect no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
return(DisConnectIF(inst, arg));
|
||||
err = mISDN_DisConnectIF(inst, arg);
|
||||
break;
|
||||
#endif
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
case MGR_RELEASE | INDICATION:
|
||||
if (l1l) {
|
||||
printk(KERN_DEBUG "release_l1 id %x\n", l1l->inst.st->id);
|
||||
release_l1(l1l);
|
||||
} else
|
||||
printk(KERN_WARNING "l1_manager release no instance\n");
|
||||
break;
|
||||
printk(KERN_DEBUG "release_l1 id %x\n", l1l->inst.st->id);
|
||||
release_l1(l1l);
|
||||
break;
|
||||
case MGR_STATUS | REQUEST:
|
||||
if (!l1l) {
|
||||
printk(KERN_WARNING "l1_manager status l1 no instance\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
return(l1_status(l1l, arg));
|
||||
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);
|
||||
return(-EINVAL);
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
return(err);
|
||||
}
|
||||
|
||||
int Isdnl1Init(void)
|
||||
|
@ -765,59 +815,70 @@ int Isdnl1Init(void)
|
|||
int err;
|
||||
|
||||
printk(KERN_INFO "ISDN L1 driver version %s\n", mISDN_getrev(l1_revision));
|
||||
SET_MODULE_OWNER(&isdnl1);
|
||||
#ifdef MODULE
|
||||
isdnl1.owner = THIS_MODULE;
|
||||
#endif
|
||||
isdnl1.name = MName;
|
||||
isdnl1.DPROTO.protocol[1] = ISDN_PID_L1_TE_S0;
|
||||
isdnl1.own_ctrl = l1_manager;
|
||||
isdnl1.prev = NULL;
|
||||
isdnl1.next = NULL;
|
||||
isdnl1.ilist = NULL;
|
||||
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;
|
||||
FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
|
||||
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;
|
||||
FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
|
||||
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;
|
||||
FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
|
||||
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
|
||||
FsmFree(&l1fsm_u);
|
||||
mISDN_FsmFree(&l1fsm_u);
|
||||
#endif
|
||||
FsmFree(&l1fsm_s);
|
||||
FsmFree(&l1fsm_b);
|
||||
}
|
||||
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;
|
||||
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(isdnl1.ilist) {
|
||||
if(!list_empty(&isdnl1.ilist)) {
|
||||
printk(KERN_WARNING "mISDNl1 inst list not empty\n");
|
||||
while(isdnl1.ilist)
|
||||
release_l1(isdnl1.ilist);
|
||||
list_for_each_entry_safe(l1, nl1, &isdnl1.ilist, list)
|
||||
release_l1(l1);
|
||||
}
|
||||
#ifdef mISDN_UINTERFACE
|
||||
FsmFree(&l1fsm_u);
|
||||
mISDN_FsmFree(&l1fsm_u);
|
||||
#endif
|
||||
mISDN_FsmFree(&l1fsm_s);
|
||||
#ifdef OBSOLETE
|
||||
mISDN_FsmFree(&l1fsm_b);
|
||||
#endif
|
||||
FsmFree(&l1fsm_s);
|
||||
FsmFree(&l1fsm_b);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
|
||||
#include <linux/mISDNif.h>
|
||||
#include "fsm.h"
|
||||
#ifdef MEMDBG
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
#ifdef OBSOLETE
|
||||
#define D_RCVBUFREADY 0
|
||||
#define D_XMTBUFREADY 1
|
||||
#define D_L1STATECHANGE 2
|
||||
|
@ -21,10 +22,18 @@
|
|||
#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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,7 +9,7 @@
|
|||
#include <linux/mISDNif.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include "fsm.h"
|
||||
#ifdef MEMDBG
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
|
@ -30,29 +30,31 @@ typedef struct _laddr {
|
|||
} laddr_t;
|
||||
|
||||
typedef struct _layer2 {
|
||||
struct _layer2 *prev;
|
||||
struct _layer2 *next;
|
||||
int sapi;
|
||||
int tei;
|
||||
laddr_t addr;
|
||||
int maxlen;
|
||||
teimgr_t *tm;
|
||||
u_int flag;
|
||||
u_int vs, va, vr;
|
||||
int rc;
|
||||
u_int window;
|
||||
u_int sow;
|
||||
struct FsmInst l2m;
|
||||
struct FsmTimer t200, t203;
|
||||
int T200, N200, T203;
|
||||
int debug;
|
||||
mISDNinstance_t inst;
|
||||
mISDNif_t *cloneif;
|
||||
struct sk_buff *windowar[MAX_WINDOW];
|
||||
struct sk_buff *down_skb;
|
||||
struct sk_buff_head i_queue;
|
||||
struct sk_buff_head ui_queue;
|
||||
struct sk_buff_head down_queue;
|
||||
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 */
|
||||
|
@ -64,8 +66,8 @@ typedef struct _status_info_l2 {
|
|||
int sapi;
|
||||
int tei;
|
||||
laddr_t addr;
|
||||
int maxlen;
|
||||
u_int flag;
|
||||
u_int maxlen;
|
||||
u_long flag;
|
||||
u_int vs;
|
||||
u_int va;
|
||||
u_int vr;
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
* Fritz Elfert
|
||||
*
|
||||
*/
|
||||
#define __NO_VERSION__
|
||||
#include "layer3.h"
|
||||
#include "helper.h"
|
||||
#include "dss1.h"
|
||||
|
||||
const char *l3_revision = "$Revision$";
|
||||
|
||||
|
@ -70,7 +70,7 @@ l3m_debug(struct FsmInst *fi, char *fmt, ...)
|
|||
va_start(log.args, fmt);
|
||||
log.fmt = fmt;
|
||||
log.head = l3->inst.name;
|
||||
l3->inst.obj->ctrl(&l3->inst, MGR_DEBUGDATA | REQUEST, &log);
|
||||
mISDN_ctrl(&l3->inst, MGR_DEBUGDATA | REQUEST, &log);
|
||||
va_end(log.args);
|
||||
}
|
||||
|
||||
|
@ -82,10 +82,22 @@ l3_debug(layer3_t *l3, char *fmt, ...)
|
|||
va_start(log.args, fmt);
|
||||
log.fmt = fmt;
|
||||
log.head = l3->inst.name;
|
||||
l3->inst.obj->ctrl(&l3->inst, MGR_DEBUGDATA | REQUEST, &log);
|
||||
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)
|
||||
{
|
||||
|
@ -146,16 +158,19 @@ getcallref(u_char * p)
|
|||
return (cr);
|
||||
}
|
||||
|
||||
static int OrigCallRef = 0;
|
||||
|
||||
int
|
||||
newcallref(void)
|
||||
newcallref(layer3_t *l3)
|
||||
{
|
||||
if (OrigCallRef == 127)
|
||||
OrigCallRef = 1;
|
||||
int max = 127;
|
||||
|
||||
if (test_bit(FLG_CRLEN2, &l3->Flag))
|
||||
max = 32767;
|
||||
|
||||
if (l3->OrigCallRef >= max)
|
||||
l3->OrigCallRef = 1;
|
||||
else
|
||||
OrigCallRef++;
|
||||
return (OrigCallRef);
|
||||
l3->OrigCallRef++;
|
||||
return (l3->OrigCallRef);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -214,18 +229,6 @@ StopAllL3Timer(l3_process_t *pc)
|
|||
}
|
||||
}
|
||||
|
||||
struct sk_buff *
|
||||
l3_alloc_skb(int len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!(skb = alloc_skb(len + MAX_HEADER_LEN + IFRAME_HEAD_SIZE, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING "mISDN: No skb for D-channel\n");
|
||||
return (NULL);
|
||||
}
|
||||
skb_reserve(skb, MAX_HEADER_LEN + IFRAME_HEAD_SIZE);
|
||||
return (skb);
|
||||
}
|
||||
/*
|
||||
static void
|
||||
no_l3_proto(struct PStack *st, int pr, void *arg)
|
||||
|
@ -249,44 +252,74 @@ no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
|
|||
l3_process_t
|
||||
*getl3proc(layer3_t *l3, int cr)
|
||||
{
|
||||
l3_process_t *p = l3->proc;
|
||||
|
||||
while (p)
|
||||
l3_process_t *p;
|
||||
|
||||
list_for_each_entry(p, &l3->plist, list)
|
||||
if (p->callref == cr)
|
||||
return (p);
|
||||
else
|
||||
p = p->next;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
l3_process_t
|
||||
*getl3proc4id(layer3_t *l3, int id)
|
||||
{
|
||||
l3_process_t *p = l3->proc;
|
||||
|
||||
while (p)
|
||||
if (p->id == id)
|
||||
return (p);
|
||||
else
|
||||
p = p->next;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
l3_process_t
|
||||
*new_l3_process(layer3_t *l3, int cr, int n303)
|
||||
*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);
|
||||
APPEND_TO_LIST(p, l3->proc);
|
||||
L3InitTimer(p, &p->aux_timer);
|
||||
list_add_tail(&p->list, &l3->plist);
|
||||
return (p);
|
||||
};
|
||||
|
||||
|
@ -299,16 +332,16 @@ release_l3_process(l3_process_t *p)
|
|||
return;
|
||||
l3 = p->l3;
|
||||
mISDN_l3up(p, CC_RELEASE_CR | INDICATION, NULL);
|
||||
REMOVE_FROM_LISTBASE(p, l3->proc);
|
||||
list_del(&p->list);
|
||||
StopAllL3Timer(p);
|
||||
kfree(p);
|
||||
if (!l3->proc && !test_bit(FLG_PTP, &l3->Flag)) {
|
||||
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");
|
||||
FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
|
||||
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
|
||||
} else {
|
||||
if (l3->debug)
|
||||
l3_debug(l3, "release_l3_process: not release link");
|
||||
|
@ -319,15 +352,10 @@ release_l3_process(l3_process_t *p)
|
|||
static void
|
||||
l3ml3p(layer3_t *l3, int pr)
|
||||
{
|
||||
l3_process_t *p = l3->proc;
|
||||
l3_process_t *np;
|
||||
l3_process_t *p, *np;
|
||||
|
||||
while (p) {
|
||||
/* p might be kfreed under us, so we need to save where we want to go on */
|
||||
np = p->next;
|
||||
list_for_each_entry_safe(p, np, &l3->plist, list)
|
||||
l3->p_mgr(p, pr, NULL);
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -340,9 +368,9 @@ mISDN_l3up(l3_process_t *l3p, u_int prim, struct sk_buff *skb)
|
|||
return(-EINVAL);
|
||||
l3 = l3p->l3;
|
||||
if (!skb)
|
||||
err = if_link(&l3->inst.up, prim, l3p->id, 0, NULL, 0);
|
||||
err = mISDN_queue_data(&l3->inst, FLG_MSG_UP, prim, l3p->id, 0, NULL, 0);
|
||||
else
|
||||
err = if_newhead(&l3->inst.up, prim, l3p->id, skb);
|
||||
err = mISDN_queueup_newhead(&l3->inst, 0, prim, l3p->id, skb);
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
@ -351,9 +379,9 @@ l3down(layer3_t *l3, u_int prim, int dinfo, struct sk_buff *skb) {
|
|||
int err = -EINVAL;
|
||||
|
||||
if (!skb)
|
||||
err = if_link(&l3->inst.down, prim, dinfo, 0, NULL, 0);
|
||||
err = mISDN_queue_data(&l3->inst, FLG_MSG_DOWN, prim, dinfo, 0, NULL, 0);
|
||||
else
|
||||
err = if_newhead(&l3->inst.down, prim, dinfo, skb);
|
||||
err = mISDN_queuedown_newhead(&l3->inst, 0, prim, dinfo, skb);
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
@ -364,7 +392,7 @@ lc_activate(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer3_t *l3 = fi->userdata;
|
||||
|
||||
FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
|
||||
mISDN_FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
|
||||
l3down(l3, DL_ESTABLISH | REQUEST, 0, NULL);
|
||||
}
|
||||
|
||||
|
@ -375,16 +403,16 @@ lc_connect(struct FsmInst *fi, int event, void *arg)
|
|||
struct sk_buff *skb;
|
||||
int dequeued = 0;
|
||||
|
||||
FsmChangeState(fi, ST_L3_LC_ESTAB);
|
||||
mISDN_FsmChangeState(fi, ST_L3_LC_ESTAB);
|
||||
while ((skb = skb_dequeue(&l3->squeue))) {
|
||||
if (l3down(l3, DL_DATA | REQUEST, DINFO_SKB, skb))
|
||||
if (l3down(l3, DL_DATA | REQUEST, l3_newid(l3), skb))
|
||||
dev_kfree_skb(skb);
|
||||
dequeued++;
|
||||
}
|
||||
if ((!l3->proc) && dequeued) {
|
||||
if (list_empty(&l3->plist) && dequeued) {
|
||||
if (l3->debug)
|
||||
l3m_debug(fi, "lc_connect: release link");
|
||||
FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
|
||||
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
|
||||
} else
|
||||
l3ml3p(l3, DL_ESTABLISH | INDICATION);
|
||||
}
|
||||
|
@ -396,17 +424,17 @@ lc_connected(struct FsmInst *fi, int event, void *arg)
|
|||
struct sk_buff *skb;
|
||||
int dequeued = 0;
|
||||
|
||||
FsmDelTimer(&l3->l3m_timer, 51);
|
||||
FsmChangeState(fi, ST_L3_LC_ESTAB);
|
||||
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, DINFO_SKB, skb))
|
||||
if (l3down(l3, DL_DATA | REQUEST, l3_newid(l3), skb))
|
||||
dev_kfree_skb(skb);
|
||||
dequeued++;
|
||||
}
|
||||
if ((!l3->proc) && dequeued) {
|
||||
if (list_empty(&l3->plist) && dequeued) {
|
||||
if (l3->debug)
|
||||
l3m_debug(fi, "lc_connected: release link");
|
||||
FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
|
||||
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
|
||||
} else
|
||||
l3ml3p(l3, DL_ESTABLISH | CONFIRM);
|
||||
}
|
||||
|
@ -416,8 +444,8 @@ lc_start_delay(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer3_t *l3 = fi->userdata;
|
||||
|
||||
FsmChangeState(fi, ST_L3_LC_REL_DELAY);
|
||||
FsmAddTimer(&l3->l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
|
||||
mISDN_FsmChangeState(fi, ST_L3_LC_REL_DELAY);
|
||||
mISDN_FsmAddTimer(&l3->l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -429,9 +457,9 @@ lc_release_req(struct FsmInst *fi, int event, void *arg)
|
|||
if (l3->debug)
|
||||
l3m_debug(fi, "lc_release_req: l2 blocked");
|
||||
/* restart release timer */
|
||||
FsmAddTimer(&l3->l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
|
||||
mISDN_FsmAddTimer(&l3->l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
|
||||
} else {
|
||||
FsmChangeState(fi, ST_L3_LC_REL_WAIT);
|
||||
mISDN_FsmChangeState(fi, ST_L3_LC_REL_WAIT);
|
||||
l3down(l3, DL_RELEASE | REQUEST, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -441,8 +469,8 @@ lc_release_ind(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer3_t *l3 = fi->userdata;
|
||||
|
||||
FsmDelTimer(&l3->l3m_timer, 52);
|
||||
FsmChangeState(fi, ST_L3_LC_REL);
|
||||
mISDN_FsmDelTimer(&l3->l3m_timer, 52);
|
||||
mISDN_FsmChangeState(fi, ST_L3_LC_REL);
|
||||
discard_queue(&l3->squeue);
|
||||
l3ml3p(l3, DL_RELEASE | INDICATION);
|
||||
}
|
||||
|
@ -452,7 +480,7 @@ lc_release_cnf(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer3_t *l3 = fi->userdata;
|
||||
|
||||
FsmChangeState(fi, ST_L3_LC_REL);
|
||||
mISDN_FsmChangeState(fi, ST_L3_LC_REL);
|
||||
discard_queue(&l3->squeue);
|
||||
l3ml3p(l3, DL_RELEASE | CONFIRM);
|
||||
}
|
||||
|
@ -485,33 +513,33 @@ 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, dinfo, arg));
|
||||
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);
|
||||
FsmEvent(&l3->l3m, EV_ESTABLISH_REQ, NULL);
|
||||
mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_REQ, NULL);
|
||||
}
|
||||
break;
|
||||
case (DL_ESTABLISH | REQUEST):
|
||||
FsmEvent(&l3->l3m, EV_ESTABLISH_REQ, NULL);
|
||||
mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_REQ, NULL);
|
||||
break;
|
||||
case (DL_ESTABLISH | CONFIRM):
|
||||
FsmEvent(&l3->l3m, EV_ESTABLISH_CNF, NULL);
|
||||
mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_CNF, NULL);
|
||||
break;
|
||||
case (DL_ESTABLISH | INDICATION):
|
||||
FsmEvent(&l3->l3m, EV_ESTABLISH_IND, NULL);
|
||||
mISDN_FsmEvent(&l3->l3m, EV_ESTABLISH_IND, NULL);
|
||||
break;
|
||||
case (DL_RELEASE | INDICATION):
|
||||
FsmEvent(&l3->l3m, EV_RELEASE_IND, NULL);
|
||||
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_IND, NULL);
|
||||
break;
|
||||
case (DL_RELEASE | CONFIRM):
|
||||
FsmEvent(&l3->l3m, EV_RELEASE_CNF, NULL);
|
||||
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_CNF, NULL);
|
||||
break;
|
||||
case (DL_RELEASE | REQUEST):
|
||||
FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
|
||||
mISDN_FsmEvent(&l3->l3m, EV_RELEASE_REQ, NULL);
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
|
@ -520,27 +548,32 @@ l3_msg(layer3_t *l3, u_int pr, int dinfo, int len, void *arg)
|
|||
void
|
||||
init_l3(layer3_t *l3)
|
||||
{
|
||||
l3->proc = NULL;
|
||||
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 = 1;
|
||||
l3->l3m.debug = l3->debug;
|
||||
l3->l3m.userdata = l3;
|
||||
l3->l3m.userint = 0;
|
||||
l3->l3m.printdebug = l3m_debug;
|
||||
FsmInitTimer(&l3->l3m, &l3->l3m_timer);
|
||||
mISDN_FsmInitTimer(&l3->l3m, &l3->l3m_timer);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
release_l3(layer3_t *l3)
|
||||
{
|
||||
printk(KERN_DEBUG "release_l3(%p) proc(%p) global(%p) dummy(%p)\n",
|
||||
l3, l3->proc, l3->global, l3->dummy);
|
||||
while (l3->proc)
|
||||
release_l3_process(l3->proc);
|
||||
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);
|
||||
|
@ -551,7 +584,7 @@ release_l3(layer3_t *l3)
|
|||
kfree(l3->dummy);
|
||||
l3->dummy = NULL;
|
||||
}
|
||||
FsmDelTimer(&l3->l3m_timer, 54);
|
||||
mISDN_FsmDelTimer(&l3->l3m_timer, 54);
|
||||
discard_queue(&l3->squeue);
|
||||
}
|
||||
|
||||
|
@ -562,11 +595,11 @@ mISDNl3New(void)
|
|||
l3fsm.event_count = L3_EVENT_COUNT;
|
||||
l3fsm.strEvent = strL3Event;
|
||||
l3fsm.strState = strL3State;
|
||||
FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
|
||||
mISDN_FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
|
||||
}
|
||||
|
||||
void
|
||||
mISDNl3Free(void)
|
||||
{
|
||||
FsmFree(&l3fsm);
|
||||
mISDN_FsmFree(&l3fsm);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <linux/mISDNif.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include "fsm.h"
|
||||
#ifdef MEMDBG
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
|||
#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
|
||||
|
@ -35,58 +36,64 @@ typedef struct _L3Timer {
|
|||
} L3Timer_t;
|
||||
|
||||
typedef struct _l3_process {
|
||||
struct _l3_process *prev;
|
||||
struct _l3_process *next;
|
||||
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 _layer3 *prev;
|
||||
struct _layer3 *next;
|
||||
struct FsmInst l3m;
|
||||
struct FsmTimer l3m_timer;
|
||||
l3_process_t *proc;
|
||||
l3_process_t *global;
|
||||
l3_process_t *dummy;
|
||||
int (*p_mgr)(l3_process_t *, u_int, void *);
|
||||
u_int id;
|
||||
int debug;
|
||||
u_int Flag;
|
||||
mISDNinstance_t inst;
|
||||
struct sk_buff_head squeue;
|
||||
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;
|
||||
int primitive;
|
||||
void (*rout) (l3_process_t *, u_char, void *);
|
||||
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 struct sk_buff *l3_alloc_skb(int);
|
||||
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 *, int);
|
||||
extern l3_process_t *new_l3_process(layer3_t *, int, 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(void);
|
||||
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 *, ...);
|
||||
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 *, ...);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "capi.h"
|
||||
#include "m_capi.h"
|
||||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
@ -43,77 +43,87 @@ static char* str_ev_listen[] = {
|
|||
static struct Fsm listen_fsm =
|
||||
{ 0, 0, 0, 0, 0 };
|
||||
|
||||
static void listen_debug(struct FsmInst *fi, char *fmt, ...)
|
||||
static void
|
||||
listen_debug(struct FsmInst *fi, char *fmt, ...)
|
||||
{
|
||||
char tmp[128];
|
||||
char *p = tmp;
|
||||
va_list args;
|
||||
Listen_t *listen = fi->userdata;
|
||||
Application_t *app = fi->userdata;
|
||||
|
||||
if (!fi->debug)
|
||||
return;
|
||||
va_start(args, fmt);
|
||||
p += sprintf(p, "Controller 0x%x ApplId %d listen ",
|
||||
listen->contr->adrController, listen->ApplId);
|
||||
app->contr->addr, app->ApplId);
|
||||
p += vsprintf(p, fmt, args);
|
||||
*p = 0;
|
||||
listenDebug(listen, CAPI_DBG_LISTEN_STATE, tmp);
|
||||
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)
|
||||
static void
|
||||
listen_req_l_x(struct FsmInst *fi, int event, void *arg, int state)
|
||||
{
|
||||
Listen_t *listen = fi->userdata;
|
||||
_cmsg *cmsg = arg;
|
||||
Application_t *app = fi->userdata;
|
||||
_cmsg *cmsg = arg;
|
||||
|
||||
FsmChangeState(fi, state);
|
||||
mISDN_FsmChangeState(fi, state);
|
||||
|
||||
listen->InfoMask = cmsg->InfoMask;
|
||||
listen->CIPmask = cmsg->CIPmask;
|
||||
listen->CIPmask2 = cmsg->CIPmask2;
|
||||
listenDebug(listen, CAPI_DBG_LISTEN_INFO, "set InfoMask to 0x%x", listen->InfoMask);
|
||||
listenDebug(listen, CAPI_DBG_LISTEN_INFO, "set CIP to 0x%x,0x%x", listen->CIPmask,
|
||||
listen->CIPmask2);
|
||||
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;
|
||||
|
||||
FsmEvent(&listen->listen_m, EV_LISTEN_CONF, cmsg);
|
||||
contrRecvCmsg(listen->contr, cmsg);
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
static void
|
||||
listen_conf_l_x_1(struct FsmInst *fi, int event, void *arg, int state)
|
||||
{
|
||||
Listen_t *listen = fi->userdata;
|
||||
_cmsg *cmsg = arg;
|
||||
Application_t *app = fi->userdata;
|
||||
_cmsg *cmsg = arg;
|
||||
|
||||
if (cmsg->Info != CAPI_NOERROR) {
|
||||
FsmChangeState(fi, state);
|
||||
mISDN_FsmChangeState(fi, state);
|
||||
} else { // Info == 0
|
||||
if (listen->CIPmask == 0)
|
||||
FsmChangeState(fi, ST_LISTEN_L_0);
|
||||
else
|
||||
FsmChangeState(fi, ST_LISTEN_L_1);
|
||||
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)
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
@ -131,53 +141,56 @@ const int FN_LISTEN_COUNT = sizeof(fn_listen_list)/sizeof(struct FsmNode);
|
|||
// ----------------------------------------------------------------------
|
||||
// Methods
|
||||
|
||||
|
||||
void listenConstr(Listen_t *listen, Contr_t *contr, __u16 ApplId)
|
||||
void listenConstr(Application_t *app)
|
||||
{
|
||||
listen->listen_m.fsm = &listen_fsm;
|
||||
listen->listen_m.state = ST_LISTEN_L_0;
|
||||
listen->listen_m.debug = contr->debug & CAPI_DBG_LISTEN_STATE;
|
||||
listen->listen_m.userdata = listen;
|
||||
listen->listen_m.printdebug = listen_debug;
|
||||
|
||||
listen->contr = contr;
|
||||
listen->ApplId = ApplId;
|
||||
listen->InfoMask = 0;
|
||||
listen->CIPmask = 0;
|
||||
listen->CIPmask2 = 0;
|
||||
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(Listen_t *listen)
|
||||
void listenDestr(Application_t *app)
|
||||
{
|
||||
listenDebug(listen, CAPI_DBG_LISTEN, "%s\n", __FUNCTION__);
|
||||
test_and_clear_bit(APPL_STATE_LISTEN, &app->state);
|
||||
listenDebug(app, CAPI_DBG_LISTEN, "%s", __FUNCTION__);
|
||||
}
|
||||
|
||||
void listenSendMessage(Listen_t *listen, struct sk_buff *skb)
|
||||
__u16
|
||||
listenSendMessage(Application_t *app, struct sk_buff *skb)
|
||||
{
|
||||
_cmsg cmsg;
|
||||
capi_message2cmsg(&cmsg, skb->data);
|
||||
|
||||
switch (CMSGCMD(&cmsg)) {
|
||||
case CAPI_LISTEN_REQ:
|
||||
FsmEvent(&listen->listen_m, EV_LISTEN_REQ, &cmsg);
|
||||
break;
|
||||
default:
|
||||
int_error();
|
||||
}
|
||||
dev_kfree_skb(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(Listen_t *listen, __u16 CIPValue)
|
||||
int listenHandle(Application_t *app, __u16 CIPValue)
|
||||
{
|
||||
if ((listen->CIPmask & 1) ||
|
||||
(listen -> CIPmask & (1 << CIPValue)))
|
||||
if ((app->CIPmask & 1) ||
|
||||
(app->CIPmask & (1 << CIPValue)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
//
|
||||
|
||||
void init_listen(void)
|
||||
{
|
||||
listen_fsm.state_count = ST_LISTEN_COUNT;
|
||||
|
@ -185,10 +198,10 @@ void init_listen(void)
|
|||
listen_fsm.strEvent = str_ev_listen;
|
||||
listen_fsm.strState = str_st_listen;
|
||||
|
||||
FsmNew(&listen_fsm, fn_listen_list, FN_LISTEN_COUNT);
|
||||
mISDN_FsmNew(&listen_fsm, fn_listen_list, FN_LISTEN_COUNT);
|
||||
}
|
||||
|
||||
void free_listen(void)
|
||||
{
|
||||
FsmFree(&listen_fsm);
|
||||
mISDN_FsmFree(&listen_fsm);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,597 @@
|
|||
/*
|
||||
* loop.c loop driver for looped bchannel pairs
|
||||
*
|
||||
* Author Andreas Eversberg (jolly@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$";
|
||||
|
||||
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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue