summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile644
-rw-r--r--dahdi_cfg.c1489
-rw-r--r--dahdi_cfg.h27
-rw-r--r--dahdi_diag.c31
-rw-r--r--dahdi_monitor.c577
-rw-r--r--dahdi_scan.c172
-rw-r--r--dahdi_speed.c36
-rw-r--r--dahdi_test.c135
-rw-r--r--dahdi_tool.c589
-rw-r--r--fxotune.c1110
-rw-r--r--fxotune.h110
-rw-r--r--fxstest.c144
-rw-r--r--hdlcgen.c105
-rw-r--r--hdlcstress.c186
-rw-r--r--hdlctest.c261
-rw-r--r--hdlcverify.c106
-rw-r--r--makeopts.in47
-rw-r--r--patgen.c98
-rw-r--r--patlooptest.c124
-rw-r--r--pattest.c104
-rw-r--r--ppp/Makefile29
-rw-r--r--ppp/zaptel.c284
-rw-r--r--sethdlc.c693
-rw-r--r--timertest.c54
-rw-r--r--tonezone.c512
-rw-r--r--tonezone.h86
-rw-r--r--zonedata.c931
27 files changed, 8684 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..85e1c48
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,644 @@
+#
+# Makefile for Zaptel driver modules and utilities
+#
+# Copyright (C) 2001-2007 Digium, Inc.
+#
+#
+
+ifneq ($(KBUILD_EXTMOD),)
+# We only get in here if we're from kernel 2.6 <= 2.6.9 and going through
+# Kbuild. Later versions will include Kbuild instead of Makefile.
+include $(src)/Kbuild
+
+else
+
+CFLAGS+=-DSTANDALONE_ZAPATA -DBUILDING_TONEZONE
+
+ifeq ($(MAKELEVEL),0)
+PWD:=$(shell pwd)
+endif
+
+ifeq ($(ARCH),)
+ARCH:=$(shell uname -m | sed -e s/i.86/i386/)
+endif
+
+ifeq ($(DEB_HOST_GNU_TYPE),)
+UNAME_M:=$(shell uname -m)
+else
+UNAME_M:=$(DEB_HOST_GNU_TYPE)
+endif
+
+# If you want to build for a kernel other than the current kernel, set KVERS
+ifndef KVERS
+KVERS:=$(shell uname -r)
+endif
+ifndef KSRC
+ ifneq (,$(wildcard /lib/modules/$(KVERS)/build))
+ KSRC:=/lib/modules/$(KVERS)/build
+ else
+ KSRC_SEARCH_PATH:=/usr/src/linux-2.4 /usr/src/linux
+ KSRC:=$(shell for dir in $(KSRC_SEARCH_PATH); do if [ -d $$dir ]; then echo $$dir; break; fi; done)
+ endif
+endif
+KVERS_MAJ:=$(shell echo $(KVERS) | cut -d. -f1-2)
+KINCLUDES:=$(KSRC)/include
+
+# We use the kernel's .config file as an indication that the KSRC
+# directory is indeed a valid and configured kernel source (or partial
+# source) directory.
+#
+# We also source it, as it has the format of Makefile variables list.
+# Thus we will have many CONFIG_* variables from there.
+KCONFIG:=$(KSRC)/.config
+ifneq (,$(wildcard $(KCONFIG)))
+ HAS_KSRC=yes
+ include $(KCONFIG)
+else
+ HAS_KSRC=no
+endif
+
+ifeq ($(KVERS_MAJ),2.4)
+ BUILDVER:=linux24
+else
+ BUILDVER:=linux26
+endif
+
+# Set HOTPLUG_FIRMWARE=no to override automatic building with hotplug support
+# if it is enabled in the kernel.
+ifeq ($(BUILDVER),linux26)
+ ifneq (,$(wildcard $(DESTDIR)/etc/udev/rules.d))
+ DYNFS=yes
+ UDEVRULES=yes
+ endif
+ ifeq (yes,$(HAS_KSRC))
+ HOTPLUG_FIRMWARE:=$(shell if grep -q '^CONFIG_FW_LOADER=[ym]' $(KCONFIG); then echo "yes"; else echo "no"; fi)
+ endif
+endif
+
+ifneq (,$(findstring $(CONFIG_DEVFS_FS),y m))
+ DYNFS=yes
+ HAS_DEVFS=yes
+endif
+
+# If the file .zaptel.makeopts is present in your home directory, you can
+# include all of your favorite menuselect options so that every time you download
+# a new version of Asterisk, you don't have to run menuselect to set them.
+# The file /etc/zaptel.makeopts will also be included but can be overridden
+# by the file in your home directory.
+
+GLOBAL_MAKEOPTS=$(wildcard /etc/zaptel.makeopts)
+USER_MAKEOPTS=$(wildcard ~/.zaptel.makeopts)
+
+ifeq ($(strip $(foreach var,clean distclean dist-clean update,$(findstring $(var),$(MAKECMDGOALS)))),)
+ ifneq ($(wildcard menuselect.makeopts),)
+ include menuselect.makeopts
+ endif
+endif
+
+ifeq ($(strip $(foreach var,clean distclean dist-clean update,$(findstring $(var),$(MAKECMDGOALS)))),)
+ ifneq ($(wildcard makeopts),)
+ include makeopts
+ endif
+endif
+
+ifeq ($(BUILDVER),linux24)
+MENUSELECT_MODULES+=xpp wctc4xxp wctdm24xxp zttranscode
+endif
+
+ifeq ($(findstring xpp,$(MENUSELECT_MODULES)),)
+ BUILD_XPP:=yes
+endif
+
+SUBDIRS_UTILS_ALL:= kernel/xpp/utils ppp
+SUBDIRS_UTILS :=
+ifeq ($(BUILD_XPP),yes)
+ SUBDIRS_UTILS += kernel/xpp/utils
+endif
+#SUBDIRS_UTILS += ppp
+
+TOPDIR_MODULES:=pciradio tor2 torisa wcfxo wct1xxp wctdm wcte11xp wcusb zaptel ztd-eth ztd-loc ztdummy ztdynamic zttranscode
+SUBDIR_MODULES:=wct4xxp wctc4xxp xpp wctdm24xxp wcte12xp
+TOPDIR_MODULES+=$(MODULES_EXTRA)
+SUBDIR_MODULES+=$(SUBDIRS_EXTRA)
+BUILD_TOPDIR_MODULES:=$(filter-out $(MENUSELECT_MODULES),$(TOPDIR_MODULES))
+BUILD_SUBDIR_MODULES:=$(filter-out $(MENUSELECT_MODULES),$(SUBDIR_MODULES))
+BUILD_MODULES:=$(BUILD_TOPDIR_MODULES) $(BUILD_SUBDIR_MODULES)
+
+MOD_DESTDIR:=zaptel
+
+KERN_DIR:=kernel
+
+#NOTE NOTE NOTE
+#
+# all variables set before the include of Makefile.kernel26 are needed by the 2.6 kernel module build process
+
+ifneq ($(KBUILD_EXTMOD),)
+
+obj-m:=$(BUILD_TOPDIR_MODULES:%=%.o)
+obj-m+=$(BUILD_SUBDIR_MODULES:%=%/)
+
+include $(src)/Makefile.kernel26
+
+else
+KBUILD_OBJ_M=$(BUILD_TOPDIR_MODULES:%=%.o) $(BUILD_SUBDIR_MODULES:%=%/)
+
+ifeq ($(BUILDVER),linux24)
+ INSTALL_MODULES:=$(BUILD_TOPDIR_MODULES:%=$(KERN_DIR)/%.o)
+ INSTALL_MODULES+=$(foreach mod,$(BUILD_SUBDIR_MODULES),$(KERN_DIR)/$(mod)/$(mod).o)
+ ALL_MODULES:=$(TOPDIR_MODULES:%=$(KERN_DIR)/%.o)
+ ALL_MODULES+=$(SUBDIR_MODULES:%=$(KERN_DIR)/%/%.o)
+else
+ ALL_MODULES:=$(TOPDIR_MODULES:%=%.ko)
+ ALL_MODULES+=$(foreach mod,$(filter-out xpp,$(SUBDIR_MODULES)),$(mod)/$(mod).ko)
+ ALL_MODULES+=$(patsubst %,xpp/%.ko,xpp_usb xpd_fxo xpd_fxs xpp)
+endif
+
+OPTFLAG=-O2
+CFLAGS+=-I. $(OPTFLAGS) -g -fPIC -Wall -DBUILDING_TONEZONE #-DTONEZONE_DRIVER
+ifneq (,$(findstring ppc,$(UNAME_M)))
+CFLAGS_PPC:=-fsigned-char
+endif
+ifneq (,$(findstring x86_64,$(UNAME_M)))
+CFLAGS_x86_64:=-m64
+endif
+CFLAGS+=$(CFLAGS_PPC) $(CFLAGS_x86_64)
+KFLAGS=-I$(KINCLUDES) -O6
+KFLAGS+=-DMODULE -D__KERNEL__ -DEXPORT_SYMTAB -I$(KSRC)/drivers/net \
+ -Wall -I. -Wstrict-prototypes -fomit-frame-pointer -I$(KSRC)/drivers/net/wan -I$(KINCLUDES)/net
+ifneq (,$(wildcard $(KINCLUDES)/linux/modversions.h))
+ KFLAGS+=-DMODVERSIONS -include $(KINCLUDES)/linux/modversions.h
+endif
+ifneq (,$(findstring ppc,$(UNAME_M)))
+KFLAGS_PPC:=-msoft-float -fsigned-char
+endif
+KFLAGS+=$(KFLAGS_PPC)
+ifeq ($(KVERS_MAJ),2.4)
+ ifneq (,$(findstring x86_64,$(UNAME_M)))
+ KFLAGS+=-mcmodel=kernel
+ endif
+endif
+
+#
+# Features are now configured in zconfig.h
+#
+
+MODULE_ALIASES=wcfxs wctdm8xxp wct2xxp
+
+KFLAGS+=-DSTANDALONE_ZAPATA
+CFLAGS+=-DSTANDALONE_ZAPATA
+ifeq ($(BUILDVER),linux24)
+KMAKE = $(MAKE) -C kernel HOTPLUG_FIRMWARE=no \
+ HOSTCC=$(HOSTCC) ARCH=$(ARCH) KSRC=$(KSRC) LD=$(LD) CC=$(CC) \
+ UNAME_M=$(UNAME_M) \
+ BUILD_TOPDIR_MODULES="$(BUILD_TOPDIR_MODULES)" BUILD_SUBDIR_MODULES="$(BUILD_SUBDIR_MODULES)"
+else
+KMAKE = $(MAKE) -C $(KSRC) ARCH=$(ARCH) SUBDIRS=$(PWD)/kernel \
+ HOTPLUG_FIRMWARE=$(HOTPLUG_FIRMWARE) KBUILD_OBJ_M="$(KBUILD_OBJ_M)"
+endif
+KMAKE_INST = $(KMAKE) \
+ INSTALL_MOD_PATH=$(DESTDIR) INSTALL_MOD_DIR=misc modules_install
+
+ROOT_PREFIX=
+
+CONFIG_FILE=/etc/zaptel.conf
+CFLAGS+=-DZAPTEL_CONFIG=\"$(CONFIG_FILE)\"
+
+# sample makefile "trace print"
+#tracedummy=$(shell echo ====== GOT HERE ===== >&2; echo >&2)
+
+CHKCONFIG := $(wildcard /sbin/chkconfig)
+UPDATE_RCD := $(wildcard /usr/sbin/update-rc.d)
+ifeq (,$(DESTDIR))
+ ifneq (,$(CHKCONFIG))
+ ADD_INITD := $(CHKCONFIG) --add zaptel
+ else
+ ifndef (,$(UPDATE_RCD))
+ ADD_INITD := $(UPDATE_RCD) zaptel defaults 15 30
+ endif
+ endif
+endif
+
+INITRD_DIR := $(firstword $(wildcard /etc/rc.d/init.d /etc/init.d))
+ifneq (,$(INITRD_DIR))
+ INIT_TARGET := $(DESTDIR)$(INITRD_DIR)/zaptel
+ COPY_INITD := install -D zaptel.init $(INIT_TARGET)
+endif
+RCCONF_DIR := $(firstword $(wildcard /etc/sysconfig /etc/default))
+
+NETSCR_DIR := $(firstword $(wildcard /etc/sysconfig/network-scripts ))
+ifneq (,$(NETSCR_DIR))
+ NETSCR_TARGET := $(DESTDIR)$(NETSCR_DIR)/ifup-hdlc
+ COPY_NETSCR := install -D ifup-hdlc $(NETSCR_TARGET)
+endif
+
+ifneq ($(wildcard .version),)
+ ZAPTELVERSION:=$(shell cat .version)
+else
+ifneq ($(wildcard .svn),)
+ ZAPTELVERSION=SVN-$(shell build_tools/make_svn_branch_name)
+endif
+endif
+
+LTZ_A:=libtonezone.a
+LTZ_A_OBJS:=zonedata.o tonezone.o
+LTZ_SO:=libtonezone.so
+LTZ_SO_OBJS:=zonedata.lo tonezone.lo
+LTZ_SO_MAJOR_VER:=1
+LTZ_SO_MINOR_VER:=0
+
+# libdir, includedir and mandir are defined in makeopts (from
+# configure).
+# we use /sbin, rather than configure's $(sbindir) because we use /sbin
+# for historical reasons.
+BIN_DIR:=/sbin
+LIB_DIR:=$(libdir)
+INC_DIR:=$(includedir)/zaptel
+MAN_DIR:=$(mandir)/man8
+MOD_DIR:=$(DESTDIR)/lib/modules/$(KVERS)/misc
+
+# Utilities we build with a standard build procedure:
+UTILS = zttool zttest ztmonitor ztspeed sethdlc-new ztcfg \
+ ztcfg-dude usbfxstest fxstest fxotune ztdiag torisatool \
+ ztscan
+
+
+# Makefile mentions them. Source is not included (anynore?)
+UTILS += fxsdump ztprovision
+
+# some tests:
+UTILS += patgen pattest patlooptest hdlcstress hdlctest hdlcgen \
+ hdlcverify timertest
+
+UTILSO = $(UTILS:%=%.o)
+
+BINS:=fxotune fxstest sethdlc-new ztcfg ztdiag ztmonitor ztspeed zttest ztscan
+ifeq (1,$(PBX_LIBNEWT))
+ BINS+=zttool
+endif
+BINS:=$(filter-out $(MENUSELECT_UTILS),$(BINS))
+MAN_PAGES:=$(wildcard $(BINS:%=doc/%.8))
+
+# All the man pages. Not just installed ones:
+GROFF_PAGES := $(wildcard doc/*.8 kernel/xpp/utils/*.8)
+GROFF_HTML := $(GROFF_PAGES:%=%.html)
+
+all: menuselect.makeopts
+ @$(MAKE) _all
+
+_all: $(if $(BUILD_MODULES),modules) programs
+
+libs: $(LTZ_SO) $(LTZ_A)
+
+utils-subdirs:
+ @for dir in $(SUBDIRS_UTILS); do \
+ $(MAKE) -C $$dir; \
+ done
+
+programs: libs utils
+
+utils: $(BINS) utils-subdirs
+
+modules: prereq
+ifeq (no,$(HAS_KSRC))
+ echo "You do not appear to have the sources for the $(KVERS) kernel installed."
+ exit 1
+endif
+ $(KMAKE) modules
+
+version.h:
+ @ZAPTELVERSION="${ZAPTELVERSION}" build_tools/make_version_h > $@.tmp
+ @if cmp -s $@.tmp $@ ; then :; else \
+ mv $@.tmp $@ ; \
+ fi
+ @rm -f $@.tmp
+
+tests: patgen pattest patlooptest hdlcstress hdlctest hdlcgen hdlcverify timertest
+
+zonedata.o: tonezone.h
+
+zonedata.lo: zonedata.c tonezone.h
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+tonezone.o: kernel/zaptel.h tonezone.h
+
+tonezone.lo: tonezone.c tonezone.h kernel/zaptel.h
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+prereq: config.status version.h
+
+zttool.o: kernel/zaptel.h
+zttool.o: CFLAGS+=$(NEWT_INCLUDE)
+zttool: LDLIBS+=$(NEWT_LIB)
+
+ztscan.o: kernel/zaptel.h
+
+ztprovision.o: kernel/zaptel.h
+
+ztmonitor.o: kernel/zaptel.h
+
+ztspeed: CFLAGS=
+
+sethdlc-new: CFLAGS+=-I$(KINCLUDES)
+
+$(LTZ_A): $(LTZ_A_OBJS)
+ ar rcs $@ $^
+ ranlib $@
+
+$(LTZ_SO): $(LTZ_SO_OBJS)
+ $(CC) $(CFLAGS) -shared -Wl,-soname,$(LTZ_SO).$(LTZ_SO_MAJOR_VER).$(LTZ_SO_MINOR_VER) -o $@ $^ $(LDFLAGS) $(LDLIBS) -lm
+
+ztcfg.o: ztcfg.h kernel/zaptel.h
+ztcfg: ztcfg.o $(LTZ_A)
+ztcfg: LDLIBS+=-lm
+
+ztcfg-shared: ztcfg.o $(LTZ_SO)
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS) -lm
+
+ztcfg-dude: ztcfg-dude.o mknotch.o complex.o $(LTZ_SO)
+ztcfg-dude: LDLIBS+=-lm -lstdc++
+
+data:
+ $(MAKE) -C datamods datamods
+
+# FIXME: we assume CC can build the C++ modules:
+complex.o mknotch.o: %.o: %.cc
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+usbfxstest: LDLIBS+=-lzap
+fxstest: $(LTZ_SO)
+fxstest: LDLIBS+=-lm
+fxotune: LDLIBS+=-lm
+fxsdump: LDLIBS+=-lm
+
+stackcheck: checkstack modules
+ ./checkstack kernel/*.ko kernel/*/*.ko
+
+
+tonezones.txt: zonedata.c
+ perl -ne 'next unless (/\.(country|description) = *"([^"]*)/); \
+ print (($$1 eq "country")? "* $$2\t":"$$2\n");' $< \
+ >$@
+
+zaptel.conf.asciidoc: zaptel.conf.sample
+ perl -n -e \
+ 'if (/^#($$|\s)(.*)/){ if (!$$in_doc){print "\n"}; $$in_doc=1; print "$$2\n" } else { if ($$in_doc){print "\n"}; $$in_doc=0; print " $$_" }' \
+ $< >$@
+
+README.html: README zaptel.conf.asciidoc tonezones.txt
+ $(ASCIIDOC) -n -a toc -a toclevels=3 $<
+
+kernel/xpp/README.Astribank.html: kernel/xpp/README.Astribank
+ cd $(@D); $(ASCIIDOC) -o $(@F) -n -a toc -a toclevels=4 $(<F)
+
+# on Debian: this requires the full groof, not just groff-base.
+%.8.html: %.8
+ man -Thtml $^ >$@
+
+htmlman: $(GROFF_HTML)
+
+
+MISDNVERSION=1_1_7_2
+MISDNUSERVERSION=1_1_7_2
+b410p:
+ @if test "$(DOWNLOAD)" = ":" ; then \
+ echo "**************************************************"; \
+ echo "*** ***"; \
+ echo "*** You must have either wget or fetch to be ***"; \
+ echo "*** able to automatically download and install ***"; \
+ echo "*** b410p support. ***"; \
+ echo "*** ***"; \
+ echo "*** Please install one of these. ***"; \
+ echo "*** ***"; \
+ echo "**************************************************"; \
+ exit 1; \
+ fi
+ [ -f mISDN-$(MISDNVERSION).tar.gz ] || $(DOWNLOAD) http://downloads.digium.com/pub/zaptel/b410p/mISDN-$(MISDNVERSION).tar.gz
+ tar -zxf mISDN-$(MISDNVERSION).tar.gz
+ $(MAKE) -C mISDN-$(MISDNVERSION) install
+ [ -f mISDNuser-$(MISDNUSERVERSION).tar.gz ] || $(DOWNLOAD) http://downloads.digium.com/pub/zaptel/b410p/mISDNuser-$(MISDNUSERVERSION).tar.gz
+ tar -zxf mISDNuser-$(MISDNUSERVERSION).tar.gz
+ $(MAKE) -C mISDNuser-$(MISDNUSERVERSION) install
+
+$(UTILS): %: %.o
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS)
+
+$(UTILSO): %.o: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+install: all devices install-modules install-programs install-firmware
+ @echo "###################################################"
+ @echo "###"
+ @echo "### Zaptel installed successfully."
+ @echo "### If you have not done so before, install init scripts with:"
+ @echo "###"
+ @echo "### make config"
+ @echo "###"
+ @echo "###################################################"
+
+install-programs: install-utils install-libs install-include
+
+install-utils: utils install-utils-subdirs
+ifneq (,$(BINS))
+ install -d $(DESTDIR)$(BIN_DIR)
+ install $(BINS) $(DESTDIR)$(BIN_DIR)/
+ install -d $(DESTDIR)$(MAN_DIR)
+ install -m 644 $(MAN_PAGES) $(DESTDIR)$(MAN_DIR)/
+endif
+ifeq (,$(wildcard $(DESTDIR)$(CONFIG_FILE)))
+ $(INSTALL) -D -m 644 zaptel.conf.sample $(DESTDIR)$(CONFIG_FILE)
+endif
+
+# Pushing those two to a separate target that is not used by default:
+install-modconf:
+ build_tools/genmodconf $(BUILDVER) "$(ROOT_PREFIX)" "$(filter-out zaptel ztdummy xpp zttranscode ztdynamic,$(BUILD_MODULES)) $(MODULE_ALIASES)"
+ @if [ -d /etc/modutils ]; then \
+ /sbin/update-modules ; \
+ fi
+
+install-firmware:
+ifeq ($(HOTPLUG_FIRMWARE),yes)
+ $(MAKE) -C firmware hotplug-install DESTDIR=$(DESTDIR) HOTPLUG_FIRMWARE=$(HOTPLUG_FIRMWARE)
+endif
+
+install-libs: libs
+ $(INSTALL) -D -m 755 $(LTZ_A) $(DESTDIR)$(LIB_DIR)/$(LTZ_A)
+ $(INSTALL) -D -m 755 $(LTZ_SO) $(DESTDIR)$(LIB_DIR)/$(LTZ_SO).$(LTZ_SO_MAJOR_VER).$(LTZ_SO_MINOR_VER)
+ifeq (,$(DESTDIR))
+ if [ `id -u` = 0 ]; then \
+ /sbin/ldconfig || : ;\
+ fi
+endif
+ rm -f $(DESTDIR)$(LIB_DIR)$(LTZ_SO)
+ $(LN) -sf $(LTZ_SO).$(LTZ_SO_MAJOR_VER).$(LTZ_SO_MINOR_VER) \
+ $(DESTDIR)$(LIB_DIR)/$(LTZ_SO).$(LTZ_SO_MAJOR_VER)
+ $(LN) -sf $(LTZ_SO).$(LTZ_SO_MAJOR_VER).$(LTZ_SO_MINOR_VER) \
+ $(DESTDIR)$(LIB_DIR)/$(LTZ_SO)
+ifneq (no,$(USE_SELINUX))
+ ifeq (,$(DESTDIR))
+ /sbin/restorecon -v $(DESTDIR)$(LIB_DIR)/$(LTZ_SO)
+ endif
+endif
+ $(INSTALL) -D -m 644 tonezone.h $(DESTDIR)$(INC_DIR)/tonezone.h
+
+install-utils-subdirs:
+ @for dir in $(SUBDIRS_UTILS); do \
+ $(MAKE) -C $$dir install; \
+ done
+
+install-include:
+ $(INSTALL) -D -m 644 kernel/zaptel.h $(DESTDIR)$(INC_DIR)/zaptel.h
+
+devices:
+ifneq (yes,$(DYNFS))
+ mkdir -p $(DESTDIR)/dev/zap
+ rm -f $(DESTDIR)/dev/zap/ctl
+ rm -f $(DESTDIR)/dev/zap/channel
+ rm -f $(DESTDIR)/dev/zap/pseudo
+ rm -f $(DESTDIR)/dev/zap/timer
+ rm -f $(DESTDIR)/dev/zap/transcode
+ rm -f $(DESTDIR)/dev/zap/253
+ rm -f $(DESTDIR)/dev/zap/252
+ rm -f $(DESTDIR)/dev/zap/251
+ rm -f $(DESTDIR)/dev/zap/250
+ mknod $(DESTDIR)/dev/zap/ctl c 196 0
+ mknod $(DESTDIR)/dev/zap/transcode c 196 250
+ mknod $(DESTDIR)/dev/zap/timer c 196 253
+ mknod $(DESTDIR)/dev/zap/channel c 196 254
+ mknod $(DESTDIR)/dev/zap/pseudo c 196 255
+ N=1; \
+ while [ $$N -lt 250 ]; do \
+ rm -f $(DESTDIR)/dev/zap/$$N; \
+ mknod $(DESTDIR)/dev/zap/$$N c 196 $$N; \
+ N=$$[$$N+1]; \
+ done
+else # DYNFS
+ ifneq (yes,$(UDEVRULES)) #!UDEVRULES
+ @echo "**** Dynamic filesystem detected -- not creating device nodes"
+ else # UDEVRULES
+ install -d $(DESTDIR)/etc/udev/rules.d
+ build_tools/genudevrules > $(DESTDIR)/etc/udev/rules.d/zaptel.rules
+ endif
+endif
+
+install-udev: devices
+
+uninstall-hotplug:
+ $(MAKE) -C firmware hotplug-uninstall DESTDIR=$(DESTDIR)
+
+uninstall-modules:
+ifneq ($(BUILDVER),linux24)
+ @./build_tools/uninstall-modules $(DESTDIR)/lib/modules/$(KVERS) $(ALL_MODULES)
+endif
+
+ifeq ($(BUILDVER),linux24)
+install-modules: $(INSTALL_MODULES) uninstall-modules
+ $(INSTALL) -d $(DESTDIR)$(MOD_DIR)
+ $(INSTALL) -m 644 $(INSTALL_MODULES) $(DESTDIR)$(MOD_DIR)
+else
+install-modules: uninstall-modules
+ $(KMAKE_INST)
+endif
+ [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || :
+
+config:
+ifneq (,$(COPY_INITD))
+ $(COPY_INITD)
+endif
+ifneq (,$(RCCONF_DIR))
+ ifeq (,$(wildcard $(DESTDIR)$(RCCONF_DIR)/zaptel))
+ $(INSTALL) -D -m 644 zaptel.sysconfig $(DESTDIR)$(RCCONF_DIR)/zaptel
+ endif
+endif
+ifneq (,$(COPY_NETSCR))
+ $(COPY_NETSCR)
+endif
+ifneq (,$(ADD_INITD))
+ $(ADD_INITD)
+endif
+ @echo "Zaptel has been configured."
+ @echo ""
+ @echo "If you have any zaptel hardware it is now recommended to "
+ @echo "edit /etc/default/zaptel or /etc/sysconfig/zaptel and set there an "
+ @echo "optimal value for the variable MODULES ."
+ @echo ""
+ @echo "I think that the zaptel hardware you have on your system is:"
+ @kernel/xpp/utils/zaptel_hardware || true
+
+
+update:
+ @if [ -d .svn ]; then \
+ echo "Updating from Subversion..." ; \
+ svn update | tee update.out; \
+ rm -f .version; \
+ if [ `grep -c ^C update.out` -gt 0 ]; then \
+ echo ; echo "The following files have conflicts:" ; \
+ grep ^C update.out | cut -b4- ; \
+ fi ; \
+ rm -f update.out; \
+ else \
+ echo "Not under version control"; \
+ fi
+
+clean:
+ -@$(MAKE) -C menuselect clean
+ rm -f torisatool
+ rm -f $(BINS)
+ rm -f *.o ztcfg tzdriver sethdlc sethdlc-new
+ rm -f $(LTZ_SO) $(LTZ_A) *.lo
+ifeq (yes,$(HAS_KSRC))
+ $(KMAKE) clean
+else
+ rm -f kernel/*.o kernel/*.ko kernel/*/*.o kernel/*/*.ko
+endif
+ @for dir in $(SUBDIRS_UTILS_ALL); do \
+ $(MAKE) -C $$dir clean; \
+ done
+ $(MAKE) -C firmware clean
+ rm -rf .tmp_versions
+ rm -f gendigits tones.h
+ rm -f libtonezone*
+ rm -f fxotune
+ rm -f core
+ rm -f ztcfg-shared fxstest
+ rm -rf misdn*
+ rm -rf mISDNuser*
+ rm -rf $(GROFF_HTML)
+ rm -rf README.html xpp/README.Astribank.html zaptel.conf.asciidoc
+
+distclean: dist-clean
+
+dist-clean: clean
+ @$(MAKE) -C menuselect dist-clean
+ @$(MAKE) -C firmware dist-clean
+ rm -f makeopts menuselect.makeopts menuselect-tree
+ rm -f config.log config.status
+
+config.status: configure
+ @CFLAGS="" ./configure
+ @echo "****"
+ @echo "**** The configure script was just executed, so 'make' needs to be"
+ @echo "**** restarted."
+ @echo "****"
+ @exit 1
+
+menuselect.makeopts: menuselect/menuselect menuselect-tree
+ @menuselect/menuselect --check-deps ${GLOBAL_MAKEOPTS} ${USER_MAKEOPTS} $@
+
+menuconfig: menuselect
+
+menuselect: menuselect/menuselect menuselect-tree
+ -@menuselect/menuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && echo "menuselect changes saved!" || echo "menuselect changes NOT saved!"
+
+menuselect/menuselect: menuselect/menuselect.c menuselect/menuselect_curses.c menuselect/menuselect_stub.c menuselect/menuselect.h menuselect/linkedlists.h config.status
+ @CFLAGS="" $(MAKE) -C menuselect CC=$(HOSTCC)
+
+menuselect-tree: zaptel.xml firmware/firmware.xml
+ @echo "Generating input for menuselect ..."
+ @build_tools/make_tree > $@
+
+.PHONY: menuselect distclean dist-clean clean version.h all _all install b410p devices programs modules tests devel data stackcheck install-udev config update install-programs install-modules install-include install-libs install-utils-subdirs utils-subdirs uninstall-modules
+
+endif
+
+#end of: ifneq ($(KBUILD_EXTMOD),)
+endif
diff --git a/dahdi_cfg.c b/dahdi_cfg.c
new file mode 100644
index 0000000..a880f3e
--- /dev/null
+++ b/dahdi_cfg.c
@@ -0,0 +1,1489 @@
+/*
+ * Configuration program for Zapata Telephony Interface
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001 Linux Support Services, Inc.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under thet erms 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.
+ *
+ * Primary Author: Mark Spencer <markster@digium.com>
+ * Radio Support by Jim Dixon <jim@lambdatel.com>
+ */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#include "tonezone.h"
+#else
+#include <zaptel/zaptel.h>
+#include <zaptel/tonezone.h>
+#endif
+#include "ztcfg.h"
+
+#define NUM_SPANS ZT_MAX_SPANS
+
+#define NUM_TONES 15
+
+/* Assume no more than 1024 dynamics */
+#define NUM_DYNAMIC 1024
+
+static int lineno=0;
+
+static FILE *cf;
+
+static char *filename=CONFIG_FILENAME;
+
+int rxtones[NUM_TONES + 1],rxtags[NUM_TONES + 1],txtones[NUM_TONES + 1];
+int bursttime = 0, debouncetime = 0, invertcor = 0, exttone = 0, corthresh = 0;
+int txgain = 0, rxgain = 0, deemp = 0, preemp = 0;
+
+int corthreshes[] = {3125,6250,9375,12500,15625,18750,21875,25000,0} ;
+
+static int toneindex = 1;
+
+#define DEBUG_READER (1 << 0)
+#define DEBUG_PARSER (1 << 1)
+#define DEBUG_APPLY (1 << 2)
+static int debug = 0;
+
+static int errcnt = 0;
+
+static int deftonezone = -1;
+
+static struct zt_lineconfig lc[ZT_MAX_SPANS];
+
+static struct zt_chanconfig cc[ZT_MAX_CHANNELS];
+
+static struct zt_dynamic_span zds[NUM_DYNAMIC];
+
+static const char *sig[ZT_MAX_CHANNELS]; /* Signalling */
+
+static int slineno[ZT_MAX_CHANNELS]; /* Line number where signalling specified */
+
+static int spans=0;
+
+static int fo_real = 1;
+
+static int verbose = 0;
+
+static int force = 0;
+
+static int stopmode = 0;
+
+static int numdynamic = 0;
+
+static char zonestoload[ZT_TONE_ZONE_MAX][10];
+
+static int numzones = 0;
+
+static int fd = -1;
+
+static const char *lbostr[] = {
+"0 db (CSU)/0-133 feet (DSX-1)",
+"133-266 feet (DSX-1)",
+"266-399 feet (DSX-1)",
+"399-533 feet (DSX-1)",
+"533-655 feet (DSX-1)",
+"-7.5db (CSU)",
+"-15db (CSU)",
+"-22.5db (CSU)"
+};
+
+static const char *laws[] = {
+ "Default",
+ "Mu-law",
+ "A-law"
+};
+
+static const char *sigtype_to_str(const int sig)
+{
+ switch (sig) {
+ case 0:
+ return "Unused";
+ case ZT_SIG_EM:
+ return "E & M";
+ case ZT_SIG_EM_E1:
+ return "E & M E1";
+ case ZT_SIG_FXSLS:
+ return "FXS Loopstart";
+ case ZT_SIG_FXSGS:
+ return "FXS Groundstart";
+ case ZT_SIG_FXSKS:
+ return "FXS Kewlstart";
+ case ZT_SIG_FXOLS:
+ return "FXO Loopstart";
+ case ZT_SIG_FXOGS:
+ return "FXO Groundstart";
+ case ZT_SIG_FXOKS:
+ return "FXO Kewlstart";
+ case ZT_SIG_CAS:
+ return "CAS / User";
+ case ZT_SIG_DACS:
+ return "DACS";
+ case ZT_SIG_DACS_RBS:
+ return "DACS w/RBS";
+ case ZT_SIG_CLEAR:
+ return "Clear channel";
+ case ZT_SIG_SLAVE:
+ return "Slave channel";
+ case ZT_SIG_HDLCRAW:
+ return "Raw HDLC";
+ case ZT_SIG_HDLCNET:
+ return "Network HDLC";
+ case ZT_SIG_HDLCFCS:
+ return "HDLC with FCS check";
+ case ZT_SIG_HARDHDLC:
+ return "Hardware assisted D-channel";
+ case ZT_SIG_MTP2:
+ return "MTP2";
+ default:
+ return "Unknown";
+ }
+}
+
+int ind_ioctl(int channo, int fd, int op, void *data)
+{
+ZT_INDIRECT_DATA ind;
+
+ ind.chan = channo;
+ ind.op = op;
+ ind.data = data;
+ return ioctl(fd,ZT_INDIRECT,&ind);
+}
+
+static void clear_fields()
+{
+
+ memset(rxtones,0,sizeof(rxtones));
+ memset(rxtags,0,sizeof(rxtags));
+ memset(txtones,0,sizeof(txtones));
+ bursttime = 0;
+ debouncetime = 0;
+ invertcor = 0;
+ exttone = 0;
+ txgain = 0;
+ rxgain = 0;
+ deemp = 0;
+ preemp = 0;
+}
+
+static int error(char *fmt, ...)
+{
+ int res;
+ static int shown=0;
+ va_list ap;
+ if (!shown) {
+ fprintf(stderr, "Notice: Configuration file is %s\n", filename);
+ shown++;
+ }
+ res = fprintf(stderr, "line %d: ", lineno);
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ errcnt++;
+ return res;
+}
+
+static void trim(char *buf)
+{
+ /* Trim off trailing spaces, tabs, etc */
+ while(strlen(buf) && (buf[strlen(buf) -1] < 33))
+ buf[strlen(buf) -1] = '\0';
+}
+
+static int parseargs(char *input, char *output[], int maxargs, char sep)
+{
+ char *c;
+ int pos=0;
+ c = input;
+ output[pos++] = c;
+ while(*c) {
+ while(*c && (*c != sep)) c++;
+ if (*c) {
+ *c = '\0';
+ c++;
+ while(*c && (*c < 33)) c++;
+ if (*c) {
+ if (pos >= maxargs)
+ return -1;
+ output[pos] = c;
+ trim(output[pos]);
+ pos++;
+ output[pos] = NULL;
+ /* Return error if we have too many */
+ } else
+ return pos;
+ }
+ }
+ return pos;
+}
+
+int dspanconfig(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int chans;
+ int timing;
+ argc = res = parseargs(args, realargs, 4, ',');
+ if (res != 4) {
+ error("Incorrect number of arguments to 'dynamic' (should be <driver>,<address>,<num channels>, <timing>)\n");
+ }
+ res = sscanf(realargs[2], "%d", &chans);
+ if ((res == 1) && (chans < 1))
+ res = -1;
+ if (res != 1) {
+ error("Invalid number of channels '%s', should be a number > 0.\n", realargs[2]);
+ }
+
+ res = sscanf(realargs[3], "%d", &timing);
+ if ((res == 1) && (timing < 0))
+ res = -1;
+ if (res != 1) {
+ error("Invalid timing '%s', should be a number > 0.\n", realargs[3]);
+ }
+
+
+ zap_copy_string(zds[numdynamic].driver, realargs[0], sizeof(zds[numdynamic].driver));
+ zap_copy_string(zds[numdynamic].addr, realargs[1], sizeof(zds[numdynamic].addr));
+ zds[numdynamic].numchans = chans;
+ zds[numdynamic].timing = timing;
+
+ numdynamic++;
+ return 0;
+}
+
+int spanconfig(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int res;
+ int argc;
+ int span;
+ int timing;
+ argc = res = parseargs(args, realargs, 7, ',');
+ if ((res < 5) || (res > 7)) {
+ error("Incorrect number of arguments to 'span' (should be <spanno>,<timing>,<lbo>,<framing>,<coding>[, crc4 | yellow [, yellow]])\n");
+ }
+ res = sscanf(realargs[0], "%i", &span);
+ if (res != 1) {
+ error("Span number should be a valid span number, not '%s'\n", realargs[0]);
+ return -1;
+ }
+ res = sscanf(realargs[1], "%i", &timing);
+ if ((res != 1) || (timing < 0) || (timing > 15)) {
+ error("Timing should be a number from 0 to 15, not '%s'\n", realargs[1]);
+ return -1;
+ }
+ res = sscanf(realargs[2], "%i", &lc[spans].lbo);
+ if (res != 1) {
+ error("Line build-out (LBO) should be a number from 0 to 7 (usually 0) not '%s'\n", realargs[2]);
+ return -1;
+ }
+ if ((lc[spans].lbo < 0) || (lc[spans].lbo > 7)) {
+ error("Line build-out should be in the range 0 to 7, not %d\n", lc[spans].lbo);
+ return -1;
+ }
+ if (!strcasecmp(realargs[3], "d4")) {
+ lc[spans].lineconfig |= ZT_CONFIG_D4;
+ lc[spans].lineconfig &= ~ZT_CONFIG_ESF;
+ lc[spans].lineconfig &= ~ZT_CONFIG_CCS;
+ } else if (!strcasecmp(realargs[3], "esf")) {
+ lc[spans].lineconfig |= ZT_CONFIG_ESF;
+ lc[spans].lineconfig &= ~ZT_CONFIG_D4;
+ lc[spans].lineconfig &= ~ZT_CONFIG_CCS;
+ } else if (!strcasecmp(realargs[3], "ccs")) {
+ lc[spans].lineconfig |= ZT_CONFIG_CCS;
+ lc[spans].lineconfig &= ~(ZT_CONFIG_ESF | ZT_CONFIG_D4);
+ } else if (!strcasecmp(realargs[3], "cas")) {
+ lc[spans].lineconfig &= ~ZT_CONFIG_CCS;
+ lc[spans].lineconfig &= ~(ZT_CONFIG_ESF | ZT_CONFIG_D4);
+ } else {
+ error("Framing(T1)/Signalling(E1) must be one of 'd4', 'esf', 'cas' or 'ccs', not '%s'\n", realargs[3]);
+ return -1;
+ }
+ if (!strcasecmp(realargs[4], "ami")) {
+ lc[spans].lineconfig &= ~(ZT_CONFIG_B8ZS | ZT_CONFIG_HDB3);
+ lc[spans].lineconfig |= ZT_CONFIG_AMI;
+ } else if (!strcasecmp(realargs[4], "b8zs")) {
+ lc[spans].lineconfig |= ZT_CONFIG_B8ZS;
+ lc[spans].lineconfig &= ~(ZT_CONFIG_AMI | ZT_CONFIG_HDB3);
+ } else if (!strcasecmp(realargs[4], "hdb3")) {
+ lc[spans].lineconfig |= ZT_CONFIG_HDB3;
+ lc[spans].lineconfig &= ~(ZT_CONFIG_AMI | ZT_CONFIG_B8ZS);
+ } else {
+ error("Coding must be one of 'ami', 'b8zs' or 'hdb3', not '%s'\n", realargs[4]);
+ return -1;
+ }
+ if (argc > 5) {
+ if (!strcasecmp(realargs[5], "yellow"))
+ lc[spans].lineconfig |= ZT_CONFIG_NOTOPEN;
+ else if (!strcasecmp(realargs[5], "crc4")) {
+ lc[spans].lineconfig |= ZT_CONFIG_CRC4;
+ } else {
+ error("Only valid fifth arguments are 'yellow' or 'crc4', not '%s'\n", realargs[5]);
+ return -1;
+ }
+ }
+ if (argc > 6) {
+ if (!strcasecmp(realargs[6], "yellow"))
+ lc[spans].lineconfig |= ZT_CONFIG_NOTOPEN;
+ else {
+ error("Only valid sixth argument is 'yellow', not '%s'\n", realargs[6]);
+ return -1;
+ }
+ }
+ lc[spans].span = span;
+ lc[spans].sync = timing;
+ /* Valid span */
+ spans++;
+ return 0;
+}
+
+int apply_channels(int chans[], char *argstr)
+{
+ char *args[ZT_MAX_CHANNELS+1];
+ char *range[3];
+ int res,x, res2,y;
+ int chan;
+ int start, finish;
+ char argcopy[256];
+ res = parseargs(argstr, args, ZT_MAX_CHANNELS, ',');
+ if (res < 0)
+ error("Too many arguments... Max is %d\n", ZT_MAX_CHANNELS);
+ for (x=0;x<res;x++) {
+ if (strchr(args[x], '-')) {
+ /* It's a range */
+ zap_copy_string(argcopy, args[x], sizeof(argcopy));
+ res2 = parseargs(argcopy, range, 2, '-');
+ if (res2 != 2) {
+ error("Syntax error in range '%s'. Should be <val1>-<val2>.\n", args[x]);
+ return -1;
+ }
+ res2 =sscanf(range[0], "%i", &start);
+ if (res2 != 1) {
+ error("Syntax error. Start of range '%s' should be a number from 1 to %d\n", args[x], ZT_MAX_CHANNELS - 1);
+ return -1;
+ } else if ((start < 1) || (start >= ZT_MAX_CHANNELS)) {
+ error("Start of range '%s' must be between 1 and %d (not '%d')\n", args[x], ZT_MAX_CHANNELS - 1, start);
+ return -1;
+ }
+ res2 =sscanf(range[1], "%i", &finish);
+ if (res2 != 1) {
+ error("Syntax error. End of range '%s' should be a number from 1 to %d\n", args[x], ZT_MAX_CHANNELS - 1);
+ return -1;
+ } else if ((finish < 1) || (finish >= ZT_MAX_CHANNELS)) {
+ error("end of range '%s' must be between 1 and %d (not '%d')\n", args[x], ZT_MAX_CHANNELS - 1, finish);
+ return -1;
+ }
+ if (start > finish) {
+ error("Range '%s' should start before it ends\n", args[x]);
+ return -1;
+ }
+ for (y=start;y<=finish;y++)
+ chans[y]=1;
+ } else {
+ /* It's a single channel */
+ res2 =sscanf(args[x], "%i", &chan);
+ if (res2 != 1) {
+ error("Syntax error. Channel should be a number from 1 to %d, not '%s'\n", ZT_MAX_CHANNELS - 1, args[x]);
+ return -1;
+ } else if ((chan < 1) || (chan >= ZT_MAX_CHANNELS)) {
+ error("Channel must be between 1 and %d (not '%d')\n", ZT_MAX_CHANNELS - 1, chan);
+ return -1;
+ }
+ chans[chan]=1;
+ }
+ }
+ return res;
+}
+
+int parse_idle(int *i, char *s)
+{
+ char a,b,c,d;
+ if (s) {
+ if (sscanf(s, "%c%c%c%c", &a,&b,&c,&d) == 4) {
+ if (((a == '0') || (a == '1')) && ((b == '0') || (b == '1')) && ((c == '0') || (c == '1')) && ((d == '0') || (d == '1'))) {
+ *i = 0;
+ if (a == '1')
+ *i |= ZT_ABIT;
+ if (b == '1')
+ *i |= ZT_BBIT;
+ if (c == '1')
+ *i |= ZT_CBIT;
+ if (d == '1')
+ *i |= ZT_DBIT;
+ return 0;
+ }
+ }
+ }
+ error("CAS Signalling requires idle definition in the form ':xxxx' at the end of the channel definition, where xxxx represent the a, b, c, and d bits\n");
+ return -1;
+}
+
+static int parse_channel(char *channel, int *startchan)
+{
+ if (!channel || (sscanf(channel, "%i", startchan) != 1) ||
+ (*startchan < 1)) {
+ error("DACS requires a starting channel in the form ':x' where x is the channel\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int chanconfig(char *keyword, char *args)
+{
+ int chans[ZT_MAX_CHANNELS];
+ int res = 0;
+ int x;
+ int master=0;
+ int dacschan = 0;
+ char *idle;
+ bzero(chans, sizeof(chans));
+ strtok(args, ":");
+ idle = strtok(NULL, ":");
+ if (!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) {
+ res = parse_channel(idle, &dacschan);
+ }
+ if (!res)
+ res = apply_channels(chans, args);
+ if (res <= 0)
+ return -1;
+ for (x=1;x<ZT_MAX_CHANNELS;x++)
+ if (chans[x]) {
+ if (slineno[x]) {
+ error("Channel %d already configured as '%s' at line %d\n", x, sig[x], slineno[x]);
+ continue;
+ }
+ if ((!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) && slineno[dacschan]) {
+ error("DACS Destination channel %d already configured as '%s' at line %d\n", dacschan, sig[dacschan], slineno[dacschan]);
+ continue;
+ } else {
+ cc[dacschan].chan = dacschan;
+ cc[dacschan].master = dacschan;
+ slineno[dacschan] = lineno;
+ }
+ cc[x].chan = x;
+ cc[x].master = x;
+ slineno[x] = lineno;
+ if (!strcasecmp(keyword, "e&m")) {
+ cc[x].sigtype = ZT_SIG_EM;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "e&me1")) {
+ cc[x].sigtype = ZT_SIG_EM_E1;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "fxsls")) {
+ cc[x].sigtype = ZT_SIG_FXSLS;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "fxsgs")) {
+ cc[x].sigtype = ZT_SIG_FXSGS;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "fxsks")) {
+ cc[x].sigtype = ZT_SIG_FXSKS;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "fxols")) {
+ cc[x].sigtype = ZT_SIG_FXOLS;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "fxogs")) {
+ cc[x].sigtype = ZT_SIG_FXOGS;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "fxoks")) {
+ cc[x].sigtype = ZT_SIG_FXOKS;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "cas") || !strcasecmp(keyword, "user")) {
+ if (parse_idle(&cc[x].idlebits, idle))
+ return -1;
+ cc[x].sigtype = ZT_SIG_CAS;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "dacs")) {
+ /* Setup channel for monitor */
+ cc[x].idlebits = dacschan;
+ cc[x].sigtype = ZT_SIG_DACS;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ /* Setup inverse */
+ cc[dacschan].idlebits = x;
+ cc[dacschan].sigtype = ZT_SIG_DACS;
+ sig[x] = sigtype_to_str(cc[dacschan].sigtype);
+ dacschan++;
+ } else if (!strcasecmp(keyword, "dacsrbs")) {
+ /* Setup channel for monitor */
+ cc[x].idlebits = dacschan;
+ cc[x].sigtype = ZT_SIG_DACS_RBS;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ /* Setup inverse */
+ cc[dacschan].idlebits = x;
+ cc[dacschan].sigtype = ZT_SIG_DACS_RBS;
+ sig[x] = sigtype_to_str(cc[dacschan].sigtype);
+ dacschan++;
+ } else if (!strcasecmp(keyword, "unused")) {
+ cc[x].sigtype = 0;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "indclear") || !strcasecmp(keyword, "bchan")) {
+ cc[x].sigtype = ZT_SIG_CLEAR;
+ sig[x] = sigtype_to_str(cc[x].sigtype);
+ } else if (!strcasecmp(keyword, "clear")) {
+ sig[x] = sigtype_to_str(ZT_SIG_CLEAR);
+ if (master) {
+ cc[x].sigtype = ZT_SIG_SLAVE;
+ cc[x].master = master;
+ } else {
+ cc[x].sigtype = ZT_SIG_CLEAR;
+ master = x;
+ }
+ } else if (!strcasecmp(keyword, "rawhdlc")) {
+ sig[x] = sigtype_to_str(ZT_SIG_HDLCRAW);
+ if (master) {
+ cc[x].sigtype = ZT_SIG_SLAVE;
+ cc[x].master = master;
+ } else {
+ cc[x].sigtype = ZT_SIG_HDLCRAW;
+ master = x;
+ }
+ } else if (!strcasecmp(keyword, "nethdlc")) {
+ sig[x] = sigtype_to_str(ZT_SIG_HDLCNET);
+ memset(cc[x].netdev_name, 0, sizeof(cc[x].netdev_name));
+ if (master) {
+ cc[x].sigtype = ZT_SIG_SLAVE;
+ cc[x].master = master;
+ } else {
+ cc[x].sigtype = ZT_SIG_HDLCNET;
+ if (idle) {
+ zap_copy_string(cc[x].netdev_name, idle, sizeof(cc[x].netdev_name));
+ }
+ master = x;
+ }
+ } else if (!strcasecmp(keyword, "fcshdlc")) {
+ sig[x] = sigtype_to_str(ZT_SIG_HDLCFCS);
+ if (master) {
+ cc[x].sigtype = ZT_SIG_SLAVE;
+ cc[x].master = master;
+ } else {
+ cc[x].sigtype = ZT_SIG_HDLCFCS;
+ master = x;
+ }
+ } else if (!strcasecmp(keyword, "dchan")) {
+ sig[x] = "D-channel";
+ cc[x].sigtype = ZT_SIG_HDLCFCS;
+ } else if (!strcasecmp(keyword, "hardhdlc")) {
+ sig[x] = "Hardware assisted D-channel";
+ cc[x].sigtype = ZT_SIG_HARDHDLC;
+ } else if (!strcasecmp(keyword, "mtp2")) {
+ sig[x] = "MTP2";
+ cc[x].sigtype = ZT_SIG_MTP2;
+ } else {
+ fprintf(stderr, "Huh? (%s)\n", keyword);
+ }
+ }
+ return 0;
+}
+
+static int setlaw(char *keyword, char *args)
+{
+ int res;
+ int law;
+ int x;
+ int chans[ZT_MAX_CHANNELS];
+
+ bzero(chans, sizeof(chans));
+ res = apply_channels(chans, args);
+ if (res <= 0)
+ return -1;
+ if (!strcasecmp(keyword, "alaw")) {
+ law = ZT_LAW_ALAW;
+ } else if (!strcasecmp(keyword, "mulaw")) {
+ law = ZT_LAW_MULAW;
+ } else if (!strcasecmp(keyword, "deflaw")) {
+ law = ZT_LAW_DEFAULT;
+ } else {
+ fprintf(stderr, "Huh??? Don't know about '%s' law\n", keyword);
+ return -1;
+ }
+ for (x=0;x<ZT_MAX_CHANNELS;x++) {
+ if (chans[x])
+ cc[x].deflaw = law;
+ }
+ return 0;
+}
+
+static int registerzone(char *keyword, char *args)
+{
+ if (numzones >= ZT_TONE_ZONE_MAX) {
+ error("Too many tone zones specified\n");
+ return 0;
+ }
+ zap_copy_string(zonestoload[numzones++], args, sizeof(zonestoload[0]));
+ return 0;
+}
+
+static int defaultzone(char *keyword, char *args)
+{
+ struct tone_zone *z;
+ if (!(z = tone_zone_find(args))) {
+ error("No such tone zone known: %s\n", args);
+ return 0;
+ }
+ deftonezone = z->zone;
+ return 0;
+}
+
+#if 0
+static int unimplemented(char *keyword, char *args)
+{
+ fprintf(stderr, "Warning: '%s' is not yet implemented\n", keyword);
+ return 0;
+}
+#endif
+
+
+/* Radio functions */
+
+int ctcss(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int rxtone;
+ int rxtag;
+ int txtone;
+ int isdcs = 0;
+ argc = res = parseargs(args, realargs, 3, ',');
+ if (res != 3) {
+ error("Incorrect number of arguments to 'ctcss' (should be <rxtone>,<rxtag>,<txtone>)\n");
+ }
+ res = sscanf(realargs[0], "%d", &rxtone);
+ if ((res == 1) && (rxtone < 1))
+ res = -1;
+ if (res != 1) {
+ error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]);
+ }
+ res = sscanf(realargs[1], "%i", &rxtag);
+ if ((res == 1) && (rxtag < 0))
+ res = -1;
+ if (res != 1) {
+ error("Invalid rxtag '%s', should be a number > 0.\n", realargs[1]);
+ }
+ if ((*realargs[2] == 'D') || (*realargs[2] == 'd'))
+ {
+ realargs[2]++;
+ isdcs = 0x8000;
+ }
+ res = sscanf(realargs[2], "%d", &txtone);
+ if ((res == 1) && (rxtag < 0))
+ res = -1;
+ if (res != 1) {
+ error("Invalid txtone '%s', should be a number > 0.\n", realargs[2]);
+ }
+
+ if (toneindex >= NUM_TONES)
+ {
+ error("Cannot specify more then %d CTCSS tones\n",NUM_TONES);
+ }
+ rxtones[toneindex] = rxtone;
+ rxtags[toneindex] = rxtag;
+ txtones[toneindex] = txtone | isdcs;
+ toneindex++;
+ return 0;
+}
+
+int dcsrx(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int rxtone;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'dcsrx' (should be <rxtone>)\n");
+ }
+ res = sscanf(realargs[0], "%d", &rxtone);
+ if ((res == 1) && (rxtone < 1))
+ res = -1;
+ if (res != 1) {
+ error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]);
+ }
+
+ rxtones[0] = rxtone;
+ return 0;
+}
+
+int tx(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int txtone;
+ int isdcs = 0;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'tx' (should be <txtone>)\n");
+ }
+ if ((*realargs[0] == 'D') || (*realargs[0] == 'd'))
+ {
+ realargs[0]++;
+ isdcs = 0x8000;
+ }
+ res = sscanf(realargs[0], "%d", &txtone);
+ if ((res == 1) && (txtone < 1))
+ res = -1;
+ if (res != 1) {
+ error("Invalid tx (tone) '%s', should be a number > 0.\n", realargs[0]);
+ }
+
+ txtones[0] = txtone | isdcs;
+ return 0;
+}
+
+int debounce_time(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int val;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'debouncetime' (should be <value>)\n");
+ }
+ res = sscanf(realargs[0], "%d", &val);
+ if ((res == 1) && (val < 1))
+ res = -1;
+ if (res != 1) {
+ error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+ }
+
+ debouncetime = val;
+ return 0;
+}
+
+int burst_time(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int val;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'bursttime' (should be <value>)\n");
+ }
+ res = sscanf(realargs[0], "%d", &val);
+ if ((res == 1) && (val < 1))
+ res = -1;
+ if (res != 1) {
+ error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+ }
+
+ bursttime = val;
+ return 0;
+}
+
+int tx_gain(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int val;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'txgain' (should be <value>)\n");
+ }
+ res = sscanf(realargs[0], "%d", &val);
+ if (res != 1) {
+ error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+ }
+
+ txgain = val;
+ return 0;
+}
+
+int rx_gain(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int val;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'rxgain' (should be <value>)\n");
+ }
+ res = sscanf(realargs[0], "%d", &val);
+ if (res != 1) {
+ error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+ }
+
+ rxgain = val;
+ return 0;
+}
+
+int de_emp(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int val;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'de-emp' (should be <value>)\n");
+ }
+ res = sscanf(realargs[0], "%d", &val);
+ if ((res == 1) && (val < 1))
+ res = -1;
+ if (res != 1) {
+ error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+ }
+
+ deemp = val;
+ return 0;
+}
+
+int pre_emp(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int val;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'pre_emp' (should be <value>)\n");
+ }
+ res = sscanf(realargs[0], "%d", &val);
+ if ((res == 1) && (val < 1))
+ res = -1;
+ if (res != 1) {
+ error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+ }
+
+ preemp = val;
+ return 0;
+}
+
+int invert_cor(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int val;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'invertcor' (should be <value>)\n");
+ }
+ if ((*realargs[0] == 'y') || (*realargs[0] == 'Y')) val = 1;
+ else if ((*realargs[0] == 'n') || (*realargs[0] == 'N')) val = 0;
+ else
+ {
+ res = sscanf(realargs[0], "%d", &val);
+ if ((res == 1) && (val < 0))
+ res = -1;
+ if (res != 1) {
+ error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+ }
+ }
+ invertcor = (val > 0);
+ return 0;
+}
+
+int ext_tone(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int val;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'exttone' (should be <value>)\n");
+ }
+ if ((*realargs[0] == 'y') || (*realargs[0] == 'Y')) val = 1;
+ else if ((*realargs[0] == 'n') || (*realargs[0] == 'N')) val = 0;
+ else if ((*realargs[0] == 'i') || (*realargs[0] == 'I')) val = 2;
+ else
+ {
+ res = sscanf(realargs[0], "%d", &val);
+ if ((res == 1) && (val < 0))
+ res = -1;
+ if (val > 2) res = -1;
+ if (res != 1) {
+ error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+ }
+ }
+ exttone = val;
+ return 0;
+}
+
+int cor_thresh(char *keyword, char *args)
+{
+ static char *realargs[10];
+ int argc;
+ int res;
+ int val;
+ int x = 0;
+ argc = res = parseargs(args, realargs, 1, ',');
+ if (res != 1) {
+ error("Incorrect number of arguments to 'corthresh' (should be <value>)\n");
+ }
+ res = sscanf(realargs[0], "%d", &val);
+ if ((res == 1) && (val < 1))
+ res = -1;
+ for(x = 0; corthreshes[x]; x++)
+ {
+ if (corthreshes[x] == val) break;
+ }
+ if (!corthreshes[x]) res = -1;
+ if (res != 1) {
+ error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+ }
+ corthresh = x + 1;
+ return 0;
+}
+
+int rad_apply_channels(int chans[], char *argstr)
+{
+ char *args[ZT_MAX_CHANNELS+1];
+ char *range[3];
+ int res,x, res2,y;
+ int chan;
+ int start, finish;
+ char argcopy[256];
+ res = parseargs(argstr, args, ZT_MAX_CHANNELS, ',');
+ if (res < 0)
+ error("Too many arguments... Max is %d\n", ZT_MAX_CHANNELS);
+ for (x=0;x<res;x++) {
+ if (strchr(args[x], '-')) {
+ /* It's a range */
+ zap_copy_string(argcopy, args[x], sizeof(argcopy));
+ res2 = parseargs(argcopy, range, 2, '-');
+ if (res2 != 2) {
+ error("Syntax error in range '%s'. Should be <val1>-<val2>.\n", args[x]);
+ return -1;
+ }
+ res2 =sscanf(range[0], "%i", &start);
+ if (res2 != 1) {
+ error("Syntax error. Start of range '%s' should be a number from 1 to %d\n", args[x], ZT_MAX_CHANNELS - 1);
+ return -1;
+ } else if ((start < 1) || (start >= ZT_MAX_CHANNELS)) {
+ error("Start of range '%s' must be between 1 and %d (not '%d')\n", args[x], ZT_MAX_CHANNELS - 1, start);
+ return -1;
+ }
+ res2 =sscanf(range[1], "%i", &finish);
+ if (res2 != 1) {
+ error("Syntax error. End of range '%s' should be a number from 1 to %d\n", args[x], ZT_MAX_CHANNELS - 1);
+ return -1;
+ } else if ((finish < 1) || (finish >= ZT_MAX_CHANNELS)) {
+ error("end of range '%s' must be between 1 and %d (not '%d')\n", args[x], ZT_MAX_CHANNELS - 1, finish);
+ return -1;
+ }
+ if (start > finish) {
+ error("Range '%s' should start before it ends\n", args[x]);
+ return -1;
+ }
+ for (y=start;y<=finish;y++)
+ chans[y]=1;
+ } else {
+ /* It's a single channel */
+ res2 =sscanf(args[x], "%i", &chan);
+ if (res2 != 1) {
+ error("Syntax error. Channel should be a number from 1 to %d, not '%s'\n", ZT_MAX_CHANNELS - 1, args[x]);
+ return -1;
+ } else if ((chan < 1) || (chan >= ZT_MAX_CHANNELS)) {
+ error("Channel must be between 1 and %d (not '%d')\n", ZT_MAX_CHANNELS - 1, chan);
+ return -1;
+ }
+ chans[chan]=1;
+ }
+ }
+ return res;
+}
+
+static int rad_chanconfig(char *keyword, char *args)
+{
+ int chans[ZT_MAX_CHANNELS];
+ int res = 0;
+ int x,i,n;
+ struct zt_radio_param p;
+
+ toneindex = 1;
+ bzero(chans, sizeof(chans));
+ res = rad_apply_channels(chans, args);
+ if (res <= 0)
+ return -1;
+ for (x=1;x<ZT_MAX_CHANNELS;x++) {
+ if (chans[x]) {
+ p.radpar = ZT_RADPAR_NUMTONES;
+ if (ind_ioctl(x,fd,ZT_RADIO_GETPARAM,&p) == -1)
+ n = 0; else n = p.data;
+ if (n)
+ {
+ p.radpar = ZT_RADPAR_INITTONE;
+ if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+ error("Cannot init tones for channel %d\n",x);
+ if (!rxtones[0]) for(i = 1; i <= n; i++)
+ {
+ if (rxtones[i])
+ {
+ p.radpar = ZT_RADPAR_RXTONE;
+ p.index = i;
+ p.data = rxtones[i];
+ if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+ error("Cannot set rxtone on channel %d\n",x);
+ }
+ if (rxtags[i])
+ {
+ p.radpar = ZT_RADPAR_RXTONECLASS;
+ p.index = i;
+ p.data = rxtags[i];
+ if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+ error("Cannot set rxtag on channel %d\n",x);
+ }
+ if (txtones[i])
+ {
+ p.radpar = ZT_RADPAR_TXTONE;
+ p.index = i;
+ p.data = txtones[i];
+ if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+ error("Cannot set txtone on channel %d\n",x);
+ }
+ } else { /* if we may have DCS receive */
+ if (rxtones[0])
+ {
+ p.radpar = ZT_RADPAR_RXTONE;
+ p.index = 0;
+ p.data = rxtones[0];
+ if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+ error("Cannot set DCS rxtone on channel %d\n",x);
+ }
+ }
+ if (txtones[0])
+ {
+ p.radpar = ZT_RADPAR_TXTONE;
+ p.index = 0;
+ p.data = txtones[0];
+ if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+ error("Cannot set default txtone on channel %d\n",x);
+ }
+ }
+ if (debouncetime)
+ {
+ p.radpar = ZT_RADPAR_DEBOUNCETIME;
+ p.data = debouncetime;
+ if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+ error("Cannot set debouncetime on channel %d\n",x);
+ }
+ if (bursttime)
+ {
+ p.radpar = ZT_RADPAR_BURSTTIME;
+ p.data = bursttime;
+ if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+ error("Cannot set bursttime on channel %d\n",x);
+ }
+ p.radpar = ZT_RADPAR_DEEMP;
+ p.data = deemp;
+ ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+ p.radpar = ZT_RADPAR_PREEMP;
+ p.data = preemp;
+ ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+ p.radpar = ZT_RADPAR_TXGAIN;
+ p.data = txgain;
+ ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+ p.radpar = ZT_RADPAR_RXGAIN;
+ p.data = rxgain;
+ ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+ p.radpar = ZT_RADPAR_INVERTCOR;
+ p.data = invertcor;
+ ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+ p.radpar = ZT_RADPAR_EXTRXTONE;
+ p.data = exttone;
+ ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+ if (corthresh)
+ {
+ p.radpar = ZT_RADPAR_CORTHRESH;
+ p.data = corthresh - 1;
+ if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+ error("Cannot set corthresh on channel %d\n",x);
+ }
+ }
+ }
+ clear_fields();
+ return 0;
+}
+
+/* End Radio functions */
+
+static void printconfig(int fd)
+{
+ int x,y;
+ int ps;
+ int configs=0;
+ struct zt_versioninfo vi;
+
+ strcpy(vi.version, "Unknown");
+ strcpy(vi.echo_canceller, "Unknown");
+
+ if (ioctl(fd, ZT_GETVERSION, &vi))
+ error("Unable to read Zaptel version information.\n");
+
+ printf("\nZaptel Version: %s\n"
+ "Echo Canceller: %s\n"
+ "Configuration\n"
+ "======================\n\n", vi.version, vi.echo_canceller);
+ for (x=0;x<spans;x++)
+ printf("SPAN %d: %3s/%4s Build-out: %s\n",
+ x+1, ( lc[x].lineconfig & ZT_CONFIG_D4 ? "D4" :
+ lc[x].lineconfig & ZT_CONFIG_ESF ? "ESF" :
+ lc[x].lineconfig & ZT_CONFIG_CCS ? "CCS" : "CAS" ),
+ ( lc[x].lineconfig & ZT_CONFIG_AMI ? "AMI" :
+ lc[x].lineconfig & ZT_CONFIG_B8ZS ? "B8ZS" :
+ lc[x].lineconfig & ZT_CONFIG_HDB3 ? "HDB3" : "???" ),
+ lbostr[lc[x].lbo]);
+ for (x=0;x<numdynamic;x++) {
+ printf("Dynamic span %d: driver %s, addr %s, channels %d, timing %d\n",
+ x +1, zds[x].driver, zds[x].addr, zds[x].numchans, zds[x].timing);
+ }
+ if (verbose > 1) {
+ printf("\nChannel map:\n\n");
+ for (x=1;x<ZT_MAX_CHANNELS;x++) {
+ if ((cc[x].sigtype != ZT_SIG_SLAVE) && (cc[x].sigtype)) {
+ configs++;
+ ps = 0;
+ if ((cc[x].sigtype & __ZT_SIG_DACS) == __ZT_SIG_DACS)
+ printf("Channel %02d %s to %02d", x, sig[x], cc[x].idlebits);
+ else {
+ printf("Channel %02d: %s (%s)", x, sig[x], laws[cc[x].deflaw]);
+ for (y=1;y<ZT_MAX_CHANNELS;y++)
+ if (cc[y].master == x) {
+ printf("%s%02d", ps++ ? " " : " (Slaves: ", y);
+ }
+ }
+ if (ps) printf(")\n"); else printf("\n");
+ } else
+ if (cc[x].sigtype) configs++;
+ }
+ } else
+ for (x=1;x<ZT_MAX_CHANNELS;x++)
+ if (cc[x].sigtype)
+ configs++;
+ printf("\n%d channels to configure.\n\n", configs);
+}
+
+static struct handler {
+ char *keyword;
+ int (*func)(char *keyword, char *args);
+} handlers[] = {
+ { "span", spanconfig },
+ { "dynamic", dspanconfig },
+ { "loadzone", registerzone },
+ { "defaultzone", defaultzone },
+ { "e&m", chanconfig },
+ { "e&me1", chanconfig },
+ { "fxsls", chanconfig },
+ { "fxsgs", chanconfig },
+ { "fxsks", chanconfig },
+ { "fxols", chanconfig },
+ { "fxogs", chanconfig },
+ { "fxoks", chanconfig },
+ { "rawhdlc", chanconfig },
+ { "nethdlc", chanconfig },
+ { "fcshdlc", chanconfig },
+ { "hardhdlc", chanconfig },
+ { "mtp2", chanconfig },
+ { "dchan", chanconfig },
+ { "bchan", chanconfig },
+ { "indclear", chanconfig },
+ { "clear", chanconfig },
+ { "unused", chanconfig },
+ { "cas", chanconfig },
+ { "dacs", chanconfig },
+ { "dacsrbs", chanconfig },
+ { "user", chanconfig },
+ { "alaw", setlaw },
+ { "mulaw", setlaw },
+ { "deflaw", setlaw },
+ { "ctcss", ctcss },
+ { "dcsrx", dcsrx },
+ { "rxdcs", dcsrx },
+ { "tx", tx },
+ { "debouncetime", debounce_time },
+ { "bursttime", burst_time },
+ { "exttone", ext_tone },
+ { "invertcor", invert_cor },
+ { "corthresh", cor_thresh },
+ { "rxgain", rx_gain },
+ { "txgain", tx_gain },
+ { "deemp", de_emp },
+ { "preemp", pre_emp },
+ { "channel", rad_chanconfig },
+ { "channels", rad_chanconfig },
+};
+
+static char *readline()
+{
+ static char buf[256];
+ char *c;
+ do {
+ if (!fgets(buf, sizeof(buf), cf))
+ return NULL;
+ /* Strip comments */
+ c = strchr(buf, '#');
+ if (c)
+ *c = '\0';
+ trim(buf);
+ lineno++;
+ } while (!strlen(buf));
+ return buf;
+}
+
+static void usage(char *argv0, int exitcode)
+{
+ char *c;
+ c = strrchr(argv0, '/');
+ if (!c)
+ c = argv0;
+ else
+ c++;
+ fprintf(stderr,
+ "Usage: %s [options]\n"
+ " Valid options are:\n"
+ " -c <filename> -- Use <filename> instead of " CONFIG_FILENAME "\n"
+ " -d [level] -- Generate debugging output. (Default level is 1.)\n"
+ " -f -- Always reconfigure every channel\n"
+ " -h -- Generate this help statement\n"
+ " -s -- Shutdown spans only\n"
+ " -t -- Test mode only, do not apply\n"
+ " -v -- Verbose (more -v's means more verbose)\n"
+ ,c);
+ exit(exitcode);
+}
+
+int main(int argc, char *argv[])
+{
+ int c;
+ char *buf;
+ char *key, *value;
+ int x,found;
+ while((c = getopt(argc, argv, "fthc:vsd::")) != -1) {
+ switch(c) {
+ case 'c':
+ filename=optarg;
+ break;
+ case 'h':
+ usage(argv[0], 0);
+ break;
+ case '?':
+ usage(argv[0], 1);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'f':
+ force++;
+ break;
+ case 't':
+ fo_real = 0;
+ break;
+ case 's':
+ stopmode = 1;
+ break;
+ case 'd':
+ if (optarg)
+ debug = atoi(optarg);
+ else
+ debug = 1;
+ break;
+ }
+ }
+ if (fd == -1) fd = open(MASTER_DEVICE, O_RDWR);
+ if (fd < 0)
+ error("Unable to open master device '%s'\n", MASTER_DEVICE);
+ cf = fopen(filename, "r");
+ if (cf) {
+ while((buf = readline())) {
+ if (debug & DEBUG_READER)
+ fprintf(stderr, "Line %d: %s\n", lineno, buf);
+ key = value = buf;
+ while(value && *value && (*value != '=')) value++;
+ if (value)
+ *value='\0';
+ if (value)
+ value++;
+ while(value && *value && (*value < 33)) value++;
+ if (*value) {
+ trim(key);
+ if (debug & DEBUG_PARSER)
+ fprintf(stderr, "Keyword: [%s], Value: [%s]\n", key, value);
+ } else
+ error("Syntax error. Should be <keyword>=<value>\n");
+ found=0;
+ for (x=0;x<sizeof(handlers) / sizeof(handlers[0]);x++) {
+ if (!strcasecmp(key, handlers[x].keyword)) {
+ found++;
+ handlers[x].func(key, value);
+ break;
+ }
+ }
+ if (!found)
+ error("Unknown keyword '%s'\n", key);
+ }
+ if (debug & DEBUG_READER)
+ fprintf(stderr, "<End of File>\n");
+ fclose(cf);
+ } else {
+ error("Unable to open configuration file '%s'\n", filename);
+ }
+
+ if (!errcnt) {
+ if (verbose) {
+ printconfig(fd);
+ }
+ if (fo_real) {
+ if (debug & DEBUG_APPLY) {
+ printf("About to open Master device\n");
+ fflush(stdout);
+ }
+ for (x=0;x<numdynamic;x++) {
+ /* destroy them all */
+ ioctl(fd, ZT_DYNAMIC_DESTROY, &zds[x]);
+ }
+ if (stopmode) {
+ for (x=0;x<spans;x++) {
+ if (ioctl(fd, ZT_SHUTDOWN, &lc[x].span)) {
+ fprintf(stderr, "Zaptel shutdown failed: %s\n", strerror(errno));
+ close(fd);
+ exit(1);
+ }
+ }
+ } else {
+ for (x=0;x<spans;x++) {
+ if (ioctl(fd, ZT_SPANCONFIG, lc + x)) {
+ fprintf(stderr, "ZT_SPANCONFIG failed on span %d: %s (%d)\n", lc[x].span, strerror(errno), errno);
+ close(fd);
+ exit(1);
+ }
+ }
+ for (x=0;x<numdynamic;x++) {
+ if (ioctl(fd, ZT_DYNAMIC_CREATE, &zds[x])) {
+ fprintf(stderr, "Zaptel dynamic span creation failed: %s\n", strerror(errno));
+ close(fd);
+ exit(1);
+ }
+ }
+ for (x=1;x<ZT_MAX_CHANNELS;x++) {
+ struct zt_params current_state;
+ int master;
+ int needupdate = force;
+
+ if (debug & DEBUG_APPLY) {
+ printf("Configuring device %d\n", x);
+ fflush(stdout);
+ }
+ if (!cc[x].sigtype)
+ continue;
+
+ if (!needupdate) {
+ memset(&current_state, 0, sizeof(current_state));
+ current_state.channo = cc[x].chan | ZT_GET_PARAMS_RETURN_MASTER;
+ if (ioctl(fd, ZT_GET_PARAMS, &current_state))
+ needupdate = 1;
+ }
+
+ if (!needupdate) {
+ master = current_state.channo >> 16;
+
+ if (cc[x].sigtype != current_state.sigtype) {
+ needupdate++;
+ if (verbose > 1)
+ printf("Changing signalling on channel %d from %s to %s\n",
+ cc[x].chan, sigtype_to_str(current_state.sigtype),
+ sigtype_to_str(cc[x].sigtype));
+ }
+
+ if ((cc[x].deflaw != ZT_LAW_DEFAULT) && (cc[x].deflaw != current_state.curlaw)) {
+ needupdate++;
+ if (verbose > 1)
+ printf("Changing law on channel %d from %s to %s\n",
+ cc[x].chan, laws[current_state.curlaw],
+ laws[cc[x].deflaw]);
+ }
+
+ if (cc[x].master != master) {
+ needupdate++;
+ if (verbose > 1)
+ printf("Changing master of channel %d from %d to %d\n",
+ cc[x].chan, master,
+ cc[x].master);
+ }
+
+ if (cc[x].idlebits != current_state.idlebits) {
+ needupdate++;
+ if (verbose > 1)
+ printf("Changing idle bits of channel %d from %d to %d\n",
+ cc[x].chan, current_state.idlebits,
+ cc[x].idlebits);
+ }
+ }
+
+ if (needupdate && ioctl(fd, ZT_CHANCONFIG, &cc[x])) {
+ fprintf(stderr, "ZT_CHANCONFIG failed on channel %d: %s (%d)\n", x, strerror(errno), errno);
+ if (errno == EINVAL) {
+ fprintf(stderr, "Did you forget that FXS interfaces are configured with FXO signalling\n"
+ "and that FXO interfaces use FXS signalling?\n");
+ }
+ close(fd);
+ exit(1);
+ }
+ }
+ for (x=0;x<numzones;x++) {
+ if (debug & DEBUG_APPLY) {
+ printf("Loading tone zone for %s\n", zonestoload[x]);
+ fflush(stdout);
+ }
+ if (tone_zone_register(fd, zonestoload[x]))
+ if (errno != EBUSY)
+ error("Unable to register tone zone '%s'\n", zonestoload[x]);
+ }
+ if (debug & DEBUG_APPLY) {
+ printf("Doing startup\n");
+ fflush(stdout);
+ }
+ if (deftonezone > -1) {
+ if (ioctl(fd, ZT_DEFAULTZONE, &deftonezone)) {
+ fprintf(stderr, "ZT_DEFAULTZONE failed: %s (%d)\n", strerror(errno), errno);
+ close(fd);
+ exit(1);
+ }
+ }
+ for (x=0;x<spans;x++) {
+ if (ioctl(fd, ZT_STARTUP, &lc[x].span)) {
+ fprintf(stderr, "Zaptel startup failed: %s\n", strerror(errno));
+ close(fd);
+ exit(1);
+ }
+ }
+ }
+ }
+ } else {
+ fprintf(stderr, "\n%d error(s) detected\n\n", errcnt);
+ exit(1);
+ }
+ exit(0);
+}
diff --git a/dahdi_cfg.h b/dahdi_cfg.h
new file mode 100644
index 0000000..8ad5d81
--- /dev/null
+++ b/dahdi_cfg.h
@@ -0,0 +1,27 @@
+/*
+ * BSD Telephony Of Mexico "Tormenta" card LINUX driver, version 1.6 1/9/01
+ *
+ * Working with the "Tormenta ISA" Card
+ *
+ *
+ * Part of the "Zapata" Computer Telephony Technology.
+ *
+ * See http://www.bsdtelephony.com.mx
+ *
+ *
+ * The technologies, software, hardware, designs, drawings, scheumatics, board
+ * layouts and/or artwork, concepts, methodologies (including the use of all
+ * of these, and that which is derived from the use of all of these), all other
+ * intellectual properties contained herein, and all intellectual property
+ * rights have been and shall continue to be expressly for the benefit of all
+ * mankind, and are perpetually placed in the public domain, and may be used,
+ * copied, and/or modified by anyone, in any manner, for any legal purpose,
+ * without restriction.
+ */
+
+#ifndef _ZTCFG_H
+#define _ZTCFG_H
+
+#define CONFIG_FILENAME ZAPTEL_CONFIG
+#define MASTER_DEVICE "/dev/zap/ctl"
+#endif
diff --git a/dahdi_diag.c b/dahdi_diag.c
new file mode 100644
index 0000000..50900a8
--- /dev/null
+++ b/dahdi_diag.c
@@ -0,0 +1,31 @@
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int chan;
+ if ((argc < 2) || (sscanf(argv[1], "%d", &chan) != 1)) {
+ fprintf(stderr, "Usage: ztdiag <channel>\n");
+ exit(1);
+ }
+ fd = open("/dev/zap/ctl", O_RDWR);
+ if (fd < 0) {
+ perror("open(/dev/zap/ctl");
+ exit(1);
+ }
+ if (ioctl(fd, ZT_CHANDIAG, &chan)) {
+ perror("ioctl(ZT_CHANDIAG)");
+ exit(1);
+ }
+ exit(0);
+}
diff --git a/dahdi_monitor.c b/dahdi_monitor.c
new file mode 100644
index 0000000..3c8b5ff
--- /dev/null
+++ b/dahdi_monitor.c
@@ -0,0 +1,577 @@
+/*
+ * Monitor a Zaptel Channel
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001 Linux Support Services, Inc.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under thet erms 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.
+ *
+ * Primary Author: Mark Spencer <markster@digium.com>
+ *
+ */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#include "tonezone.h"
+#else
+#include <zaptel/zaptel.h>
+#include <zaptel/tonezone.h>
+#endif
+#include <linux/soundcard.h>
+
+/*
+* defines for file handle numbers
+*/
+#define MON_BRX 0 /*!< both channels if multichannel==1 or receive otherwise */
+#define MON_TX 1 /*!< transmit channel */
+#define MON_PRE_BRX 2 /*!< same as MON_BRX but before echo cancellation */
+#define MON_PRE_TX 3 /*!< same as MON_TX but before echo cancellation */
+#define MON_STEREO 4 /*!< stereo mix of rx/tx streams */
+#define MON_PRE_STEREO 5 /*!< stereo mix of rx/tx before echo can. This is exactly what is fed into the echo can */
+
+#define BLOCK_SIZE 240
+
+#define BUFFERS 4
+
+#define FRAG_SIZE 8
+
+/* Put the ofh (output file handles) outside
+ * the main loop in case we ever add a signal
+ * handler.
+ */
+static FILE* ofh[6] = {0, 0, 0, 0, 0, 0};
+
+static int stereo = 0;
+static int verbose = 0;
+
+int audio_open(void)
+{
+ int fd;
+ int speed = 8000;
+ int fmt = AFMT_S16_LE;
+ int fragsize = (BUFFERS << 16) | (FRAG_SIZE);
+ struct audio_buf_info ispace, ospace;
+ fd = open("/dev/dsp", O_WRONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open /dev/dsp: %s\n", strerror(errno));
+ return -1;
+ }
+ /* Step 1: Signed linear */
+ if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0) {
+ fprintf(stderr, "ioctl(SETFMT) failed: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ /* Step 2: Make non-stereo */
+ if (ioctl(fd, SNDCTL_DSP_STEREO, &stereo) < 0) {
+ fprintf(stderr, "ioctl(STEREO) failed: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ if (stereo != 0) {
+ fprintf(stderr, "Can't turn stereo off :(\n");
+ }
+ /* Step 3: Make 8000 Hz */
+ if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) {
+ fprintf(stderr, "ioctl(SPEED) failed: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ if (speed != 8000)
+ fprintf(stderr, "Warning: Requested 8000 Hz, got %d\n", speed);
+ if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fragsize)) {
+ fprintf(stderr, "Sound card won't let me set fragment size to %u %u-byte buffers (%x)\n"
+ "so sound may be choppy: %s.\n", BUFFERS, (1 << FRAG_SIZE), fragsize, strerror(errno));
+ }
+ bzero(&ispace, sizeof(ispace));
+ bzero(&ospace, sizeof(ospace));
+
+ if (ioctl(fd, SNDCTL_DSP_GETISPACE, &ispace)) {
+ /* They don't support block size stuff, so just return but notify the user */
+ fprintf(stderr, "Sound card won't let me know the input buffering...\n");
+ }
+ if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &ospace)) {
+ /* They don't support block size stuff, so just return but notify the user */
+ fprintf(stderr, "Sound card won't let me know the output buffering...\n");
+ }
+ fprintf(stderr, "New input space: %d of %d %d byte fragments (%d bytes left)\n",
+ ispace.fragments, ispace.fragstotal, ispace.fragsize, ispace.bytes);
+ fprintf(stderr, "New output space: %d of %d %d byte fragments (%d bytes left)\n",
+ ospace.fragments, ospace.fragstotal, ospace.fragsize, ospace.bytes);
+ return fd;
+}
+
+int pseudo_open(void)
+{
+ int fd;
+ int x = 1;
+ fd = open("/dev/zap/pseudo", O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open pseudo channel: %s\n", strerror(errno));
+ return -1;
+ }
+ if (ioctl(fd, ZT_SETLINEAR, &x)) {
+ fprintf(stderr, "Unable to set linear mode: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ x = BLOCK_SIZE;
+ if (ioctl(fd, ZT_SET_BLOCKSIZE, &x)) {
+ fprintf(stderr, "unable to set sane block size: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+#define barlen 35
+#define baroptimal 3250
+//define barlevel 200
+#define barlevel ((baroptimal/barlen)*2)
+#define maxlevel (barlen*barlevel)
+
+void draw_barheader()
+{
+ char bar[barlen+5];
+
+ memset(bar, '-', sizeof(bar));
+ memset(bar, '<', 1);
+ memset(bar+barlen+2, '>', 1);
+ memset(bar+barlen+3, '\0', 1);
+
+ zap_copy_string(bar+(barlen/2), "(RX)", 4);
+ printf("%s", bar);
+
+ zap_copy_string(bar+(barlen/2), "(TX)", 4);
+ printf(" %s\n", bar);
+}
+
+void draw_bar(int avg, int max)
+{
+ char bar[barlen+5];
+
+ memset(bar, ' ', sizeof(bar));
+
+ max /= barlevel;
+ avg /= barlevel;
+ if (avg > barlen)
+ avg = barlen;
+ if (max > barlen)
+ max = barlen;
+
+ if (avg > 0)
+ memset(bar, '#', avg);
+ if (max > 0)
+ memset(bar + max, '*', 1);
+
+ bar[barlen+1] = '\0';
+ printf("%s", bar);
+ fflush(stdout);
+}
+
+void visualize(short *tx, short *rx, int cnt)
+{
+ int x;
+ float txavg = 0;
+ float rxavg = 0;
+ static int txmax = 0;
+ static int rxmax = 0;
+ static int sametxmax = 0;
+ static int samerxmax = 0;
+ static int txbest = 0;
+ static int rxbest = 0;
+ float ms;
+ static struct timeval last;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ ms = (tv.tv_sec - last.tv_sec) * 1000.0 + (tv.tv_usec - last.tv_usec) / 1000.0;
+ for (x=0;x<cnt;x++) {
+ txavg += abs(tx[x]);
+ rxavg += abs(rx[x]);
+ }
+ txavg = abs(txavg / cnt);
+ rxavg = abs(rxavg / cnt);
+
+ if (txavg > txbest)
+ txbest = txavg;
+ if (rxavg > rxbest)
+ rxbest = rxavg;
+
+ /* Update no more than 10 times a second */
+ if (ms < 100)
+ return;
+
+ /* Save as max levels, if greater */
+ if (txbest > txmax) {
+ txmax = txbest;
+ sametxmax = 0;
+ }
+ if (rxbest > rxmax) {
+ rxmax = rxbest;
+ samerxmax = 0;
+ }
+
+ memcpy(&last, &tv, sizeof(last));
+
+ /* Clear screen */
+ printf("\r ");
+ draw_bar(rxbest, rxmax);
+ printf(" ");
+ draw_bar(txbest, txmax);
+ if (verbose)
+ printf(" Rx: %5d (%5d) Tx: %5d (%5d)", rxbest, rxmax, txbest, txmax);
+ txbest = 0;
+ rxbest = 0;
+
+ /* If we have had the same max hits for x times, clear the values */
+ sametxmax++;
+ samerxmax++;
+ if (sametxmax > 6) {
+ txmax = 0;
+ sametxmax = 0;
+ }
+ if (samerxmax > 6) {
+ rxmax = 0;
+ samerxmax = 0;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int afd = -1;
+ int pfd[4] = {-1, -1, -1, -1};
+ short buf_brx[BLOCK_SIZE * 2];
+ short buf_tx[BLOCK_SIZE * 4];
+ short stereobuf[BLOCK_SIZE * 4];
+ int res_brx, res_tx;
+ int visual = 0;
+ int multichannel = 0;
+ int ossoutput = 0;
+ int preecho = 0;
+ int savefile = 0;
+ int stereo_output = 0;
+ int limit = 0;
+ int readcount = 0;
+ int x, i, chan;
+ struct zt_confinfo zc;
+
+ if ((argc < 2) || (atoi(argv[1]) < 1)) {
+ fprintf(stderr, "Usage: ztmonitor <channel num> [-v[v]] [-m] [-o] [-p] [-l limit] [-f FILE | -s FILE | -r FILE1 -t FILE2] [-F FILE | -S FILE | -R FILE1 -T FILE2]\n");
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -v: Visual mode. Implies -m.\n");
+ fprintf(stderr, " -vv: Visual/Verbose mode. Implies -m.\n");
+ fprintf(stderr, " -l LIMIT: Stop after reading LIMIT bytes\n");
+ fprintf(stderr, " -m: Separate rx/tx streams.\n");
+ fprintf(stderr, " -o: Output audio via OSS. Note: Only 'normal' combined rx/tx streams are output via OSS.\n");
+ fprintf(stderr, " -p: Get a pre-echocanceled stream.\n");
+ fprintf(stderr, " -f FILE: Save combined rx/tx stream to FILE. Cannot be used with -m.\n");
+ fprintf(stderr, " -r FILE: Save rx stream to FILE. Implies -m.\n");
+ fprintf(stderr, " -t FILE: Save tx stream to FILE. Implies -m.\n");
+ fprintf(stderr, " -s FILE: Save stereo rx/tx stream to FILE.\n");
+ fprintf(stderr, " -F FILE: Save combined pre-echocanceled rx/tx stream to FILE. Cannot be used with -m. Implies -p.\n");
+ fprintf(stderr, " -R FILE: Save pre-echocanceled rx stream to FILE. Implies -m and -p.\n");
+ fprintf(stderr, " -T FILE: Save pre-echocanceled tx stream to FILE. Implies -m and -p.\n");
+ fprintf(stderr, " -S FILE: Save pre-echocanceled stereo rx/tx stream to FILE. Implies -p.\n");
+ fprintf(stderr, "Examples:\n");
+ fprintf(stderr, "Save a stream to a file\n");
+ fprintf(stderr, " ztmonitor 1 -f stream.raw\n");
+ fprintf(stderr, "Visualize an rx/tx stream and save them to separate files.\n");
+ fprintf(stderr, " ztmonitor 1 -v -r streamrx.raw -t streamtx.raw\n");
+ fprintf(stderr, "Play a combined rx/tx stream via OSS and save it to a file\n");
+ fprintf(stderr, " ztmonitor 1 -o -f stream.raw\n");
+ fprintf(stderr, "Save a combined normal rx/tx stream and a combined 'preecho' rx/tx stream to files\n");
+ fprintf(stderr, " ztmonitor 1 -p -f stream.raw -F streampreecho.raw\n");
+ fprintf(stderr, "Save a normal rx/tx stream and a 'preecho' rx/tx stream to separate files\n");
+ fprintf(stderr, " ztmonitor 1 -m -p -r streamrx.raw -t streamtx.raw -R streampreechorx.raw -T streampreechotx.raw\n");
+ exit(1);
+ }
+
+ chan = atoi(argv[1]);
+
+ for (i = 2; i < argc; ++i) {
+ if (!strcmp(argv[i], "-v")) {
+ if (visual)
+ verbose = 1;
+ visual = 1;
+ multichannel = 1;
+ } else if (!strcmp(argv[i], "-vv")) {
+ visual = 1;
+ verbose = 1;
+ multichannel = 1;
+ } else if ((!strcmp(argv[i], "-f") || !strcmp(argv[i], "-r") || !strcmp(argv[i], "-t")
+ || !strcmp(argv[i], "-F") || !strcmp(argv[i], "-R") || !strcmp(argv[i], "-T")
+ || !strcmp(argv[i], "-s") || !strcmp(argv[i], "-S"))
+ && (i+1) < argc) {
+ char *output_file;
+
+ /* Set which file descriptor to use */
+ if (!strcmp(argv[i], "-f")) {
+ savefile = 1;
+ x = MON_BRX;
+ } else if (!strcmp(argv[i], "-r")) {
+ savefile = 1;
+ multichannel = 1;
+ x = MON_BRX;
+ } else if (!strcmp(argv[i], "-t")) {
+ savefile = 1;
+ multichannel = 1;
+ x = MON_TX;
+ } else if (!strcmp(argv[i], "-s")) {
+ savefile = 1;
+ stereo_output = 1;
+ multichannel = 1;
+ x = MON_STEREO;
+ } else if (!strcmp(argv[i], "-F")) {
+ savefile = 1;
+ preecho = 1;
+ x = MON_PRE_BRX;
+ } else if (!strcmp(argv[i], "-R")) {
+ savefile = 1;
+ multichannel = 1;
+ preecho = 1;
+ x = MON_PRE_BRX;
+ } else if (!strcmp(argv[i], "-T")) {
+ savefile = 1;
+ multichannel = 1;
+ preecho = 1;
+ x = MON_PRE_TX;
+ } else if (!strcmp(argv[i], "-S")) {
+ savefile = 1;
+ preecho = 1;
+ stereo_output = 1;
+ multichannel = 1;
+ x = MON_PRE_STEREO;
+ } else
+ x = MON_BRX;
+
+ ++i; /* we care about the file name */
+ output_file = argv[i];
+ fprintf(stderr, "Output to %s\n", output_file);
+ if ((ofh[x] = fopen(output_file, "w"))<0) {
+ fprintf(stderr, "Could not open %s for writing: %s\n",
+ output_file, strerror(errno));
+ exit(1);
+ }
+ fprintf(stderr, "Run e.g., 'sox -r 8000 -s -w -c 1 %s %s.wav' to convert.\n",
+ output_file, output_file);
+ } else if (!strcmp(argv[i], "-m")) {
+ multichannel = 1;
+ } else if (!strcmp(argv[i], "-o")) {
+ ossoutput = 1;
+ } else if (!strcmp(argv[i], "-p")) {
+ preecho = 1;
+ } else if (!strcmp(argv[i], "-l") && isdigit(argv[i+1][0])) {
+ limit = atoi(argv[i+1]);
+ i++;
+ }
+ }
+
+ if (ossoutput) {
+ if (multichannel) {
+ printf("Multi-channel audio is enabled. OSS output will be disabled.\n");
+ ossoutput = 0;
+ } else {
+ /* Open audio */
+ if ((afd = audio_open()) < 0) {
+ printf("Cannot open audio ...\n");
+ ossoutput = 0;
+ }
+ }
+ }
+ if (!ossoutput && !multichannel && !savefile) {
+ fprintf(stderr, "Nothing to do with the stream(s) ...\n");
+ exit(1);
+ }
+
+ /* Open Pseudo device */
+ if ((pfd[MON_BRX] = pseudo_open()) < 0)
+ exit(1);
+ if (multichannel && ((pfd[MON_TX] = pseudo_open()) < 0))
+ exit(1);
+ if (preecho) {
+ if ((pfd[MON_PRE_BRX] = pseudo_open()) < 0)
+ exit(1);
+ if (multichannel && ((pfd[MON_PRE_TX] = pseudo_open()) < 0))
+ exit(1);
+ }
+ /* Conference them */
+ if (multichannel) {
+ memset(&zc, 0, sizeof(zc));
+ zc.chan = 0;
+ zc.confno = chan;
+ /* Two pseudo's, one for tx, one for rx */
+ zc.confmode = ZT_CONF_MONITOR;
+ if (ioctl(pfd[MON_BRX], ZT_SETCONF, &zc) < 0) {
+ fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+ exit(1);
+ }
+ memset(&zc, 0, sizeof(zc));
+ zc.chan = 0;
+ zc.confno = chan;
+ zc.confmode = ZT_CONF_MONITORTX;
+ if (ioctl(pfd[MON_TX], ZT_SETCONF, &zc) < 0) {
+ fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+ exit(1);
+ }
+ if (preecho) {
+ memset(&zc, 0, sizeof(zc));
+ zc.chan = 0;
+ zc.confno = chan;
+ /* Two pseudo's, one for tx, one for rx */
+ zc.confmode = ZT_CONF_MONITOR_RX_PREECHO;
+ if (ioctl(pfd[MON_PRE_BRX], ZT_SETCONF, &zc) < 0) {
+ fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+ exit(1);
+ }
+ memset(&zc, 0, sizeof(zc));
+ zc.chan = 0;
+ zc.confno = chan;
+ zc.confmode = ZT_CONF_MONITOR_TX_PREECHO;
+ if (ioctl(pfd[MON_PRE_TX], ZT_SETCONF, &zc) < 0) {
+ fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+ exit(1);
+ }
+ }
+ } else {
+ memset(&zc, 0, sizeof(zc));
+ zc.chan = 0;
+ zc.confno = chan;
+ zc.confmode = ZT_CONF_MONITORBOTH;
+ if (ioctl(pfd[MON_BRX], ZT_SETCONF, &zc) < 0) {
+ fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+ exit(1);
+ }
+ if (preecho) {
+ memset(&zc, 0, sizeof(zc));
+ zc.chan = 0;
+ zc.confno = chan;
+ zc.confmode = ZT_CONF_MONITORBOTH_PREECHO;
+ if (ioctl(pfd[MON_PRE_BRX], ZT_SETCONF, &zc) < 0) {
+ fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+ exit(1);
+ }
+ }
+ }
+ if (visual) {
+ printf("\nVisual Audio Levels.\n");
+ printf("--------------------\n");
+ printf(" Use zapata.conf file to adjust the gains if needed.\n\n");
+ printf("( # = Audio Level * = Max Audio Hit )\n");
+ draw_barheader();
+ }
+ /* Now, copy from pseudo to audio */
+ for (;;) {
+ res_brx = read(pfd[MON_BRX], buf_brx, sizeof(buf_brx));
+ if (res_brx < 1)
+ break;
+ readcount += res_brx;
+ if (ofh[MON_BRX])
+ fwrite(buf_brx, 1, res_brx, ofh[MON_BRX]);
+
+ if (multichannel) {
+ res_tx = read(pfd[MON_TX], buf_tx, res_brx);
+ if (res_tx < 1)
+ break;
+ if (ofh[MON_TX])
+ fwrite(buf_tx, 1, res_tx, ofh[MON_TX]);
+
+ if (stereo_output && ofh[MON_STEREO]) {
+ for (x=0;x<res_tx;x++) {
+ stereobuf[x*2] = buf_brx[x];
+ stereobuf[x*2+1] = buf_tx[x];
+ }
+ fwrite(stereobuf, 1, res_tx*2, ofh[MON_STEREO]);
+ }
+
+ if (visual) {
+ if (res_brx == res_tx)
+ visualize((short *)buf_tx, (short *)buf_brx, res_brx/2);
+ else
+ printf("Huh? res_tx = %d, res_brx = %d?\n", res_tx, res_brx);
+ }
+ }
+
+ if (preecho) {
+ res_brx = read(pfd[MON_PRE_BRX], buf_brx, sizeof(buf_brx));
+ if (res_brx < 1)
+ break;
+ if (ofh[MON_PRE_BRX])
+ fwrite(buf_brx, 1, res_brx, ofh[MON_PRE_BRX]);
+
+ if (multichannel) {
+ res_tx = read(pfd[MON_PRE_TX], buf_tx, res_brx);
+ if (res_tx < 1)
+ break;
+ if (ofh[MON_PRE_TX])
+ fwrite(buf_tx, 1, res_tx, ofh[MON_PRE_TX]);
+
+ if (stereo_output && ofh[MON_PRE_STEREO]) {
+ for (x=0;x<res_brx;x++) {
+ stereobuf[x*2] = buf_brx[x];
+ stereobuf[x*2+1] = buf_tx[x];
+ }
+ fwrite(stereobuf, 1, res_brx*2, ofh[MON_PRE_STEREO]);
+ }
+
+ /* XXX How are we going to visualize the preecho set of streams?
+ if (visual) {
+ if (res == res2)
+ visualize((short *)buf, (short *)buf2, res/2);
+ else
+ printf("Huh? res = %d, res2 = %d?\n", res, res2);
+ } */
+ }
+ }
+
+ if (ossoutput && afd) {
+ if (stereo) {
+ for (x=0;x<res_brx;x++)
+ buf_tx[x<<1] = buf_tx[(x<<1) + 1] = buf_brx[x];
+ write(afd, buf_tx, res_brx << 1);
+ } else
+ write(afd, buf_brx, res_brx);
+ }
+
+ if (limit && readcount >= limit) {
+ /* bail if we've read too much */
+ break;
+ }
+ }
+ if (ofh[MON_BRX]) fclose(ofh[MON_BRX]);
+ if (ofh[MON_TX]) fclose(ofh[MON_TX]);
+ if (ofh[MON_PRE_BRX]) fclose(ofh[MON_PRE_BRX]);
+ if (ofh[MON_PRE_TX]) fclose(ofh[MON_PRE_TX]);
+ if (ofh[MON_STEREO]) fclose(ofh[MON_STEREO]);
+ if (ofh[MON_PRE_STEREO]) fclose(ofh[MON_PRE_STEREO]);
+ exit(0);
+}
diff --git a/dahdi_scan.c b/dahdi_scan.c
new file mode 100644
index 0000000..64298ee
--- /dev/null
+++ b/dahdi_scan.c
@@ -0,0 +1,172 @@
+/*
+ * Scan and output information about Zaptel spans and ports.
+ *
+ * Written by Brandon Kruse <bkruse@digium.com>
+ * and Kevin P. Fleming <kpfleming@digium.com>
+ * Copyright (C) 2007 Digium, Inc.
+ *
+ * Based on zttool written by Mark Spencer <markster@digium.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under thet erms 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 <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+int main(int argc, char *argv[])
+{
+ int ctl;
+ int x, y;
+ struct zt_params params;
+ unsigned int basechan = 1;
+ struct zt_spaninfo s;
+ char buf[100];
+ char alarms[50];
+
+ if ((ctl = open("/dev/zap/ctl", O_RDWR)) < 0) {
+ fprintf(stderr, "Unable to open /dev/zap/ctl: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ for (x = 1; x < ZT_MAX_SPANS; x++) {
+ memset(&s, 0, sizeof(s));
+ s.spanno = x;
+ if (ioctl(ctl, ZT_SPANSTAT, &s))
+ continue;
+
+ alarms[0] = '\0';
+ if (s.alarms) {
+ if (s.alarms & ZT_ALARM_BLUE)
+ strcat(alarms,"BLU/");
+ if (s.alarms & ZT_ALARM_YELLOW)
+ strcat(alarms, "YEL/");
+ if (s.alarms & ZT_ALARM_RED)
+ strcat(alarms, "RED/");
+ if (s.alarms & ZT_ALARM_LOOPBACK)
+ strcat(alarms,"LB/");
+ if (s.alarms & ZT_ALARM_RECOVER)
+ strcat(alarms,"REC/");
+ if (s.alarms & ZT_ALARM_NOTOPEN)
+ strcat(alarms, "NOP/");
+ if (!strlen(alarms))
+ strcat(alarms, "UUU/");
+ if (strlen(alarms)) {
+ /* Strip trailing / */
+ alarms[strlen(alarms)-1]='\0';
+ }
+ } else {
+ if (s.numchans)
+ strcpy(alarms, "OK");
+ else
+ strcpy(alarms, "UNCONFIGURED");
+ }
+
+ fprintf(stdout, "[%d]\n", x);
+ fprintf(stdout, "active=yes\n");
+ fprintf(stdout, "alarms=%s\n", alarms);
+ fprintf(stdout, "description=%s\n", s.desc);
+ fprintf(stdout, "name=%s\n", s.name);
+ fprintf(stdout, "manufacturer=%s\n", s.manufacturer);
+ fprintf(stdout, "devicetype=%s\n", s.devicetype);
+ fprintf(stdout, "location=%s\n", s.location);
+ fprintf(stdout, "basechan=%d\n", basechan);
+ fprintf(stdout, "totchans=%d\n", s.totalchans);
+ fprintf(stdout, "irq=%d\n", s.irq);
+ y = basechan;
+ memset(&params, 0, sizeof(params));
+ params.channo = y;
+ if (ioctl(ctl, ZT_GET_PARAMS, &params)) {
+ basechan += s.totalchans;
+ continue;
+ }
+
+ if (params.sigcap & (__ZT_SIG_DACS | ZT_SIG_CAS)) {
+ /* this is a digital span */
+ fprintf(stdout, "type=digital-%s\n", s.spantype);
+ fprintf(stdout, "syncsrc=%d\n", s.syncsrc);
+ fprintf(stdout, "lbo=%s\n", s.lboname);
+ fprintf(stdout, "coding_opts=");
+ buf[0] = '\0';
+ if (s.linecompat & ZT_CONFIG_B8ZS) strcat(buf, "B8ZS,");
+ if (s.linecompat & ZT_CONFIG_AMI) strcat(buf, "AMI,");
+ if (s.linecompat & ZT_CONFIG_HDB3) strcat(buf, "HDB3,");
+ buf[strlen(buf) - 1] = '\0';
+ fprintf(stdout, "%s\n", buf);
+ fprintf(stdout, "framing_opts=");
+ buf[0] = '\0';
+ if (s.linecompat & ZT_CONFIG_ESF) strcat(buf, "ESF,");
+ if (s.linecompat & ZT_CONFIG_D4) strcat(buf, "D4,");
+ if (s.linecompat & ZT_CONFIG_CCS) strcat(buf, "CCS,");
+ if (s.linecompat & ZT_CONFIG_CRC4) strcat(buf, "CRC4,");
+ buf[strlen(buf) - 1] = '\0';
+ fprintf(stdout, "%s\n", buf);
+ fprintf(stdout, "coding=");
+ if (s.lineconfig & ZT_CONFIG_B8ZS) fprintf(stdout, "B8ZS");
+ else if (s.lineconfig & ZT_CONFIG_AMI) fprintf(stdout, "AMI");
+ else if (s.lineconfig & ZT_CONFIG_HDB3) fprintf(stdout, "HDB3");
+ fprintf(stdout, "\n");
+ fprintf(stdout, "framing=");
+ if (s.lineconfig & ZT_CONFIG_ESF) fprintf(stdout, "ESF");
+ else if (s.lineconfig & ZT_CONFIG_D4) fprintf(stdout, "D4");
+ else if (s.lineconfig & ZT_CONFIG_CCS) fprintf(stdout, "CCS");
+ else if (s.lineconfig & ZT_CONFIG_CRC4) fprintf(stdout, "/CRC4");
+ fprintf(stdout, "\n");
+ } else {
+ /* this is an analog span */
+ fprintf(stdout, "type=analog\n");
+ for (y = basechan; y < (basechan + s.totalchans); y++) {
+ memset(&params, 0, sizeof(params));
+ params.channo = y;
+ if (ioctl(ctl, ZT_GET_PARAMS, &params)) {
+ fprintf(stdout, "port=%d,unknown\n", y);
+ continue;
+ };
+ fprintf(stdout, "port=%d,", y);
+ switch (params.sigcap & (__ZT_SIG_FXO | __ZT_SIG_FXS)) {
+ case __ZT_SIG_FXO:
+ fprintf(stdout, "FXS");
+ break;
+ case __ZT_SIG_FXS:
+ fprintf(stdout, "FXO");
+ break;
+ default:
+ fprintf(stdout, "none");
+ }
+ if (params.sigcap & ZT_SIG_BROKEN)
+ fprintf(stdout, " FAILED");
+ fprintf(stdout, "\n");
+ }
+ }
+
+ basechan += s.totalchans;
+ }
+
+ exit(0);
+}
diff --git a/dahdi_speed.c b/dahdi_speed.c
new file mode 100644
index 0000000..7b41d78
--- /dev/null
+++ b/dahdi_speed.c
@@ -0,0 +1,36 @@
+/*
+ *
+ * Generic speed test -- Run an infinite loop and
+ * see how high we can count (in 5 seconds). You
+ * can use this to measure how much CPU zaptel REALLY
+ * is taking.
+ *
+ * MUST BE COMPILED WITHOUT OPTIMIZATION
+ *
+ */
+
+#include <stdio.h>
+#include <sys/signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static long count=0;
+
+static void alm(int sig)
+{
+ printf("Count: %ld\n", count);
+ exit(0);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int a=0,b=0,c;
+ signal(SIGALRM, alm);
+ alarm(5);
+ for (;;) {
+ for (c=0;c<1000;c++)
+ a = a * b;
+ count++;
+ }
+}
diff --git a/dahdi_test.c b/dahdi_test.c
new file mode 100644
index 0000000..1ee1a2c
--- /dev/null
+++ b/dahdi_test.c
@@ -0,0 +1,135 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <math.h>
+#include <getopt.h>
+
+#define SIZE 8000
+
+static int pass = 0;
+static float best = 0.0;
+static float worst = 100.0;
+static double total = 0.0;
+static double delay_total = 0.0;
+
+void hup_handler(int sig)
+{
+ printf("\n--- Results after %d passes ---\n", pass);
+ printf("Best: %.3f -- Worst: %.3f -- Average: %f, Difference: %f\n",
+ best, worst, pass ? total/pass : 100.00, pass ? delay_total/pass : 100);
+ exit(0);
+}
+
+static void usage(char *argv0)
+{
+ char *c;
+ c = strrchr(argv0, '/');
+ if (!c)
+ c = argv0;
+ else
+ c++;
+ fprintf(stderr,
+ "Usage: %s [-c COUNT] [-v]\n"
+ " Valid options are:\n"
+ " -c COUNT Run just COUNT cycles (otherwise: forever).\n"
+ " -v More verbose output.\n"
+ " -h This help text.\n"
+ ,c);
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int res;
+ int c;
+ int count=0;
+ int seconds = 0;
+ int curarg = 1;
+ int verbose=0;
+ char buf[8192];
+ float score;
+ float ms;
+ struct timeval start, now;
+ fd = open("/dev/zap/pseudo", O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open zap interface: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ while((c = getopt(argc, argv, "c:hv")) != -1) {
+ switch(c) {
+ case 'c':
+ seconds = atoi(optarg);
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ case '?':
+ usage(argv[0]);
+ exit(1);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ }
+ }
+ while(curarg < argc) {
+ if (!strcasecmp(argv[curarg], "-v"))
+ verbose++;
+ if (!strcasecmp(argv[curarg], "-c") && argc > curarg)
+ seconds = atoi(argv[curarg + 1]);
+ curarg++;
+ }
+ printf("Opened pseudo zap interface, measuring accuracy...\n");
+ signal(SIGHUP, hup_handler);
+ signal(SIGINT, hup_handler);
+ signal(SIGALRM, hup_handler);
+ /* Flush input buffer */
+ for (count = 0;count < 4; count++)
+ res = read(fd, buf, sizeof(buf));
+ count = 0;
+ ms = 0; /* Makes the compiler happy */
+ if (seconds > 0)
+ alarm(seconds + 1); /* This will give 'seconds' cycles */
+ for(;;) {
+ if (count == 0)
+ ms = 0;
+ gettimeofday(&start, NULL);
+ res = read(fd, buf, sizeof(buf));
+ if (res < 0) {
+ fprintf(stderr, "Failed to read from pseudo interface: %s\n", strerror(errno));
+ exit(1);
+ }
+ count += res;
+ gettimeofday(&now, NULL);
+ ms += (now.tv_sec - start.tv_sec) * 8000;
+ ms += (now.tv_usec - start.tv_usec) / 125.0;
+ if (count >= SIZE) {
+ double percent;
+
+ percent = 100.0 * (count - ms) / count;
+ if (verbose)
+ printf("\n%d zaptel samples in %0.3f system clock sample intervals (%.3f%%)",
+ count, ms, 100 - percent);
+ else if ((pass % 8) == 7) printf("\n");
+ score = 100.0 - fabs(percent);
+ if (score > best)
+ best = score;
+ if (score < worst)
+ worst = score;
+ if (!verbose)
+ printf("%f%% ", score);
+ total += score;
+ delay_total += 100 - percent;
+ fflush(stdout);
+ count = 0;
+ pass++;
+ }
+ }
+}
diff --git a/dahdi_tool.c b/dahdi_tool.c
new file mode 100644
index 0000000..c1e97bc
--- /dev/null
+++ b/dahdi_tool.c
@@ -0,0 +1,589 @@
+/*
+ * Configuration program for Zapata Telephony Interface
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001 Linux Support Services, Inc.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under thet erms 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.
+ *
+ * Primary Author: Mark Spencer <markster@digium.com>
+ *
+ */
+
+/*** MODULEINFO
+ <depend>newt</depend>
+ ***/
+
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <newt.h>
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#include "tonezone.h"
+#else
+#include <zaptel/zaptel.h>
+#include <zaptel/tonezone.h>
+#endif
+
+static int ctl = -1;
+static int span_max_chan_pos;
+
+static ZT_SPANINFO s[ZT_MAX_SPANS];
+
+static char *zt_txlevelnames[] = {
+"0 db (CSU)/0-133 feet (DSX-1)",
+"133-266 feet (DSX-1)",
+"266-399 feet (DSX-1)",
+"399-533 feet (DSX-1)",
+"533-655 feet (DSX-1)",
+"-7.5db (CSU)",
+"-15db (CSU)",
+"-22.5db (CSU)"
+} ;
+
+static char *alarmstr(int span)
+{
+ static char alarms[80];
+ strcpy(alarms, "");
+ if (s[span].alarms > 0) {
+ if (s[span].alarms & ZT_ALARM_BLUE)
+ strcat(alarms,"Blue Alarm/");
+ if (s[span].alarms & ZT_ALARM_YELLOW)
+ strcat(alarms, "Yellow Alarm/");
+ if (s[span].alarms & ZT_ALARM_RED)
+ strcat(alarms, "Red Alarm/");
+ if (s[span].alarms & ZT_ALARM_LOOPBACK)
+ strcat(alarms,"Loopback/");
+ if (s[span].alarms & ZT_ALARM_RECOVER)
+ strcat(alarms,"Recovering/");
+ if (s[span].alarms & ZT_ALARM_NOTOPEN)
+ strcat(alarms, "Not Open/");
+ if (!strlen(alarms))
+ strcat(alarms, "<unknown>/");
+ if (strlen(alarms)) {
+ /* Strip trailing / */
+ alarms[strlen(alarms)-1]='\0';
+ }
+ } else
+ strcpy(alarms, "No alarms.");
+ return alarms;
+}
+
+static char *getalarms(int span, int err)
+{
+ int res;
+ static char tmp[256];
+ char alarms[50];
+ s[span].spanno = span;
+ res = ioctl(ctl, ZT_SPANSTAT, &s[span]);
+ if (res) {
+ if (err)
+ fprintf(stderr, "Unable to get span info on span %d: %s\n", span, strerror(errno));
+ return NULL;
+ }
+ strcpy(alarms, "");
+ if (s[span].alarms > 0) {
+ if (s[span].alarms & ZT_ALARM_BLUE)
+ strcat(alarms,"BLU/");
+ if (s[span].alarms & ZT_ALARM_YELLOW)
+ strcat(alarms, "YEL/");
+ if (s[span].alarms & ZT_ALARM_RED)
+ strcat(alarms, "RED/");
+ if (s[span].alarms & ZT_ALARM_LOOPBACK)
+ strcat(alarms,"LB/");
+ if (s[span].alarms & ZT_ALARM_RECOVER)
+ strcat(alarms,"REC/");
+ if (s[span].alarms & ZT_ALARM_NOTOPEN)
+ strcat(alarms, "NOP/");
+ if (!strlen(alarms))
+ strcat(alarms, "UUU/");
+ if (strlen(alarms)) {
+ /* Strip trailing / */
+ alarms[strlen(alarms)-1]='\0';
+ }
+ } else {
+ if (s[span].numchans)
+ strcpy(alarms, "OK");
+ else
+ strcpy(alarms, "UNCONFIGURED");
+ }
+
+ snprintf(tmp, sizeof(tmp), "%-15s %s", alarms, s[span].desc);
+ return tmp;
+}
+
+static void add_cards(newtComponent spans)
+{
+ int x;
+ char *s;
+ void *prev=NULL;
+
+ if (spans)
+ prev = newtListboxGetCurrent(spans);
+ newtListboxClear(spans);
+ for (x=0;x<ZT_MAX_SPANS;x++) {
+ s = getalarms(x, 0);
+ if (s && spans) {
+ /* Found one! */
+ newtListboxAppendEntry(spans, s, (void *)(long)x);
+ }
+ }
+ if (spans)
+ newtListboxSetCurrentByKey(spans, prev);
+
+}
+
+static void sel_callback(newtComponent c, void *cbdata)
+{
+ int span;
+ char info[256];
+ char info2[256];
+ cbdata = newtListboxGetCurrent(c);
+ if (cbdata) {
+ span = (long)(cbdata);
+ snprintf(info, sizeof (info), "Span %d: %d total channels, %d configured", span, s[span].totalchans, s[span].numchans);
+ snprintf(info2, sizeof(info2), "%-59s F1=Details F10=Quit", info);
+ } else {
+ span = -1;
+ strcpy(info, "There are no zaptel spans on this system.");
+ snprintf(info2, sizeof(info2), "%-59s F10=Quit", info);
+ }
+ newtPopHelpLine();
+ newtPushHelpLine(info2);
+}
+
+static void show_bits(int span, newtComponent bitbox, newtComponent inuse, newtComponent levels, newtComponent bpvcount,
+ newtComponent alarms, newtComponent syncsrc, newtComponent irqmisses)
+{
+ ZT_PARAMS zp;
+ int x;
+ int res;
+ char c;
+ char tabits[80];
+ char tbbits[80];
+ char tcbits[80];
+ char tdbits[80];
+ char rabits[80];
+ char rbbits[80];
+ char rcbits[80];
+ char rdbits[80];
+ char tmp[1024];
+
+ int use = 0;
+
+ memset(tabits,0, sizeof(tabits));
+ memset(tbbits,0, sizeof(tbbits));
+ memset(rabits,0, sizeof(rabits));
+ memset(rbbits,0, sizeof(rbbits));
+ memset(tcbits,0, sizeof(tcbits));
+ memset(tdbits,0, sizeof(tdbits));
+ memset(rcbits,0, sizeof(rcbits));
+ memset(rdbits,0, sizeof(rdbits));
+ memset(tabits,32, span_max_chan_pos);
+ memset(tbbits,32, span_max_chan_pos);
+ memset(rabits,32, span_max_chan_pos);
+ memset(rbbits,32, span_max_chan_pos);
+ memset(tcbits,32, span_max_chan_pos);
+ memset(tdbits,32, span_max_chan_pos);
+ memset(rcbits,32, span_max_chan_pos);
+ memset(rdbits,32, span_max_chan_pos);
+
+ for (x=0;x<ZT_MAX_CHANNELS;x++) {
+ memset(&zp, 0, sizeof(zp));
+ zp.channo = x;
+ res = ioctl(ctl, ZT_GET_PARAMS, &zp);
+ if (!res) {
+ if (zp.spanno == span) {
+ if (zp.sigtype && (zp.rxbits > -1)) {
+ if (zp.rxbits & ZT_ABIT)
+ rabits[zp.chanpos - 1] = '1';
+ else
+ rabits[zp.chanpos - 1] = '0';
+ if (zp.rxbits & ZT_BBIT)
+ rbbits[zp.chanpos - 1] = '1';
+ else
+ rbbits[zp.chanpos - 1] = '0';
+
+ if (zp.rxbits & ZT_CBIT)
+ rcbits[zp.chanpos - 1] = '1';
+ else
+ rcbits[zp.chanpos - 1] = '0';
+ if (zp.rxbits & ZT_DBIT)
+ rdbits[zp.chanpos - 1] = '1';
+ else
+ rdbits[zp.chanpos - 1] = '0';
+
+ if (zp.txbits & ZT_ABIT)
+ tabits[zp.chanpos - 1] = '1';
+ else
+ tabits[zp.chanpos - 1] = '0';
+ if (zp.txbits & ZT_BBIT)
+ tbbits[zp.chanpos - 1] = '1';
+ else
+ tbbits[zp.chanpos - 1] = '0';
+ if (zp.txbits & ZT_CBIT)
+ tcbits[zp.chanpos - 1] = '1';
+ else
+ tcbits[zp.chanpos - 1] = '0';
+ if (zp.txbits & ZT_DBIT)
+ tdbits[zp.chanpos - 1] = '1';
+ else
+ tdbits[zp.chanpos - 1] = '0';
+ } else {
+ c = '-';
+ if (!zp.sigtype)
+ c = ' ';
+ tabits[zp.chanpos - 1] = c;
+ tbbits[zp.chanpos - 1] = c;
+ tcbits[zp.chanpos - 1] = c;
+ tdbits[zp.chanpos - 1] = c;
+ rabits[zp.chanpos - 1] = c;
+ rbbits[zp.chanpos - 1] = c;
+ rcbits[zp.chanpos - 1] = c;
+ rdbits[zp.chanpos - 1] = c;
+ }
+ if (zp.rxisoffhook)
+ use++;
+ }
+ }
+ }
+ snprintf(tmp, sizeof(tmp), "%s\n%s\n%s\n%s\n\n%s\n%s\n%s\n%s", tabits, tbbits,tcbits,tdbits,rabits,rbbits,rcbits,rdbits);
+ newtTextboxSetText(bitbox, tmp);
+ sprintf(tmp, "%3d/%3d/%3d", s[span].totalchans, s[span].numchans, use);
+ newtTextboxSetText(inuse, tmp);
+ sprintf(tmp, "%s/", zt_txlevelnames[s[span].txlevel]);
+ strcat(tmp, zt_txlevelnames[s[span].rxlevel]);
+ sprintf(tmp, "%3d/%3d", s[span].txlevel, s[span].rxlevel);
+ newtTextboxSetText(levels, tmp);
+ sprintf(tmp, "%7d", s[span].bpvcount);
+ newtTextboxSetText(bpvcount, tmp);
+ sprintf(tmp, "%7d", s[span].irqmisses);
+ newtTextboxSetText(irqmisses, tmp);
+ newtTextboxSetText(alarms, alarmstr(span));
+ if (s[span].syncsrc > 0)
+ strcpy(tmp, s[s[span].syncsrc].desc);
+ else
+ strcpy(tmp, "Internally clocked");
+ newtTextboxSetText(syncsrc, tmp);
+
+
+}
+
+static void do_loop(int span, int looped)
+{
+ newtComponent form;
+ newtComponent label;
+ char s1[256];
+ struct zt_maintinfo m;
+ int res;
+ struct newtExitStruct es;
+
+ newtOpenWindow(20,12,40,4, s[span].desc);
+
+ form = newtForm(NULL, NULL, 0);
+ m.spanno = span;
+ if (looped) {
+ snprintf(s1, sizeof(s1), "Looping UP span %d...\n", span);
+ m.command = ZT_MAINT_LOOPUP;
+ } else {
+ snprintf(s1, sizeof(s1), "Looping DOWN span %d...\n", span);
+ m.command = ZT_MAINT_LOOPDOWN;
+ }
+
+ label = newtLabel(3,1,s1);
+ newtFormAddComponent(form, label);
+ newtPushHelpLine("Please wait...");
+
+ newtFormSetTimer(form, 200);
+ newtFormRun(form, &es);
+ res = ioctl(ctl, ZT_MAINT, &m);
+ newtFormDestroy(form);
+ newtPopWindow();
+ newtPopHelpLine();
+}
+
+static newtComponent spans;
+static void show_span(int span)
+{
+ newtComponent form;
+ newtComponent back;
+ newtComponent loop;
+ newtComponent label;
+ newtComponent bitbox;
+ newtComponent inuse;
+ newtComponent levels;
+ newtComponent bpvcount;
+ newtComponent alarms;
+ newtComponent syncsrc;
+ newtComponent irqmisses;
+
+ char s1[] = " 1111111111222222222233";
+ char s2[] = "1234567890123456789012345678901";
+ int x;
+ int looped = 0;
+ struct newtExitStruct es;
+
+ void *ss;
+ char info2[256];
+
+ if (span < 0) {
+ /* Display info on a span */
+ ss = newtListboxGetCurrent(spans);
+ if (ss) {
+ span = (long)(ss);
+ }
+ }
+
+ snprintf(info2, sizeof(info2), "%-59s F10=Back", s[span].desc);
+ newtOpenWindow(10,2,60,20, s[span].desc);
+ newtPushHelpLine(info2);
+
+ back = newtButton(48,8,"Back");
+ loop = newtButton(48,14,"Loop");
+ form = newtForm(NULL, NULL, 0);
+
+ newtFormAddComponents(form, back, loop, NULL);
+
+ span_max_chan_pos = s[span].totalchans;
+ for (x=0;x<ZT_MAX_CHANNELS;x++) {
+ ZT_PARAMS zp;
+ int res;
+ memset(&zp, 0, sizeof(zp));
+ zp.channo = x;
+ res = ioctl(ctl, ZT_GET_PARAMS, &zp);
+ if (!res && zp.spanno == span && zp.chanpos > span_max_chan_pos )
+ span_max_chan_pos = zp.chanpos;
+ }
+
+ if (span_max_chan_pos > 32)
+ span_max_chan_pos = 32;
+
+ s1[span_max_chan_pos] = '\0';
+ s2[span_max_chan_pos] = '\0';
+
+ bitbox = newtTextbox(8,10,span_max_chan_pos,9,0);
+ newtFormAddComponent(form, bitbox);
+
+ label = newtLabel(8,8,s1);
+ newtFormAddComponent(form, label);
+
+ label = newtLabel(8,9,s2);
+ newtFormAddComponent(form, label);
+
+ newtFormAddHotKey(form, NEWT_KEY_F10);
+ newtFormSetTimer(form, 200);
+
+ label = newtLabel(4,10,"TxA");
+ newtFormAddComponent(form, label);
+
+ label = newtLabel(4,11,"TxB");
+ newtFormAddComponent(form, label);
+
+ label = newtLabel(4,12,"TxC");
+ newtFormAddComponent(form, label);
+
+ label = newtLabel(4,13,"TxD");
+ newtFormAddComponent(form, label);
+
+ label = newtLabel(4,15,"RxA");
+ newtFormAddComponent(form, label);
+
+ label = newtLabel(4,16,"RxB");
+ newtFormAddComponent(form, label);
+
+ label = newtLabel(4,17,"RxC");
+ newtFormAddComponent(form, label);
+
+ label = newtLabel(4,18,"RxD");
+ newtFormAddComponent(form, label);
+
+
+ label = newtLabel(4,7,"Total/Conf/Act: ");
+ newtFormAddComponent(form, label);
+
+ inuse = newtTextbox(24,7,12,1,0);
+ newtFormAddComponent(form, inuse);
+
+ label = newtLabel(4,6,"Tx/Rx Levels: ");
+ newtFormAddComponent(form, label);
+
+ levels = newtTextbox(24,6,30,1,0);
+ newtFormAddComponent(form, levels);
+
+ label = newtLabel(4,5,"Bipolar Viol: ");
+ newtFormAddComponent(form, label);
+
+ bpvcount = newtTextbox(24,5,30,1,0);
+ newtFormAddComponent(form, bpvcount);
+
+ label = newtLabel(4,4,"IRQ Misses: ");
+ newtFormAddComponent(form, label);
+
+ irqmisses = newtTextbox(24,4,30,1,0);
+ newtFormAddComponent(form, irqmisses);
+
+ label = newtLabel(4,3,"Sync Source: ");
+ newtFormAddComponent(form, label);
+
+ syncsrc = newtTextbox(24,3,30,1,0);
+ newtFormAddComponent(form, syncsrc);
+
+ label = newtLabel(4,2,"Current Alarms: ");
+ newtFormAddComponent(form, label);
+
+ alarms = newtTextbox(24,2,30,1,0);
+ newtFormAddComponent(form, alarms);
+
+ for(;;) {
+ /* Wait for user to select something */
+ do {
+ add_cards(NULL);
+ show_bits(span, bitbox, inuse, levels, bpvcount, alarms, syncsrc, irqmisses);
+ newtFormRun(form, &es);
+ } while(es.reason == NEWT_EXIT_TIMER);
+ switch(es.reason) {
+ case NEWT_EXIT_COMPONENT:
+ if (es.u.co == loop) {
+ looped = !looped;
+ do_loop(span, looped);
+ newtFormSetTimer(form, 200);
+ }
+ if (es.u.co == back) {
+ goto out;
+ }
+ break;
+ case NEWT_EXIT_HOTKEY:
+ switch(es.u.key) {
+#if 0
+ case NEWT_KEY_F1:
+ show_span(-1);
+ break;
+#endif
+ case NEWT_KEY_F10:
+ goto out;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+out:
+ newtFormDestroy(form);
+ newtPopWindow();
+ newtPopHelpLine();
+ span_max_chan_pos = 0;
+}
+
+static void show_spans(void)
+{
+ newtComponent form;
+ newtComponent quit;
+ newtComponent label;
+ newtComponent sel;
+
+
+ struct newtExitStruct es;
+
+
+ quit = newtButton(50,14,"Quit");
+ sel = newtButton(10,14,"Select");
+
+ spans = newtListbox(5, 2, 10, NEWT_FLAG_SCROLL);
+ newtListboxSetWidth(spans, 65);
+
+ label = newtLabel(5,1,"Alarms Span");
+
+ newtCenteredWindow(72,18, "Zapata Telephony Interfaces");
+ form = newtForm(NULL, NULL, 0);
+
+ newtFormSetTimer(form, 200);
+
+ newtFormAddComponents(form, spans, sel, quit, label, NULL);
+
+ newtComponentAddCallback(spans, sel_callback, NULL);
+
+ newtFormAddHotKey(form, NEWT_KEY_F1);
+ newtFormAddHotKey(form, NEWT_KEY_F10);
+
+ for(;;) {
+ /* Wait for user to select something */
+ do {
+ add_cards(spans);
+ newtFormRun(form, &es);
+ } while(es.reason == NEWT_EXIT_TIMER);
+
+ switch(es.reason) {
+ case NEWT_EXIT_COMPONENT:
+ if (es.u.co == quit) {
+ /* Quit if appropriate */
+ newtFormDestroy(form);
+ return;
+ } else if (es.u.co == sel) {
+ show_span(-1);
+ }
+ break;
+ case NEWT_EXIT_HOTKEY:
+ switch(es.u.key) {
+ case NEWT_KEY_F1:
+ show_span(-1);
+ break;
+ case NEWT_KEY_F10:
+ newtFormDestroy(form);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void cleanup(void)
+{
+ newtPopWindow();
+}
+
+int main(int argc, char *argv[])
+{
+
+ ctl = open("/dev/zap/ctl", O_RDWR);
+ if (ctl < 0) {
+ fprintf(stderr, "Unable to open /dev/zap/ctl: %s\n", strerror(errno));
+ exit(1);
+ }
+ newtInit();
+ newtCls();
+
+ newtDrawRootText(0,0,"Zaptel Tool (C)2002 Linux Support Services, Inc.");
+ newtPushHelpLine("Welcome to the Zaptel Tool!");
+ show_spans();
+ cleanup();
+ newtFinished();
+ return 0;
+}
diff --git a/fxotune.c b/fxotune.c
new file mode 100644
index 0000000..d7ee9ca
--- /dev/null
+++ b/fxotune.c
@@ -0,0 +1,1110 @@
+/*
+ * This file and contents thereof are licensed under the terms and
+ * conditions of the GNU Public License version 2. For more information
+ * (including terms and conditions) see http://www.gnu.org/
+ *
+ * fxotune.c -- A utility for tuning the various settings on the fxo
+ * modules for the TDM400 cards.
+ *
+ * by Matthew Fredrickson <creslin@digium.com>
+ *
+ * (C) 2004-2005 Digium, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <sys/time.h>
+
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+#include "kernel/wctdm.h"
+#include "fxotune.h"
+
+#define TEST_DURATION 2000
+#define BUFFER_LENGTH (2 * TEST_DURATION)
+#define SKIP_SAMPLES 800
+
+static const float amplitude = 16384.0;
+
+static char *zappath = "/dev/zap";
+static char *configfile = "/etc/fxotune.conf";
+
+static int audio_dump_fd = -1;
+
+static char *usage =
+"Usage: fxotune [-v[vv] (-s | -i <options> | -d <options>)\n"
+"\n"
+" -s : set previously calibrated echo settings\n"
+" -i : calibrate echo settings\n"
+" options : [<dialstring>] [-t <calibtype>]\n"
+" [-b <startdev>][-e <stopdev>]\n"
+" [-n <dialstring>][-l <delaytosilence>][-m <silencegoodfor>]\n"
+" -d : dump input and output waveforms to ./fxotune_dump.vals\n"
+" options : [-b <device>][-w <waveform>]\n"
+" [-n <dialstring>][-l <delaytosilence>][-m <silencegoodfor>]\n"
+" -v : more output (-vv, -vvv also)\n"
+" -o <path> : Write the received raw 16-bit signed linear audio that is\n"
+" used in processing to the file specified by <path>\n"
+" -c <config_file>\n"
+"\n"
+" <calibtype> - type of calibration\n"
+" (default 2, old method 1)\n"
+" <startdev>\n"
+" <stopdev> - defines a range of devices to test\n"
+" (default: 1-252)\n"
+" <dialstring> - string to dial to clear the line\n"
+" (default 5)\n"
+" <delaytosilence> - seconds to wait for line to clear (default 0)\n"
+" <silencegoodfor> - seconds before line will no longer be clear\n"
+" (default 18)\n"
+" <device> - the device to perform waveform dump on\n"
+" (default 1)\n"
+" <waveform> - -1 for multitone waveform, or frequency of\n"
+" single tone (default -1)\n"
+" <config_file> - Alternative file to set from / calibrate to.\n"
+" (Default: /etc/fxotune.conf)\n"
+;
+
+
+#define OUT_OF_BOUNDS(x) ((x) < 0 || (x) > 255)
+
+struct silence_info{
+ char *dialstr;
+ /** fd of device we are working with */
+ int device;
+ /** seconds we should wait after dialing the dialstring before we know for sure we'll have silence */
+ int initial_delay;
+ /** seconds after which a reset should occur */
+ int reset_after;
+ /** time of last reset */
+ struct timeval last_reset;
+};
+
+static short outbuf[TEST_DURATION];
+static int debug = 0;
+
+static FILE *debugoutfile = NULL;
+
+static int fxotune_read(int fd, void *buffer, int len)
+{
+ int res;
+
+ res = read(fd, buffer, len);
+
+ if ((res > 0) && (audio_dump_fd != -1)) {
+ write(audio_dump_fd, buffer, len);
+ }
+
+ return res;
+}
+
+/**
+ * Makes sure that the line is clear.
+ * Right now, we do this by relying on the user to specify how long after dialing the
+ * dialstring we can rely on the line being silent (before the telco complains about
+ * the user not hitting the next digit).
+ *
+ * A more robust way to do this would be to actually measure the sound levels on the line,
+ * but that's a lot more complicated, and this should work.
+ *
+ * @return 0 if succesful (no errors), 1 if unsuccesful
+ */
+static int ensure_silence(struct silence_info *info)
+{
+ struct timeval tv;
+ long int elapsedms;
+
+ gettimeofday(&tv, NULL);
+
+ if (info->last_reset.tv_sec == 0) {
+ /* this is the first request, we will force it to run */
+ elapsedms = -1;
+ } else {
+ /* this is not the first request, we will compute elapsed time */
+ elapsedms = ((tv.tv_sec - info->last_reset.tv_sec) * 1000L + (tv.tv_usec - info->last_reset.tv_usec) / 1000L);
+ }
+ if (debug > 4) {
+ fprintf(stdout, "Reset line request received - elapsed ms = %li / reset after = %ld\n", elapsedms, info->reset_after * 1000L);
+ }
+
+ if (elapsedms > 0 && elapsedms < info->reset_after * 1000L)
+ return 0;
+
+ if (debug > 1){
+ fprintf(stdout, "Resetting line\n");
+ }
+
+ /* do a line reset */
+ /* prepare line for silence */
+ /* Do line hookstate reset */
+ int x = ZT_ONHOOK;
+
+ if (ioctl(info->device, ZT_HOOK, &x)) {
+ fprintf(stderr, "Unable to hang up fd %d\n", info->device);
+ return -1;
+ }
+
+ sleep(2);
+ x = ZT_OFFHOOK;
+ if (ioctl(info->device, ZT_HOOK, &x)) {
+ fprintf(stderr, "Cannot bring fd %d off hook\n", info->device);
+ return -1;
+ }
+ sleep(2); /* Added to ensure that dial can actually takes place */
+
+ struct zt_dialoperation dop;
+ memset(&dop, 0, sizeof(dop));
+ dop.op = ZT_DIAL_OP_REPLACE;
+ dop.dialstr[0] = 'T';
+ zap_copy_string(dop.dialstr + 1, info->dialstr, sizeof(dop.dialstr));
+
+
+ if (ioctl(info->device, ZT_DIAL, &dop)) {
+ fprintf(stderr, "Unable to dial!\n");
+ return -1;
+ }
+ sleep(1);
+ sleep(info->initial_delay);
+
+
+ gettimeofday(&info->last_reset, NULL);
+
+
+ return 0;
+}
+
+/**
+ * Generates a tone of specified frequency.
+ *
+ * @param hz the frequency of the tone to be generated
+ * @param index the current sample
+ * to begenerated. For a normal waveform you need to increment
+ * this every time you execute the function.
+ *
+ * @return 16bit slinear sample for the specified index
+ */
+static short inline gentone(int hz, int index)
+{
+ return amplitude * sin((index * 2.0 * M_PI * hz)/8000);
+}
+
+/* Using DTMF tones for now since they provide good mid band testing
+ * while not being harmonics of each other */
+static int freqs[] = {697, 770, 941, 1209, 1336, 1633};
+static int freqcount = 6;
+
+/**
+ * Generates a waveform of several frequencies.
+ *
+ * @param index the current sample
+ * to begenerated. For a normal waveform you need to increment
+ * this every time you execute the function.
+ *
+ * @return 16bit slinear sample for the specified index
+ */
+static short inline genwaveform(int index)
+{
+ int i = 0;
+ float response = (float)0;
+ for (i = 0; i < freqcount; i++){
+ response += sin((index * 2.0 * M_PI * freqs[i])/8000);
+ }
+
+
+ return amplitude * response / freqcount;
+}
+
+
+/**
+ * Calculates the RMS of the waveform buffer of samples in 16bit slinear format.
+ * prebuf the buffer of either shorts or floats
+ * bufsize the number of elements in the prebuf buffer (not the number of bytes!)
+ * short_format 1 if prebuf points to an array of shorts, 0 if it points to an array of floats
+ *
+ * Formula for RMS (http://en.wikipedia.org/wiki/Root_mean_square):
+ *
+ * Xrms = sqrt(1/N Sum(x1^2, x2^2, ..., xn^2))
+ *
+ * Note: this isn't really a power calculation - but it gives a good measure of the level of the response
+ *
+ * @param prebuf the buffer containing the values to compute
+ * @param bufsize the size of the buffer
+ * @param short_format 1 if prebuf contains short values, 0 if it contains float values
+ */
+static float power_of(void *prebuf, int bufsize, int short_format)
+{
+ float sum_of_squares = 0;
+ int numsamples = 0;
+ float finalanswer = 0;
+ short *sbuf = (short*)prebuf;
+ float *fbuf = (float*)prebuf;
+ int i = 0;
+
+ if (short_format) {
+ /* idiot proof checks */
+ if (bufsize <= 0)
+ return -1;
+
+ numsamples = bufsize; /* Got rid of divide by 2 - the bufsize parameter should give the number of samples (that's what it does for the float computation, and it should do it here as well) */
+
+ for (i = 0; i < numsamples; i++) {
+ sum_of_squares += ((float)sbuf[i] * (float)sbuf[i]);
+ }
+ } else {
+ /* Version for float inputs */
+ for (i = 0; i < bufsize; i++) {
+ sum_of_squares += (fbuf[i] * fbuf[i]);
+ }
+ }
+
+ finalanswer = sum_of_squares/(float)bufsize; /* need to divide by the number of elements in the sample for RMS calc */
+
+ if (finalanswer < 0) {
+ printf("Error: Final answer negative number %f\n", finalanswer);
+ return -3;
+ }
+
+ return sqrtf(finalanswer);
+}
+
+/*
+ * In an effort to eliminate as much as possible the effect of outside noise, we use principles
+ * from the Fourier Transform to attempt to calculate the return loss of our signal for each setting.
+ *
+ * To begin, we send our output signal out on the line. We then receive back the reflected
+ * response. In the Fourier Transform, each evenly distributed frequency within the window
+ * is correlated (multiplied against, then the resulting samples are added together) with
+ * the real (cos) and imaginary (sin) portions of that frequency base to detect that frequency.
+ *
+ * Instead of doing a complete Fourier Transform, we solve the transform for only our signal
+ * by multiplying the received signal by the real and imaginary portions of our reference
+ * signal. This then gives us the real and imaginary values that we can use to calculate
+ * the return loss of the sinusoids that we sent out on the line. This is done by finding
+ * the magnitude (think polar form) of the vector resulting from the real and imaginary
+ * portions calculated above.
+ *
+ * This essentially filters out any other noise which maybe present on the line which is outside
+ * the frequencies used in our test multi-tone.
+ */
+static float db_loss(float measured, float reference)
+{
+ return 20 * (logf(measured/reference)/logf(10));
+}
+
+static void one_point_dft(const short *inbuf, int len, int frequency, float *real, float *imaginary)
+{
+ float myreal = 0, myimag = 0;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ myreal += (float) inbuf[i] * cos((i * 2.0 * M_PI * frequency)/8000);
+ myimag += (float) inbuf[i] * sin((i * 2.0 * M_PI * frequency)/8000);
+ }
+
+ myimag *= -1;
+
+ *real = myreal / (float) len;
+ *imaginary = myimag / (float) len;
+}
+
+static float calc_magnitude(short *inbuf, int insamps)
+{
+ float real, imaginary, magnitude;
+ float totalmagnitude = 0;
+ int i;
+
+ for (i = 0; i < freqcount; i++) {
+ one_point_dft(inbuf, insamps, freqs[i], &real, &imaginary);
+ magnitude = sqrtf((real * real) + (imaginary * imaginary));
+ totalmagnitude += magnitude;
+ }
+
+ return totalmagnitude;
+}
+
+/**
+ * dumps input and output buffer contents for the echo test - used to see exactly what's going on
+ */
+static int maptone(int whichzap, int freq, char *dialstr, int delayuntilsilence)
+{
+ int i = 0;
+ int res = 0, x = 0;
+ struct zt_bufferinfo bi;
+ short inbuf[TEST_DURATION]; /* changed from BUFFER_LENGTH - this buffer is for short values, so it should be allocated using the length of the test */
+ FILE *outfile = NULL;
+
+ outfile = fopen("fxotune_dump.vals", "w");
+ if (!outfile) {
+ fprintf(stdout, "Cannot create fxotune_dump.vals\n");
+ return -1;
+ }
+
+ x = 1;
+ if (ioctl(whichzap, ZT_SETLINEAR, &x)) {
+ fprintf(stderr, "Unable to set channel to signed linear mode.\n");
+ return -1;
+ }
+
+ memset(&bi, 0, sizeof(bi));
+ if (ioctl(whichzap, ZT_GET_BUFINFO, &bi)) {
+ fprintf(stderr, "Unable to get buffer information!\n");
+ return -1;
+ }
+ bi.numbufs = 2;
+ bi.bufsize = TEST_DURATION; /* KD - changed from BUFFER_LENGTH; */
+ bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
+ if (ioctl(whichzap, ZT_SET_BUFINFO, &bi)) {
+ fprintf(stderr, "Unable to set buffer information!\n");
+ return -1;
+ }
+
+ /* Fill the output buffers */
+ int leadin = 50;
+ int trailout = 100;
+ for (i = 0; i < leadin; i++)
+ outbuf[i] = 0;
+ for (; i < TEST_DURATION - trailout; i++){
+ outbuf[i] = freq > 0 ? gentone(freq, i) : genwaveform(i); /* if frequency is negative, use a multi-part waveform instead of a single frequency */
+ }
+ for (; i < TEST_DURATION; i++)
+ outbuf[i] = 0;
+
+ /* Make sure the line is clear */
+ struct silence_info sinfo;
+ memset(&sinfo, 0, sizeof(sinfo));
+ sinfo.device = whichzap;
+ sinfo.dialstr = dialstr;
+ sinfo.initial_delay = delayuntilsilence;
+ sinfo.reset_after = 4; /* doesn't matter - we are only running one test */
+
+ if (ensure_silence(&sinfo)){
+ fprintf(stderr, "Unable to get a clear outside line\n");
+ return -1;
+ }
+
+ /* Flush buffers */
+ x = ZT_FLUSH_READ | ZT_FLUSH_WRITE | ZT_FLUSH_EVENT;
+ if (ioctl(whichzap, ZT_FLUSH, &x)) {
+ fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* send data out on line */
+ res = write(whichzap, outbuf, BUFFER_LENGTH); /* we are sending a TEST_DURATION length array of shorts (which are 2 bytes each) */
+ if (res != BUFFER_LENGTH) {
+ fprintf(stderr, "Could not write all data to line\n");
+ return -1;
+ }
+
+retry:
+ /* read return response */
+ res = fxotune_read(whichzap, inbuf, BUFFER_LENGTH);
+ if (res != BUFFER_LENGTH) {
+ int x;
+
+ ioctl(whichzap, ZT_GETEVENT, &x);
+ goto retry;
+ }
+
+ /* write content of output buffer to debug file */
+ float power_result = power_of(inbuf, TEST_DURATION, 1);
+ float power_waveform = power_of(outbuf, TEST_DURATION, 1);
+ float echo = power_result/power_waveform;
+
+ fprintf(outfile, "Buffers, freq=%d, outpower=%0.0f, echo=%0.4f\n", freq, power_result, echo);
+ fprintf(outfile, "Sample, Input (received from the line), Output (sent to the line)\n");
+ for (i = 0; i < TEST_DURATION; i++){
+ fprintf(outfile, "%d, %d, %d\n",
+ i,
+ inbuf[i],
+ outbuf[i]
+ );
+ }
+
+ fclose(outfile);
+
+ fprintf(stdout, "echo ratio = %0.4f (%0.1f / %0.1f)\n", echo, power_result, power_waveform);
+
+ return 0;
+}
+
+
+
+/**
+ * Perform calibration type 2 on the specified device
+ *
+ * Determine optimum echo coefficients for the specified device
+ *
+ * New tuning strategy. If we have a number that we can dial that will result in silence from the
+ * switch, the tune will be *much* faster (we don't have to keep hanging up and dialing a digit, etc...)
+ * The downside is that the user needs to actually find a 'no tone' phone number at their CO's switch - but for
+ * really fixing echo problems, this is what it takes.
+ *
+ * Also, for the purposes of optimizing settings, if we pick a single frequency and test with that,
+ * we can try a whole bunch of impedence/echo coefficients. This should give better results than trying
+ * a bunch of frequencies, and we can always do a a frequency sweep to pick between the best 3 or 4
+ * impedence/coefficients configurations.
+ *
+ * Note: It may be possible to take this even further and do some pertubation analysis on the echo coefficients
+ * themselves (maybe use the 72 entry sweep to find some settings that are close to working well, then
+ * deviate the coefficients a bit to see if we can improve things). A better way to do this would be to
+ * use the optimization strategy from silabs. For reference, here is an application note that describes
+ * the echo coefficients (and acim values):
+ *
+ * http://www.silabs.com/public/documents/tpub_doc/anote/Wireline/Silicon_DAA/en/an84.pdf
+ *
+ */
+static int acim_tune2(int whichzap, int freq, char *dialstr, int delayuntilsilence, int silencegoodfor, struct wctdm_echo_coefs *coefs_out)
+{
+ int i = 0;
+ int res = 0, x = 0;
+ int lowesttry = -1;
+ float lowesttryresult = 999999999999.0;
+ float lowestecho = 999999999999.0;;
+ struct zt_bufferinfo bi;
+
+ short inbuf[TEST_DURATION * 2];
+
+ if (debug && !debugoutfile) {
+ if (!(debugoutfile = fopen("fxotune.vals", "w"))) {
+ fprintf(stdout, "Cannot create fxotune.vals\n");
+ return -1;
+ }
+ }
+
+ /* Set echo settings */
+ if (ioctl(whichzap, WCTDM_SET_ECHOTUNE, &echo_trys[0])) {
+ fprintf(stderr, "Unable to set impedance on fd %d\n", whichzap);
+ return -1;
+ }
+
+ x = 1;
+ if (ioctl(whichzap, ZT_SETLINEAR, &x)) {
+ fprintf(stderr, "Unable to set channel to signed linear mode.\n");
+ return -1;
+ }
+
+ memset(&bi, 0, sizeof(bi));
+ if (ioctl(whichzap, ZT_GET_BUFINFO, &bi)) {
+ fprintf(stderr, "Unable to get buffer information!\n");
+ return -1;
+ }
+ bi.numbufs = 2;
+ bi.bufsize = BUFFER_LENGTH;
+ bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
+ if (ioctl(whichzap, ZT_SET_BUFINFO, &bi)) {
+ fprintf(stderr, "Unable to set buffer information!\n");
+ return -1;
+ }
+ x = ZT_OFFHOOK;
+ if (ioctl(whichzap, ZT_HOOK, &x)) {
+ fprintf(stderr, "Cannot bring fd %d off hook", whichzap);
+ return -1;
+ }
+
+
+ /* Set up silence settings */
+ struct silence_info sinfo;
+ memset(&sinfo, 0, sizeof(sinfo));
+ sinfo.device = whichzap;
+ sinfo.dialstr = dialstr;
+ sinfo.initial_delay = delayuntilsilence;
+ sinfo.reset_after = silencegoodfor;
+
+ /* Fill the output buffers */
+ for (i = 0; i < TEST_DURATION; i++)
+ outbuf[i] = freq > 0 ? gentone(freq, i) : genwaveform(i); /* if freq is negative, use a multi-frequency waveform */
+
+ /* compute power of input (so we can later compute echo levels relative to input) */
+ float waveform_power = calc_magnitude(outbuf, TEST_DURATION);
+
+
+ /* sweep through the various coefficient settings and see how our responses look */
+
+ int echo_trys_size = 72;
+ int trys = 0;
+ for (trys = 0; trys < echo_trys_size; trys++){
+
+ /* ensure silence on the line */
+ if (ensure_silence(&sinfo)){
+ fprintf(stderr, "Unable to get a clear outside line\n");
+ return -1;
+ }
+
+ if (ioctl(whichzap, WCTDM_SET_ECHOTUNE, &echo_trys[trys])) {
+ fprintf(stderr, "Unable to set echo coefficients on fd %d\n", whichzap);
+ return -1;
+ }
+
+ /* Flush buffers */
+ x = ZT_FLUSH_READ | ZT_FLUSH_WRITE | ZT_FLUSH_EVENT;
+ if (ioctl(whichzap, ZT_FLUSH, &x)) {
+ fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* send data out on line */
+ res = write(whichzap, outbuf, BUFFER_LENGTH);
+ if (res != BUFFER_LENGTH) {
+ fprintf(stderr, "Could not write all data to line\n");
+ return -1;
+ }
+
+retry:
+ /* read return response */
+ res = fxotune_read(whichzap, inbuf, BUFFER_LENGTH * 2);
+ if (res != BUFFER_LENGTH * 2) {
+ int x;
+
+ ioctl(whichzap, ZT_GETEVENT, &x);
+ goto retry;
+ }
+
+ float freq_result = calc_magnitude(inbuf, TEST_DURATION * 2);
+ float echo = db_loss(freq_result, waveform_power);
+
+#if 0
+ if (debug > 0)
+ fprintf(stdout, "%3d,%d,%d,%d,%d,%d,%d,%d,%d: magnitude = %0.0f, echo = %0.4f dB\n",
+ echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2,
+ echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5,
+ echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8,
+ freq_result, echo);
+#endif
+
+ if (freq_result < lowesttryresult){
+ lowesttry = trys;
+ lowesttryresult = freq_result;
+ lowestecho = echo;
+ }
+ if (debug) {
+ char result[256];
+ snprintf(result, sizeof(result), "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%f,%f",
+ echo_trys[trys].acim,
+ echo_trys[trys].coef1,
+ echo_trys[trys].coef2,
+ echo_trys[trys].coef3,
+ echo_trys[trys].coef4,
+ echo_trys[trys].coef5,
+ echo_trys[trys].coef6,
+ echo_trys[trys].coef7,
+ echo_trys[trys].coef8,
+ freq_result,
+ echo
+ );
+
+ fprintf(debugoutfile, "%s\n", result);
+ fprintf(stdout, "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n",
+ echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2,
+ echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5,
+ echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8,
+ freq_result, echo);
+ }
+ }
+
+ if (debug > 0)
+ fprintf(stdout, "Config with lowest response = %d, magnitude = %0.0f, echo = %0.4f dB\n", lowesttry, lowesttryresult, lowestecho);
+
+ memcpy(coefs_out, &echo_trys[lowesttry], sizeof(struct wctdm_echo_coefs));
+
+ return 0;
+}
+
+/**
+ * Perform calibration type 1 on the specified device. Only tunes the line impedance. Look for best response range
+ */
+static int acim_tune(int whichzap, char *dialstr, int delayuntilsilence, int silencegoodfor, struct wctdm_echo_coefs *coefs_out)
+{
+ int i = 0, freq = 0, acim = 0;
+ int res = 0, x = 0;
+ struct zt_bufferinfo bi;
+ struct wctdm_echo_coefs coefs;
+ short inbuf[TEST_DURATION]; /* changed from BUFFER_LENGTH - this buffer is for short values, so it should be allocated using the length of the test */
+ int lowest = 0;
+ FILE *outfile = NULL;
+ float acim_results[16];
+
+
+ if (debug) {
+ outfile = fopen("fxotune.vals", "w");
+ if (!outfile) {
+ fprintf(stdout, "Cannot create fxotune.vals\n");
+ return -1;
+ }
+ }
+
+ /* Set up silence settings */
+ struct silence_info sinfo;
+ memset(&sinfo, 0, sizeof(sinfo));
+ sinfo.device = whichzap;
+ sinfo.dialstr = dialstr;
+ sinfo.initial_delay = delayuntilsilence;
+ sinfo.reset_after = silencegoodfor;
+
+ /* Set echo settings */
+ memset(&coefs, 0, sizeof(coefs));
+ if (ioctl(whichzap, WCTDM_SET_ECHOTUNE, &coefs)) {
+ fprintf(stdout, "Skipping non-TDM / non-FXO\n");
+ return -1;
+ }
+
+ x = 1;
+ if (ioctl(whichzap, ZT_SETLINEAR, &x)) {
+ fprintf(stderr, "Unable to set channel to signed linear mode.\n");
+ return -1;
+ }
+
+ memset(&bi, 0, sizeof(bi));
+ if (ioctl(whichzap, ZT_GET_BUFINFO, &bi)) {
+ fprintf(stderr, "Unable to get buffer information!\n");
+ return -1;
+ }
+ bi.numbufs = 2;
+ bi.bufsize = BUFFER_LENGTH;
+ bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
+ if (ioctl(whichzap, ZT_SET_BUFINFO, &bi)) {
+ fprintf(stderr, "Unable to set buffer information!\n");
+ return -1;
+ }
+
+ for (acim = 0; acim < 16; acim++) {
+ float freq_results[15];
+
+ coefs.acim = acim;
+ if (ioctl(whichzap, WCTDM_SET_ECHOTUNE, &coefs)) {
+ fprintf(stderr, "Unable to set impedance on fd %d\n", whichzap);
+ return -1;
+ }
+
+ for (freq = 200; freq <=3000; freq+=200) {
+ /* Fill the output buffers */
+ for (i = 0; i < TEST_DURATION; i++)
+ outbuf[i] = gentone(freq, i);
+
+ /* Make sure line is ready for next test iteration */
+ if (ensure_silence(&sinfo)){
+ fprintf(stderr, "Unable to get a clear line\n");
+ return -1;
+ }
+
+
+ /* Flush buffers */
+ x = ZT_FLUSH_READ | ZT_FLUSH_WRITE | ZT_FLUSH_EVENT;
+ if (ioctl(whichzap, ZT_FLUSH, &x)) {
+ fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* send data out on line */
+ res = write(whichzap, outbuf, BUFFER_LENGTH);
+ if (res != BUFFER_LENGTH) {
+ fprintf(stderr, "Could not write all data to line\n");
+ return -1;
+ }
+
+ /* read return response */
+retry:
+ /* read return response */
+ res = fxotune_read(whichzap, inbuf, BUFFER_LENGTH);
+ if (res != BUFFER_LENGTH) {
+ int x;
+
+ ioctl(whichzap, ZT_GETEVENT, &x);
+ goto retry;
+ }
+
+ /* calculate power of response */
+
+ freq_results[(freq/200)-1] = power_of(inbuf+SKIP_SAMPLES, TEST_DURATION-SKIP_SAMPLES, 1); /* changed from inbuf+SKIP_BYTES, BUFFER_LENGTH-SKIP_BYTES, 1 */
+ if (debug) fprintf(outfile, "%d,%d,%f\n", acim, freq, freq_results[(freq/200)-1]);
+ }
+ acim_results[acim] = power_of(freq_results, 15, 0);
+ }
+
+ if (debug) {
+ for (i = 0; i < 16; i++)
+ fprintf(outfile, "acim_results[%d] = %f\n", i, acim_results[i]);
+ }
+ /* Find out what the "best" impedance is for the line */
+ lowest = 0;
+ for (i = 0; i < 16; i++) {
+ if (acim_results[i] < acim_results[lowest]) {
+ lowest = i;
+ }
+ }
+
+ coefs_out->acim = lowest;
+ coefs_out->coef1 = 0;
+ coefs_out->coef2 = 0;
+ coefs_out->coef3 = 0;
+ coefs_out->coef4 = 0;
+ coefs_out->coef5 = 0;
+ coefs_out->coef6 = 0;
+ coefs_out->coef7 = 0;
+ coefs_out->coef8 = 0;
+
+ return 0;
+}
+
+/**
+ * Reads echo register settings from the configuration file and pushes them into
+ * the appropriate devices
+ *
+ * @param configfilename the path of the file that the calibration results should be written to
+ *
+ * @return 0 if successful, !0 otherwise
+ */
+static int do_set(char *configfilename)
+{
+ FILE *fp = NULL;
+ int res = 0;
+ int fd = 0;
+
+ fp = fopen(configfile, "r");
+
+ if (!fp) {
+ fprintf(stdout, "Cannot open %s!\n",configfile);
+ return -1;
+ }
+
+
+ while (res != EOF) {
+ struct wctdm_echo_coefs mycoefs;
+ char completezappath[56] = "";
+ int myzap,myacim,mycoef1,mycoef2,mycoef3,mycoef4,mycoef5,mycoef6,mycoef7,mycoef8;
+
+
+ res = fscanf(fp, "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d",&myzap,&myacim,&mycoef1,
+ &mycoef2,&mycoef3,&mycoef4,&mycoef5,&mycoef6,&mycoef7,
+ &mycoef8);
+
+ if (res == EOF) {
+ break;
+ }
+
+ /* Check to be sure conversion is done correctly */
+ if (OUT_OF_BOUNDS(myacim) || OUT_OF_BOUNDS(mycoef1)||
+ OUT_OF_BOUNDS(mycoef2)|| OUT_OF_BOUNDS(mycoef3)||
+ OUT_OF_BOUNDS(mycoef4)|| OUT_OF_BOUNDS(mycoef5)||
+ OUT_OF_BOUNDS(mycoef6)|| OUT_OF_BOUNDS(mycoef7)|| OUT_OF_BOUNDS(mycoef8)) {
+
+ fprintf(stdout, "Bounds check error on inputs from %s:%d\n", configfile, myzap);
+ return -1;
+ }
+
+ mycoefs.acim = myacim;
+ mycoefs.coef1 = mycoef1;
+ mycoefs.coef2 = mycoef2;
+ mycoefs.coef3 = mycoef3;
+ mycoefs.coef4 = mycoef4;
+ mycoefs.coef5 = mycoef5;
+ mycoefs.coef6 = mycoef6;
+ mycoefs.coef7 = mycoef7;
+ mycoefs.coef8 = mycoef8;
+
+ snprintf(completezappath, sizeof(completezappath), "%s/%d", zappath, myzap);
+ fd = open(completezappath, O_RDWR);
+
+ if (fd < 0) {
+ fprintf(stdout, "open error on %s: %s\n", completezappath, strerror(errno));
+ return -1;
+ }
+
+ if (ioctl(fd, WCTDM_SET_ECHOTUNE, &mycoefs)) {
+ fprintf(stdout, "%s: %s\n", completezappath, strerror(errno));
+ return -1;
+ }
+
+ close(fd);
+ }
+
+ fclose(fp);
+
+ if (debug)
+ fprintf(stdout, "fxotune: successfully set echo coeffecients on FXO modules\n");
+ return 0;
+}
+
+/**
+ * Output waveform information from a single test
+ *
+ * Clears the line, then sends a single waveform (multi-tone, or single tone), and listens
+ * for the response on the line. Output is written to fxotune_dump.vals
+ *
+ * @param startdev the device to test
+ * @param dialstr the string that should be dialed to clear the dialtone from the line
+ * @param delayuntilsilence the number of seconds to wait after dialing dialstr before starting the test
+ * @param silencegoodfor the number of seconds that the test can run before having to reset the line again
+ * (this is basically the amount of time it takes before the 'if you'd like to make a call...' message
+ * kicks in after you dial dialstr. This test is so short that the value is pretty much ignored.
+ * @param waveformtype the type of waveform to use - -1 = multi-tone waveform, otherwise the specified value
+ * is used as the frequency of a single tone. A value of 0 will output silence.
+ */
+static int do_dump(int startdev, char* dialstr, int delayuntilsilence, int silencegoodfor, int waveformtype)
+{
+ int res = 0;
+ int fd;
+ char zapdev[80] = "";
+
+ int zapmodule = startdev;
+ snprintf(zapdev, sizeof(zapdev), "%s/%d", zappath, zapmodule);
+
+ fd = open(zapdev, O_RDWR);
+ if (fd < 0) {
+ fprintf(stdout, "%s absent: %s\n", zapdev, strerror(errno));
+ return -1;
+ }
+
+ fprintf(stdout, "Dumping module %s\n", zapdev);
+ res = maptone(fd, waveformtype, dialstr, delayuntilsilence);
+
+ close(fd);
+
+ if (res) {
+ fprintf(stdout, "Failure!\n");
+ return res;
+ } else {
+ fprintf(stdout, "Done!\n");
+ return 0;
+ }
+
+}
+
+/**
+ * Performs calibration on all specified devices
+ *
+ * @param startdev the first device to check
+ * @param enddev the last device to check
+ * @param calibtype the type of calibration to perform. 1=old style (loops through individual frequencies
+ * doesn't optimize echo coefficients. 2=new style (uses multi-tone and optimizes echo coefficients
+ * and acim setting)
+ * @param configfilename the path of the file that the calibration results should be written to
+ * @param dialstr the string that should be dialed to clear the dialtone from the line
+ * @param delayuntilsilence the number of seconds to wait after dialing dialstr before starting the test
+ * @param silencegoodfor the number of seconds that the test can run before having to reset the line again
+ * (this is basically the amount of time it takes before the 'if you'd like to make a call...' message
+ * kicks in after you dial dialstr
+ *
+ * @return 0 if successful, !0 otherwise
+ */
+static int do_calibrate(int startdev, int enddev, int calibtype, char* configfilename, char* dialstr, int delayuntilsilence, int silencegoodfor)
+{
+ int problems = 0;
+ int res = 0;
+ int configfd, fd;
+ int devno = 0;
+ char zapdev[80] = "";
+ struct wctdm_echo_coefs coefs;
+
+ configfd = open(configfile, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+
+ if (configfd < 0) {
+ fprintf(stderr, "Cannot generate config file %s: open: %s\n", configfile, strerror(errno));
+ return -1;
+ }
+
+ for (devno = startdev; devno <= enddev; devno++) {
+ snprintf(zapdev, sizeof(zapdev), "%s/%d", zappath, devno);
+
+ fd = open(zapdev, O_RDWR);
+ if (fd < 0) {
+ fprintf(stdout, "%s absent: %s\n", zapdev, strerror(errno));
+ continue;
+ }
+
+ fprintf(stdout, "Tuning module %s\n", zapdev);
+
+ if (1 == calibtype)
+ res = acim_tune(fd, dialstr, delayuntilsilence, silencegoodfor, &coefs);
+ else
+ res = acim_tune2(fd, -1, dialstr, delayuntilsilence, silencegoodfor, &coefs);
+
+ close(fd);
+
+ if (res) {
+ fprintf(stdout, "Failure!\n");
+ problems++;
+ } else {
+ fprintf(stdout, "Done!\n");
+ }
+
+ if (res == 0) {
+
+ /* Do output to file */
+ int len = 0;
+ static char output[255] = "";
+
+ snprintf(output, sizeof(output), "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+ devno,
+ coefs.acim,
+ coefs.coef1,
+ coefs.coef2,
+ coefs.coef3,
+ coefs.coef4,
+ coefs.coef5,
+ coefs.coef6,
+ coefs.coef7,
+ coefs.coef8
+ );
+
+ if (debug)
+ fprintf(stdout, "Found best echo coefficients: %s\n", output);
+
+ len = strlen(output);
+ res = write(configfd, output, strlen(output));
+ if (res != len) {
+ fprintf(stdout, "Unable to write line \"%s\" to file.\n", output);
+ return -1;
+ }
+ }
+ }
+
+ close(configfd);
+
+ if (problems)
+ fprintf(stdout, "Unable to tune %d devices, even though those devices are present\n", problems);
+
+ return problems;
+}
+
+int main(int argc , char **argv)
+{
+ int startdev = 1; /* -b */
+ int stopdev = 252; /* -e */
+ int calibtype = 2; /* -t */
+ int waveformtype = -1; /* -w multi-tone by default. If > 0, single tone of specified frequency */
+ int delaytosilence = 0; /* -l */
+ int silencegoodfor = 18; /* -m */
+
+ char* dialstr = "5"; /* -n */
+
+ int res = 0;
+
+ int doset = 0; /* -s */
+ int docalibrate = 0; /* -i <dialstr> */
+ int dodump = 0; /* -d */
+
+ int i = 0;
+
+ for (i = 1; i < argc; i++){
+ if (!(argv[i][0] == '-' || argv[i][0] == '/') || (strlen(argv[i]) <= 1)){
+ fprintf(stdout, "Unknown option : %s\n", argv[i]);
+ /* Show usage */
+ fputs(usage, stdout);
+ return -1;
+ }
+ int moreargs = (i < argc - 1);
+
+ switch(argv[i][1]){
+ case 's':
+ doset=1;
+ continue;
+ case 'i':
+ docalibrate = 1;
+ if (moreargs){ /* we need to check for a value after 'i' for backwards compatability with command line options of old fxotune */
+ if (argv[i+1][0] != '-' && argv[i+1][0] != '/')
+ dialstr = argv[++i];
+ }
+ continue;
+ case 'c':
+ configfile = moreargs ? argv[++i] : configfile;
+ continue;
+ case 'd':
+ dodump = 1;
+ continue;
+ case 'b':
+ startdev = moreargs ? atoi(argv[++i]) : startdev;
+ break;
+ case 'e':
+ stopdev = moreargs ? atoi(argv[++i]) : stopdev;
+ break;
+ case 't':
+ calibtype = moreargs ? atoi(argv[++i]) : calibtype;
+ break;
+ case 'w':
+ waveformtype = moreargs ? atoi(argv[++i]) : waveformtype;
+ break;
+ case 'l':
+ delaytosilence = moreargs ? atoi(argv[++i]) : delaytosilence;
+ break;
+ case 'm':
+ silencegoodfor = moreargs ? atoi(argv[++i]) : silencegoodfor;
+ break;
+ case 'n':
+ dialstr = moreargs ? argv[++i] : dialstr;
+ break;
+ case 'v':
+ debug = strlen(argv[i])-1;
+ break;
+ case 'o':
+ if (moreargs) {
+ audio_dump_fd = open(argv[++i], O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ if (audio_dump_fd == -1) {
+ fprintf(stdout, "Unable to open file %s: %s\n", argv[i], strerror(errno));
+ return -1;
+ }
+ break;
+ } else {
+ fprintf(stdout, "No path supplied to -o option!\n");
+ return -1;
+ }
+ default:
+ fprintf(stdout, "Unknown option : %s\n", argv[i]);
+ /* Show usage */
+ fputs(usage, stdout);
+ return -1;
+
+ }
+ }
+
+ if (debug > 3){
+ fprintf(stdout, "Running with parameters:\n");
+ fprintf(stdout, "\tdoset=%d\n", doset);
+ fprintf(stdout, "\tdocalibrate=%d\n", docalibrate);
+ fprintf(stdout, "\tdodump=%d\n", dodump);
+ fprintf(stdout, "\tstartdev=%d\n", startdev);
+ fprintf(stdout, "\tstopdev=%d\n", stopdev);
+ fprintf(stdout, "\tcalibtype=%d\n", calibtype);
+ fprintf(stdout, "\twaveformtype=%d\n", waveformtype);
+ fprintf(stdout, "\tdelaytosilence=%d\n", delaytosilence);
+ fprintf(stdout, "\tsilencegoodfor=%d\n", silencegoodfor);
+ fprintf(stdout, "\tdialstr=%s\n", dialstr);
+ fprintf(stdout, "\tdebug=%d\n", debug);
+ }
+
+ if (docalibrate){
+ res = do_calibrate(startdev, stopdev, calibtype, configfile, dialstr, delaytosilence, silencegoodfor);
+ if (!res)
+ return do_set(configfile);
+ else
+ return -1;
+ }
+
+ if (doset)
+ return do_set(configfile);
+
+ if (dodump){
+ res = do_dump(startdev, dialstr, delaytosilence, silencegoodfor, waveformtype);
+ if (!res)
+ return 0;
+ else
+ return -1;
+ }
+
+ fputs(usage, stdout);
+ return -1;
+}
diff --git a/fxotune.h b/fxotune.h
new file mode 100644
index 0000000..093f03e
--- /dev/null
+++ b/fxotune.h
@@ -0,0 +1,110 @@
+/*
+ * This file and contents thereof are distributed under the terms of the
+ * GNU Public License version 2. For terms and conditions of this license
+ * see http://www.gnu.org
+ *
+ * fxotune.h -- data structures and associated definitions for fxotune.c
+ *
+ * By Matthew Fredrickson <creslin@digium.com>
+ *
+ * Echo coefficients and acim register values taken from AN84 from Silicon
+ * Laboratories app note AN84 for setting echo cancellation coefficients
+ *
+ * (C) 2005 Digium, Inc.
+ */
+
+struct wctdm_echo_coefs echo_trys [] =
+{
+ /* 600 ohm echo settings */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 10, 0, 6, 1, 254, 2, 255, 0, 0},
+ { 3, 255, 255, 0, 1, 0, 0, 0, 0},
+ { 3, 1, 253, 253, 2, 255, 0, 0, 0},
+ { 9, 254, 251, 255, 2, 0, 1, 0, 0},
+ { 5, 3, 251, 250, 2, 254, 0, 0, 255},
+ { 8, 253, 2, 244, 255, 10, 244, 3, 253},
+ { 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+ /* 900 ohm echo settings */
+ { 1, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 10, 252, 255, 1, 255, 0, 0, 0, 0},
+ { 7, 255, 251, 251, 2, 255, 255, 1, 255},
+ { 3, 1, 251, 250, 1, 254, 255, 0, 255},
+ { 5, 252, 250, 0, 0, 255, 1, 0, 0},
+ { 5, 3, 251, 250, 1, 253, 0, 0, 255},
+ { 8, 253, 2, 244, 255, 10, 244, 3, 253},
+ { 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+ /* 270 ohm + (750 ohm || 150 nF) (CTR21) */
+ { 2, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 7, 0, 0, 255, 254, 0, 0, 0, 0},
+ { 9, 0, 253, 254, 2, 255, 0, 0, 0},
+ { 5, 1, 249, 254, 4, 253, 1, 0, 0},
+ { 5, 252, 250, 1, 1, 254, 0, 255, 0},
+ { 5, 3, 251, 250, 2, 253, 255, 255, 255},
+ { 8, 253, 2, 244, 255, 10, 244, 3, 253},
+ { 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+ /* 220 ohm + (820 ohm || 120 nF) (Australia/NewZealand) and 220 ohm + (820 ohm
+ * || 115nF) (Slovakia/SAfrica/Germany/Austria/Bulgaria)
+ */
+ { 3, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 7, 0, 255, 254, 255, 0, 255, 0, 0},
+ { 9, 0, 253, 253, 1, 255, 0, 0, 0},
+ { 5, 1, 249, 254, 3, 253, 1, 0, 0},
+ { 5, 252, 250, 1, 1, 254, 0, 255, 0},
+ { 5, 3, 251, 251, 2, 253, 255, 255, 255},
+ { 8, 253, 2, 244, 255, 10, 244, 3, 253},
+ { 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+ /* 370 ohm + (620ohm || 310nF) (New Zealand #2/India) CO Termination */
+ { 4, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 9, 255, 1, 4, 0, 0, 1, 255, 0},
+ { 9, 0, 253, 0, 3, 254, 0, 0, 255},
+ { 9, 2, 250, 253, 5, 253, 1, 0 ,255},
+ { 5, 252, 250, 1, 2, 255, 0 ,255, 0},
+ { 5, 3, 251, 250, 3, 254, 255, 255, 255},
+ { 8, 253, 2, 244, 255, 10, 244, 3, 253},
+ { 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+ /* 320 ohm + (1050ohm || 230 nF) (England) CO Termination */
+ { 5, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 9, 0 ,255, 1, 255, 255, 0, 255, 0},
+ { 5, 255, 252, 0, 2, 254, 0, 255, 255},
+ { 9, 2, 250, 253, 4, 252, 0, 255, 255},
+ { 5, 252, 250, 1, 1, 254, 0 ,255, 255},
+ { 5, 3, 251, 250, 2, 253, 255, 255, 254},
+ { 3, 1, 1, 242, 2, 9, 245, 3, 253},
+ { 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+ /* 370 ohm + (820 ohm || 110 nF) CO Termination */
+ { 6, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 6, 1, 254, 253, 0, 255, 0, 0, 0},
+ { 9, 0, 251, 252, 2, 255, 0, 0, 0},
+ { 5, 1, 248, 252, 4, 253, 1, 0, 0},
+ { 5, 252, 250, 0, 0, 254, 0 , 255, 0},
+ { 5, 3, 251, 250, 2, 253, 255, 255, 254},
+ { 3, 1, 1, 242, 2, 9, 245, 3, 253},
+ { 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+ /* 275 ohm + (780 ohm || 115 nF) CO Termination */
+ { 7, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 7, 255, 255, 255, 255, 0, 0, 0, 0},
+ { 9, 0, 253, 254, 2, 255, 0, 0, 0},
+ { 5, 1, 249, 254, 4, 253, 1, 0, 0},
+ { 5, 252, 250, 1, 1, 254, 0, 255, 0},
+ { 5, 3, 251, 250, 2, 253, 255, 255, 255},
+ { 8, 253, 2, 244, 255, 10, 244, 3, 253},
+ { 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+ /* Make sure we include the rest of the impedances */
+ { 8, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 9, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 10, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 11, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 12, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 13, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 14, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 15, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
diff --git a/fxstest.c b/fxstest.c
new file mode 100644
index 0000000..ad1e4e6
--- /dev/null
+++ b/fxstest.c
@@ -0,0 +1,144 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include "kernel/zaptel.h"
+#include "tonezone.h"
+#include "kernel/wctdm.h"
+
+static int tones[] = {
+ ZT_TONE_DIALTONE,
+ ZT_TONE_BUSY,
+ ZT_TONE_RINGTONE,
+ ZT_TONE_CONGESTION,
+ ZT_TONE_DIALRECALL,
+};
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int res;
+ int x;
+ if (argc < 3) {
+ fprintf(stderr, "Usage: fxstest <zap device> <cmd>\n"
+ " where cmd is one of:\n"
+ " stats - reports voltages\n"
+ " regdump - dumps ProSLIC registers\n"
+ " tones - plays a series of tones\n"
+ " polarity - tests polarity reversal\n"
+ " ring - rings phone\n");
+ exit(1);
+ }
+ fd = open(argv[1], O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
+ exit(1);
+ }
+ if (!strcasecmp(argv[2], "ring")) {
+ fprintf(stderr, "Ringing phone...\n");
+ x = ZT_RING;
+ res = ioctl(fd, ZT_HOOK, &x);
+ if (res) {
+ fprintf(stderr, "Unable to ring phone...\n");
+ } else {
+ fprintf(stderr, "Phone is ringing...\n");
+ sleep(2);
+ }
+ } else if (!strcasecmp(argv[2], "polarity")) {
+ fprintf(stderr, "Twiddling polarity...\n");
+ x = 0;
+ res = ioctl(fd, ZT_SETPOLARITY, &x);
+ if (res) {
+ fprintf(stderr, "Unable to polarity...\n");
+ } else {
+ fprintf(stderr, "Polarity is forward...\n");
+ sleep(2);
+ x = 1;
+ ioctl(fd, ZT_SETPOLARITY, &x);
+ fprintf(stderr, "Polarity is reversed...\n");
+ sleep(5);
+ x = 0;
+ ioctl(fd, ZT_SETPOLARITY, &x);
+ fprintf(stderr, "Polarity is forward...\n");
+ sleep(2);
+ }
+ } else if (!strcasecmp(argv[2], "tones")) {
+ int x = 0;
+ for (;;) {
+ res = tone_zone_play_tone(fd, tones[x]);
+ if (res)
+ fprintf(stderr, "Unable to play tone %d\n", tones[x]);
+ sleep(3);
+ x=(x+1) % (sizeof(tones) / sizeof(tones[0]));
+ }
+ } else if (!strcasecmp(argv[2], "stats")) {
+ struct wctdm_stats stats;
+ res = ioctl(fd, WCTDM_GET_STATS, &stats);
+ if (res) {
+ fprintf(stderr, "Unable to get stats on channel %s\n", argv[1]);
+ } else {
+ printf("TIP: %7.4f Volts\n", (float)stats.tipvolt / 1000.0);
+ printf("RING: %7.4f Volts\n", (float)stats.ringvolt / 1000.0);
+ printf("VBAT: %7.4f Volts\n", (float)stats.batvolt / 1000.0);
+ }
+ } else if (!strcasecmp(argv[2], "regdump")) {
+ struct wctdm_regs regs;
+ int numregs = NUM_REGS;
+ memset(&regs, 0, sizeof(regs));
+ res = ioctl(fd, WCTDM_GET_REGS, &regs);
+ if (res) {
+ fprintf(stderr, "Unable to get registers on channel %s\n", argv[1]);
+ } else {
+ for (x=60;x<NUM_REGS;x++) {
+ if (regs.direct[x])
+ break;
+ }
+ if (x == NUM_REGS)
+ numregs = 60;
+ printf("Direct registers: \n");
+ for (x=0;x<numregs;x++) {
+ printf("%3d. %02x ", x, regs.direct[x]);
+ if ((x % 8) == 7)
+ printf("\n");
+ }
+ if (numregs == NUM_REGS) {
+ printf("\n\nIndirect registers: \n");
+ for (x=0;x<NUM_INDIRECT_REGS;x++) {
+ printf("%3d. %04x ", x, regs.indirect[x]);
+ if ((x % 6) == 5)
+ printf("\n");
+ }
+ }
+ printf("\n\n");
+ }
+ } else if (!strcasecmp(argv[2], "setdirect") ||
+ !strcasecmp(argv[2], "setindirect")) {
+ struct wctdm_regop regop;
+ int val;
+ int reg;
+ if ((argc < 5) || (sscanf(argv[3], "%i", &reg) != 1) ||
+ (sscanf(argv[4], "%i", &val) != 1)) {
+ fprintf(stderr, "Need a register and value...\n");
+ } else {
+ regop.reg = reg;
+ regop.val = val;
+ if (!strcasecmp(argv[2], "setindirect")) {
+ regop.indirect = 1;
+ regop.val &= 0xff;
+ } else {
+ regop.indirect = 0;
+ }
+ res = ioctl(fd, WCTDM_SET_REG, &regop);
+ if (res)
+ fprintf(stderr, "Unable to get registers on channel %s\n", argv[1]);
+ else
+ printf("Success.\n");
+ }
+ } else
+ fprintf(stderr, "Invalid command\n");
+ close(fd);
+ return 0;
+}
diff --git a/hdlcgen.c b/hdlcgen.c
new file mode 100644
index 0000000..417004b
--- /dev/null
+++ b/hdlcgen.c
@@ -0,0 +1,105 @@
+#define FAST_HDLC_NEED_TABLES
+#include "kernel/fasthdlc.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define RANDOM "/dev/urandom" /* Not genuinely random */
+/* #define RANDOM "/dev/random" */ /* Quite genuinely random */
+
+int myread(int fd, char *buf, int len)
+{
+ int sofar;
+ int res;
+ sofar = 0;
+ while(sofar < len) {
+ res = read(fd, buf + sofar, len - sofar);
+ if (res < 0)
+ return res;
+ sofar += res;
+ }
+ return sofar;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned char buf[1024];
+ unsigned char outbuf[2048];
+ int res;
+ int randin;
+ int randout;
+ int hdlcout;
+ int cnt;
+ int hdlccnt;
+ int x;
+ int flags;
+ struct fasthdlc_state transmitter;
+
+ fasthdlc_precalc();
+
+ fasthdlc_init(&transmitter);
+
+ randin = open(RANDOM, O_RDONLY);
+ if (randin < 0) {
+ fprintf(stderr, "Unable to open %s: %s\n", RANDOM, strerror(errno));
+ exit(1);
+ }
+ randout = open("random.raw", O_WRONLY|O_TRUNC|O_CREAT, 0666);
+ if (randout < 0) {
+ fprintf(stderr, "Unable to open random.raw: %s\n", strerror(errno));
+ exit(1);
+ }
+ hdlcout = open("random.hdlc", O_WRONLY|O_TRUNC|O_CREAT, 0666);
+ if (hdlcout < 0) {
+ fprintf(stderr, "Unable to open random.hdlc: %s\n", strerror(errno));
+ exit(1);
+ }
+ for (;;) {
+ cnt = (rand() % 256) + 4; /* Read a pseudo-random amount of stuff */
+ res = myread(randin, buf, cnt);
+ if (res != cnt) {
+ fprintf(stderr, "Tried to read %d bytes, but read %d instead\n", cnt, res);
+ exit(1);
+ }
+ res = write(randout, buf, cnt);
+ if (res != cnt) {
+ fprintf(stderr, "Tried to write %d bytes, but wrote %d instead\n", cnt, res);
+ exit(1);
+ }
+ /* HDLC encode */
+ hdlccnt = 0;
+ /* Start with a flag */
+ fasthdlc_tx_frame(&transmitter);
+ if (transmitter.bits >= 8)
+ outbuf[hdlccnt++] = fasthdlc_tx_run(&transmitter);
+ for (x=0;x<cnt;x++) {
+ res = fasthdlc_tx_load(&transmitter, buf[x]);
+ if (res < 0) {
+ fprintf(stderr, "Unable to load byte :(\n");
+ exit(1);
+ }
+ while(transmitter.bits >= 8) {
+ outbuf[hdlccnt++] = fasthdlc_tx_run(&transmitter);
+ }
+ }
+ flags = (rand() % 4);
+ for (x=0;x<flags;x++) {
+ if (transmitter.bits < 8)
+ fasthdlc_tx_frame(&transmitter);
+ else
+ fprintf(stderr, "Huh? Don't need a frame?\n");
+ outbuf[hdlccnt++] = fasthdlc_tx_run(&transmitter);
+ }
+ if (argc > 1)
+ printf("Encoded %d byte message with %d bytes of HDLC and %d extra flags\n", cnt, hdlccnt, flags);
+ res = write(hdlcout, outbuf, hdlccnt);
+ if (res != hdlccnt) {
+ fprintf(stderr, "Tried to write %d HDLC bytes, but wrote %d instead\n", cnt, res);
+ exit(1);
+ }
+
+ }
+}
diff --git a/hdlcstress.c b/hdlcstress.c
new file mode 100644
index 0000000..91af39d
--- /dev/null
+++ b/hdlcstress.c
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include "kernel/zaptel.h"
+#include <stdio.h>
+#include <linux/types.h>
+#include <linux/ppp_defs.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "bittest.h"
+#define FAST_HDLC_NEED_TABLES
+#include "kernel/fasthdlc.h"
+
+/* #define BLOCK_SIZE 2048 */
+#define BLOCK_SIZE 2041
+
+static int hdlcmode = 0;
+
+
+static unsigned short fcstab[256] =
+{
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#define PPP_INITFCS 0xffff /* Initial FCS value */
+#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+void print_packet(unsigned char *buf, int len)
+{
+ int x;
+ printf("{ ");
+ for (x=0;x<len;x++)
+ printf("%02x ",buf[x]);
+ printf("}\n");
+}
+
+static int fd;
+static struct fasthdlc_state fs;
+
+void send_packet(unsigned char *buf, int len)
+{
+ int res;
+ int x;
+ unsigned char outbuf[BLOCK_SIZE];
+ int pos=0;
+ unsigned int fcs = PPP_INITFCS;
+ if (hdlcmode)
+ res = write(fd, buf, len + 2);
+ else {
+ for (x=0;x<len;x++) {
+ if (fasthdlc_tx_load(&fs, buf[x]))
+ printf("Load error\n");
+ fcs = PPP_FCS(fcs, buf[x]);
+ outbuf[pos++] = fasthdlc_tx_run(&fs);
+ if (fs.bits > 7)
+ outbuf[pos++] = fasthdlc_tx_run(&fs);
+ }
+ fcs ^= 0xffff;
+ if (fasthdlc_tx_load(&fs, (fcs & 0xff)))
+ fprintf(stderr, "Load error (fcs1)\n");
+ outbuf[pos++] = fasthdlc_tx_run(&fs);
+ if (fs.bits > 7)
+ outbuf[pos++] = fasthdlc_tx_run(&fs);
+ if (fasthdlc_tx_load(&fs, ((fcs >> 8) & 0xff)))
+ fprintf(stderr, "Load error (fcs2)\n");
+ outbuf[pos++] = fasthdlc_tx_run(&fs);
+ if (fs.bits > 7)
+ outbuf[pos++] = fasthdlc_tx_run(&fs);
+ if (fasthdlc_tx_frame(&fs))
+ fprintf(stderr, "Frame error\n");
+ if (fs.bits > 7)
+ outbuf[pos++] = fasthdlc_tx_run(&fs);
+ if (fs.bits > 7)
+ outbuf[pos++] = fasthdlc_tx_run(&fs);
+ write(fd, outbuf, pos);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int res, x;
+ ZT_PARAMS tp;
+ ZT_BUFFERINFO bi;
+ int bs = BLOCK_SIZE;
+ unsigned char c=0;
+ unsigned char outbuf[BLOCK_SIZE];
+ if (argc < 2) {
+ fprintf(stderr, "Usage: markhdlctest <tor device>\n");
+ exit(1);
+ }
+ fd = open(argv[1], O_RDWR, 0600);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, ZT_SET_BLOCKSIZE, &bs)) {
+ fprintf(stderr, "Unable to set block size to %d: %s\n", bs, strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, ZT_GET_PARAMS, &tp)) {
+ fprintf(stderr, "Unable to get channel parameters\n");
+ exit(1);
+ }
+ if ((tp.sigtype & ZT_SIG_HDLCRAW) == ZT_SIG_HDLCRAW) {
+ printf("In HDLC mode\n");
+ hdlcmode = 1;
+ } else if ((tp.sigtype & ZT_SIG_CLEAR) == ZT_SIG_CLEAR) {
+ printf("In CLEAR mode\n");
+ hdlcmode = 0;
+ } else {
+ fprintf(stderr, "Not in a reasonable mode\n");
+ exit(1);
+ }
+ res = ioctl(fd, ZT_GET_BUFINFO, &bi);
+ if (!res) {
+ bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.numbufs = 4;
+ res = ioctl(fd, ZT_SET_BUFINFO, &bi);
+ if (res < 0) {
+ fprintf(stderr, "Unable to set buf info: %s\n", strerror(errno));
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "Unable to get buf info: %s\n", strerror(errno));
+ exit(1);
+ }
+ ioctl(fd, ZT_GETEVENT);
+ fasthdlc_precalc();
+ fasthdlc_init(&fs);
+#if 0
+ print_packet(outbuf, res);
+ printf("FCS is %x, PPP_GOODFCS is %x\n",
+ fcs,PPP_GOODFCS);
+#endif
+ for(;;) {
+ if (c < 1)
+ c = 1;
+ for (x=0;x<50;x++) {
+ outbuf[x] = c;
+ }
+ send_packet(outbuf, 50);
+#if 0
+ printf("Wrote %d of %d bytes\n", res, c);
+#endif
+ c = bit_next(c);
+#if 0
+ printf("(%d) Wrote %d bytes\n", packets++, res);
+#endif
+ }
+
+}
diff --git a/hdlctest.c b/hdlctest.c
new file mode 100644
index 0000000..4cd4d91
--- /dev/null
+++ b/hdlctest.c
@@ -0,0 +1,261 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include "kernel/zaptel.h"
+#include <stdio.h>
+#include <linux/types.h>
+#include <linux/ppp_defs.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "bittest.h"
+#define FAST_HDLC_NEED_TABLES
+#include "kernel/fasthdlc.h"
+
+#define BLOCK_SIZE 2039
+
+static unsigned short fcstab[256] =
+{
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#define PPP_INITFCS 0xffff /* Initial FCS value */
+#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+void print_packet(unsigned char *buf, int len)
+{
+ int x;
+ printf("{ ");
+ for (x=0;x<len;x++)
+ printf("%02x ",buf[x]);
+ printf("}\n");
+}
+
+static int bytes = 0;
+static int errors=0;
+static int c;
+
+void dump_bits(unsigned char *outbuf, int len)
+{
+ int x,i;
+ for (x=0;x<len;x++) {
+ for (i=0;i<8;i++) {
+ if (outbuf[x] & (1 << (7-i)))
+ printf("1");
+ else
+ printf("0");
+ }
+ }
+ printf("\n");
+}
+
+void dump_bitslong(unsigned int outbuf, int bits)
+{
+ int i;
+ printf("Dumping %d bits from %04x\n", bits, outbuf);
+ for (i=0;i<bits;i++) {
+ if (outbuf & (1 << (31 - i)))
+ printf("1");
+ else
+ printf("0");
+ }
+ printf("\n");
+}
+
+int check_frame(unsigned char *outbuf, int res)
+{
+ static int setup = 0;
+ int x;
+ unsigned short fcs = PPP_INITFCS;
+ if (c < 1)
+ c = 1;
+ if (!setup) {
+ c = outbuf[0];
+ setup++;
+ }
+ for (x=0;x<res;x++) {
+ if (outbuf[x] != c && (x < res - 2)) {
+ printf("(Error %d): Unexpected result, %d != %d, position %d %d bytes since last error.\n", ++errors, outbuf[x], c, x, bytes);
+ if (!x)
+ c = outbuf[0];
+ bytes=0;
+ } else
+ bytes++;
+ fcs = PPP_FCS(fcs, outbuf[x]);
+ }
+ if (fcs != PPP_GOODFCS)
+ printf("FCS Check failed :( (%04x != %04x)\n", fcs, PPP_GOODFCS);
+#if 0
+ if (res != c) {
+ printf("Res is %d, expected %d\n", res, c+2);
+ }
+#endif
+ c = bit_next(c);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int res, x;
+ ZT_PARAMS tp;
+ ZT_BUFFERINFO bi;
+ int bs = BLOCK_SIZE;
+ int pos = 0;
+ unsigned char inbuf[BLOCK_SIZE];
+ unsigned char outbuf[BLOCK_SIZE];
+ int bytes=0;
+ int out;
+ unsigned int olddata1;
+ int oldones1;
+ int oldbits1;
+ unsigned int olddata;
+ int oldones;
+ int oldbits;
+ int hdlcmode = 0;
+ struct fasthdlc_state fs;
+ if (argc < 2) {
+ fprintf(stderr, "Usage: markhdlctest <tor device>\n");
+ exit(1);
+ }
+ fd = open(argv[1], O_RDWR, 0600);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, ZT_SET_BLOCKSIZE, &bs)) {
+ fprintf(stderr, "Unable to set block size to %d: %s\n", bs, strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, ZT_GET_PARAMS, &tp)) {
+ fprintf(stderr, "Unable to get channel parameters\n");
+ exit(1);
+ }
+ if ((tp.sigtype & ZT_SIG_HDLCRAW) == ZT_SIG_HDLCRAW) {
+ printf("In HDLC mode\n");
+ hdlcmode = 1;
+ } else if ((tp.sigtype & ZT_SIG_CLEAR) == ZT_SIG_CLEAR) {
+ printf("In CLEAR mode\n");
+ hdlcmode = 0;
+ } else {
+ fprintf(stderr, "Not in a reasonable mode\n");
+ exit(1);
+ }
+ res = ioctl(fd, ZT_GET_BUFINFO, &bi);
+ if (!res) {
+ bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.numbufs = 4;
+ res = ioctl(fd, ZT_SET_BUFINFO, &bi);
+ if (res < 0) {
+ fprintf(stderr, "Unable to set buf info: %s\n", strerror(errno));
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "Unable to get buf info: %s\n", strerror(errno));
+ exit(1);
+ }
+ ioctl(fd, ZT_GETEVENT);
+ fasthdlc_precalc();
+ fasthdlc_init(&fs);
+ for(;;) {
+ res = read(fd, outbuf, sizeof(outbuf));
+ if (hdlcmode) {
+ if (res < 0) {
+ if (errno == ELAST) {
+ if (ioctl(fd, ZT_GETEVENT, &x) < 0) {
+ fprintf(stderr, "Unaable to get event: %s\n", strerror(errno));
+ exit(1);
+ }
+ fprintf(stderr, "Event: %d (%d bytes since last error)\n", x, bytes);
+ bytes=0;
+ continue;
+ } else {
+ fprintf(stderr, "Error: %s\n", strerror(errno));
+ exit(1);
+ }
+ }
+#if 0
+ printf("Res is %d, buf0 is %d, buf1 is %d\n", res, outbuf[0], outbuf[1]);
+#endif
+ if (res < 2) {
+ fprintf(stderr, "Too small? Only got %d bytes\n", res);
+ }
+ check_frame(outbuf, res);
+ } else {
+ for (x=0;x<res;x++) {
+ oldones1 = oldones;
+ oldbits1 = oldbits;
+ olddata1 = olddata;
+ oldones = fs.ones;
+ oldbits = fs.bits;
+ olddata = fs.data;
+ fasthdlc_rx_load(&fs, outbuf[x]);
+ out = fasthdlc_rx_run(&fs);
+ if (out & RETURN_EMPTY_FLAG) {
+ /* Empty */
+ } else if (out & RETURN_COMPLETE_FLAG) {
+ if (pos && (pos < 2)) {
+ printf("Too short? (%d)\n", pos);
+ } else if (pos) {
+ check_frame(inbuf, pos);
+ }
+ pos = 0;
+ } else if (out & RETURN_DISCARD_FLAG) {
+ printf("Discard (search = %d, len = %d, buf = %d, x=%d, res=%d, oldones: %d, oldbits: %d)\n", c, pos, inbuf[0], x, res, oldones, oldbits);
+ dump_bitslong(olddata, oldbits);
+ printf("Discard oldones: %d, oldbits: %d)\n", oldones1, oldbits1);
+ dump_bitslong(olddata1, oldbits1);
+ if (x > 64) {
+ dump_bits(outbuf + x - 64, 64);
+ dump_bits(outbuf + x, 64);
+ }
+ pos = 0;
+ } else {
+ if ((out != c) && (pos < c) && !pos) {
+ printf("Warning: Expecting %d at pos %d, got %d (x =%d)\n", c, pos, out, x);
+ if (x > 64) {
+ dump_bits(outbuf + x - 64, 64);
+ dump_bits(outbuf + x, 64);
+ }
+ }
+ inbuf[pos++] = out;
+ }
+ }
+ }
+ }
+
+}
diff --git a/hdlcverify.c b/hdlcverify.c
new file mode 100644
index 0000000..8212b2a
--- /dev/null
+++ b/hdlcverify.c
@@ -0,0 +1,106 @@
+#define FAST_HDLC_NEED_TABLES
+#include "kernel/fasthdlc.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int myread(int fd, char *buf, int len)
+{
+ int sofar;
+ int res;
+ sofar = 0;
+ while(sofar < len) {
+ res = read(fd, buf + sofar, len - sofar);
+ if (res < 0)
+ return res;
+ sofar += res;
+ }
+ return sofar;
+}
+
+static inline unsigned char nextchar(int fd)
+{
+ static unsigned char inbuf[2048];
+ static int bytes = 0;
+ static int pos = 0;
+ if (pos >= bytes) {
+ pos = 0;
+ bytes = read(fd, inbuf, sizeof(inbuf));
+ if (bytes < 0) {
+ fprintf(stderr, "Unable to read more data: %s\n", strerror(errno));
+ exit(1);
+ }
+ if (bytes == 0) {
+ fprintf(stderr, "-- END OF DATA --\n");
+ exit(0);
+ }
+ }
+ return inbuf[pos++];
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned char decbuf[1024];
+ unsigned char actual[1024];
+ int res;
+ int datain;
+ int hdlcin;
+ int hdlccnt;
+ int x;
+ struct fasthdlc_state receiver;
+
+ fasthdlc_precalc();
+
+ fasthdlc_init(&receiver);
+
+ hdlcin = open("random.hdlc", O_RDONLY);
+ if (hdlcin < 0) {
+ fprintf(stderr, "Unable to open %s: %s\n", "random.hdlc", strerror(errno));
+ exit(1);
+ }
+ datain = open("random.raw", O_RDONLY);
+ if (datain < 0) {
+ fprintf(stderr, "Unable to open random.raw: %s\n", strerror(errno));
+ exit(1);
+ }
+ hdlccnt = 0;
+ for (;;) {
+ /* Feed in some input */
+ if (fasthdlc_rx_load(&receiver, nextchar(hdlcin))) {
+ fprintf(stderr, "Unable to feed receiver :(\n");
+ exit(1);
+ }
+ res = fasthdlc_rx_run(&receiver);
+ if (res & RETURN_EMPTY_FLAG)
+ continue;
+ if (res & RETURN_COMPLETE_FLAG) {
+ if (hdlccnt) {
+ if (argc > 1)
+ printf("Got message of length %d\n", hdlccnt);
+ res = myread(datain, actual, hdlccnt);
+ if (res != hdlccnt) {
+ fprintf(stderr, "Tried to read %d bytes, but read %d instead\n", hdlccnt, res);
+ exit(1);
+ }
+ for (x=0;x<hdlccnt;x++) {
+ if (actual[x] != decbuf[x]) {
+ fprintf(stderr, "Found discrepancy at offset %d\n", x);
+ exit(1);
+ }
+ }
+ /* Reset message receiver */
+ hdlccnt = 0;
+ }
+ } else if (res & RETURN_DISCARD_FLAG) {
+ if (1 || hdlccnt) {
+ fprintf(stderr, "Detected abort :(\n");
+ exit(1);
+ }
+ } else {
+ decbuf[hdlccnt++] = res;
+ }
+ }
+}
diff --git a/makeopts.in b/makeopts.in
new file mode 100644
index 0000000..c2bf075
--- /dev/null
+++ b/makeopts.in
@@ -0,0 +1,47 @@
+CC=@CC@
+HOSTCC=@HOSTCC@
+CFLAGS=@CFLAGS@
+LDFLAGS=@LDFLAGS@
+
+INSTALL=@INSTALL@
+GREP=@GREP@
+SHELL=@SHELL@
+LN=@LN@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+datarootdir = @datarootdir@
+datadir = @datadir@
+includedir = @includedir@
+infodir = @infodir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+
+DOWNLOAD=@DOWNLOAD@
+
+PBX_LIBNEWT=@PBX_LIBNEWT@
+NEWT_LIB=@NEWT_LIB@
+NEWT_INCLUDE=@NEWT_INCLUDE@
+
+CURSES_LIB=@CURSES_LIB@
+CURSES_INCLUDE=@CURSES_INCLUDE@
+
+NCURSES_LIB=@NCURSES_LIB@
+NCURSES_INCLUDE=@NCURSES_INCLUDE@
+
+PBX_LIBUSB=@PBX_LIBUSB@
+USB_LIB=@USB_LIB@
+USB_INCLUDE=@USB_INCLUDE@
+
+USE_SELINUX=@USE_SELINUX@
+
+PPPD_VERSION=@PPPD_VERSION@
+
+ASCIIDOC=@ASCIIDOC@
diff --git a/patgen.c b/patgen.c
new file mode 100644
index 0000000..34f455a
--- /dev/null
+++ b/patgen.c
@@ -0,0 +1,98 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <linux/types.h>
+#include <linux/ppp_defs.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "bittest.h"
+
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+/* #define BLOCK_SIZE 2048 */
+#define BLOCK_SIZE 2041
+
+void print_packet(unsigned char *buf, int len)
+{
+ int x;
+ printf("{ ");
+ for (x=0;x<len;x++)
+ printf("%02x ",buf[x]);
+ printf("}\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int res, res1, x;
+ ZT_PARAMS tp;
+ int bs = BLOCK_SIZE;
+ unsigned char c=0;
+ unsigned char outbuf[BLOCK_SIZE];
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <tor device>\n", argv[0]);
+ exit(1);
+ }
+ fd = open(argv[1], O_RDWR, 0600);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, ZT_SET_BLOCKSIZE, &bs)) {
+ fprintf(stderr, "Unable to set block size to %d: %s\n", bs, strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, ZT_GET_PARAMS, &tp)) {
+ fprintf(stderr, "Unable to get channel parameters\n");
+ exit(1);
+ }
+ ioctl(fd, ZT_GETEVENT);
+#if 0
+ print_packet(outbuf, res);
+ printf("FCS is %x, PPP_GOODFCS is %x\n",
+ fcs,PPP_GOODFCS);
+#endif
+ for(;;) {
+ res = bs;
+ for (x=0;x<bs;x++) {
+ outbuf[x] = c;
+ c = bit_next(c);
+ }
+ res1 = write(fd, outbuf, res);
+ if (res1 < res) {
+ int e;
+ ZT_SPANINFO zi;
+ res = ioctl(fd,ZT_GETEVENT,&e);
+ if (res == -1)
+ {
+ perror("ZT_GETEVENT");
+ exit(1);
+ }
+ if (e == ZT_EVENT_NOALARM)
+ printf("ALARMS CLEARED\n");
+ if (e == ZT_EVENT_ALARM)
+ {
+ zi.spanno = 0;
+ res = ioctl(fd,ZT_SPANSTAT,&zi);
+ if (res == -1)
+ {
+ perror("ZT_SPANSTAT");
+ exit(1);
+ }
+ printf("Alarm mask %x hex\n",zi.alarms);
+ }
+ continue;
+ }
+#if 0
+ printf("(%d) Wrote %d bytes\n", packets++, res);
+#endif
+ }
+
+}
diff --git a/patlooptest.c b/patlooptest.c
new file mode 100644
index 0000000..738da63
--- /dev/null
+++ b/patlooptest.c
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+#define BLOCK_SIZE 2039
+
+void print_packet(unsigned char *buf, int len)
+{
+ int x;
+ printf("{ ");
+ for (x=0;x<len;x++)
+ printf("%02x ",buf[x]);
+ printf("}\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int res, x;
+ int i;
+ ZT_PARAMS tp;
+ int bs = BLOCK_SIZE;
+ int skipcount = 10;
+ unsigned char c=0,c1=0;
+ unsigned char inbuf[BLOCK_SIZE];
+ unsigned char outbuf[BLOCK_SIZE];
+ int setup=0;
+ int errors=0;
+ int bytes=0;
+ int timeout=0;
+ time_t start_time=0;
+ if (argc < 2 || argc > 3 ) {
+ fprintf(stderr, "Usage: %s <zaptel device> [timeout]\n",argv[0]);
+ exit(1);
+ }
+ fd = open(argv[1], O_RDWR, 0600);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, ZT_SET_BLOCKSIZE, &bs)) {
+ fprintf(stderr, "Unable to set block size to %d: %s\n", bs, strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, ZT_GET_PARAMS, &tp)) {
+ fprintf(stderr, "Unable to get channel parameters\n");
+ exit(1);
+ }
+ ioctl(fd, ZT_GETEVENT);
+
+ i = ZT_FLUSH_ALL;
+ if (ioctl(fd,ZT_FLUSH,&i) == -1)
+ {
+ perror("tor_flush");
+ exit(255);
+ }
+ if(argc==3){
+ timeout=atoi(argv[2]);
+ start_time=time(NULL);
+ printf("Using Timeout of %d Seconds\n",timeout);
+ }
+
+ for(;;) {
+ res = bs;
+ for (x=0;x<bs;x++)
+ outbuf[x] = c1++;
+
+ res = write(fd,outbuf,bs);
+ if (res != bs)
+ {
+ printf("Res is %d: %s\n", res, strerror(errno));
+ ioctl(fd, ZT_GETEVENT, &x);
+ printf("Event: %d\n", x);
+ exit(1);
+ }
+
+ if (skipcount)
+ {
+ if (skipcount > 1) read(fd,inbuf,bs);
+ skipcount--;
+ if (!skipcount) puts("Going for it...");
+ continue;
+ }
+
+ res = read(fd, inbuf, bs);
+ if (res < bs) {
+ printf("Res is %d\n", res);
+ exit(1);
+ }
+ if (!setup) {
+ c = inbuf[0];
+ setup++;
+ }
+ for (x=0;x<bs;x++) {
+ if (inbuf[x] != c) {
+ printf("(Error %d): Unexpected result, %d != %d, %d bytes since last error.\n", ++errors, inbuf[x],c, bytes);
+ c = inbuf[x];
+ bytes=0;
+ }
+ c++;
+ bytes++;
+ }
+#if 0
+ printf("(%d) Wrote %d bytes\n", packets++, res);
+#endif
+ if(timeout && (time(NULL)-start_time)>timeout){
+ printf("Timeout achieved Ending Program\n");
+ return errors;
+ }
+ }
+
+}
diff --git a/pattest.c b/pattest.c
new file mode 100644
index 0000000..69c3b6e
--- /dev/null
+++ b/pattest.c
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <linux/types.h>
+#include <linux/ppp_defs.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "bittest.h"
+
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+#define BLOCK_SIZE 2039
+
+void print_packet(unsigned char *buf, int len)
+{
+ int x;
+ printf("{ ");
+ for (x=0;x<len;x++)
+ printf("%02x ",buf[x]);
+ printf("}\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int res, x;
+ ZT_PARAMS tp;
+ int bs = BLOCK_SIZE;
+ unsigned char c=0;
+ unsigned char outbuf[BLOCK_SIZE];
+ int setup=0;
+ int errors=0;
+ int bytes=0;
+ if (argc < 2) {
+ fprintf(stderr, "Usage: markhdlctest <tor device>\n");
+ exit(1);
+ }
+ fd = open(argv[1], O_RDWR, 0600);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, ZT_SET_BLOCKSIZE, &bs)) {
+ fprintf(stderr, "Unable to set block size to %d: %s\n", bs, strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, ZT_GET_PARAMS, &tp)) {
+ fprintf(stderr, "Unable to get channel parameters\n");
+ exit(1);
+ }
+ ioctl(fd, ZT_GETEVENT);
+ for(;;) {
+ res = bs;
+ res = read(fd, outbuf, res);
+ if (res < bs) {
+ int e;
+ ZT_SPANINFO zi;
+ res = ioctl(fd,ZT_GETEVENT,&e);
+ if (res == -1)
+ {
+ perror("ZT_GETEVENT");
+ exit(1);
+ }
+ if (e == ZT_EVENT_NOALARM)
+ printf("ALARMS CLEARED\n");
+ if (e == ZT_EVENT_ALARM)
+ {
+ zi.spanno = 0;
+ res = ioctl(fd,ZT_SPANSTAT,&zi);
+ if (res == -1)
+ {
+ perror("ZT_SPANSTAT");
+ exit(1);
+ }
+ printf("Alarm mask %x hex\n",zi.alarms);
+ }
+ continue;
+ }
+ if (!setup) {
+ c = outbuf[0];
+ setup++;
+ }
+ for (x=0;x<bs;x++) {
+ if (outbuf[x] != c) {
+ printf("(Error %d): Unexpected result, %d != %d, %d bytes since last error.\n", ++errors, outbuf[x], c, bytes);
+ c = outbuf[x];
+ bytes=0;
+ }
+ c = bit_next(c);
+ bytes++;
+ }
+#if 0
+ printf("(%d) Wrote %d bytes\n", packets++, res);
+#endif
+ }
+
+}
diff --git a/ppp/Makefile b/ppp/Makefile
new file mode 100644
index 0000000..86b65a6
--- /dev/null
+++ b/ppp/Makefile
@@ -0,0 +1,29 @@
+#COPTS = -O2 -g
+
+-include ../makeopts
+
+CFLAGS += $(COPTS) -I.. -fPIC
+LDFLAGS += -shared
+
+INCLUDE_DIR = $(includedir)/pppd
+
+LIBDIR = $(libdir)/pppd/$(PPPD_VERSION)
+
+PLUGINS := zaptel.so
+
+all: $(PLUGINS)
+
+%.so: %.c
+ifeq (,$(PPPD_VERSION))
+ @echo "pppd version not found (in patchlevel.h)."
+ @echo "Install ppp source/headers and/or ./configure --with-ppp=PATH."
+ exit 1
+endif
+ $(CC) -o $@ $(CFLAGS) $^ $(LDFLAGS)
+
+install: $(PLUGINS)
+ $(INSTALL) -d $(DESTDIR)$(LIBDIR)
+ $(INSTALL) -m 0644 $? $(DESTDIR)$(LIBDIR)
+
+clean:
+ rm -f *.o *.so *.a
diff --git a/ppp/zaptel.c b/ppp/zaptel.c
new file mode 100644
index 0000000..121bfec
--- /dev/null
+++ b/ppp/zaptel.c
@@ -0,0 +1,284 @@
+/* zaptel.c - pppd plugin to implement PPP over Zaptel HDLC channel.
+ *
+ * Copyright 2002 Digium, Inc.
+ * Mark Spencer <markster@digium.inc>
+ *
+ * Borrows from PPPoE by Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
+ * Jamal Hadi Salim <hadi@cyberus.ca>
+ *
+ * which in turn...
+ *
+ * Borrows heavily from the PPPoATM plugin by Mitchell Blank Jr.,
+ * which is based in part on work from Jens Axboe and Paul Mackerras.
+ *
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <pppd/pppd.h>
+#include <pppd/fsm.h>
+#include <pppd/lcp.h>
+#include <pppd/ipcp.h>
+#include <pppd/ccp.h>
+#include <pppd/pathnames.h>
+
+#include "zaptel.h"
+
+extern int new_style_driver;
+
+const char pppd_version[] = VERSION;
+
+#define _PATH_ZAPOPT _ROOT_PATH "/etc/ppp/options."
+
+#define ZAP_MTU (ZT_DEFAULT_MTU_MRU - 16)
+extern int kill_link;
+int retries = 0;
+
+int setdevname_zaptel(const char *cp);
+
+static option_t zaptel_options[] = {
+ { "device name", o_wild, (void *) &setdevname_zaptel,
+ "Serial port device name",
+ OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC,
+ devnam},
+ { NULL }
+};
+
+static int zapfd = -1;
+static int zapchan = 0;
+
+static int connect_zaptel(void)
+{
+
+ ZT_PARAMS ztp;
+ int res;
+ int x;
+
+ info("Zaptel device is '%s'\n", devnam);
+
+ strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
+
+ if (strlen(devnam) && strcmp(devnam, "stdin")) {
+ /* Get the channel number */
+ zapchan = atoi(devnam);
+ if (zapchan < 1) {
+ fatal("'%s' is not a valid device name\n", devnam);
+ return -1;
+ }
+
+ /* Open /dev/zap/channel interface */
+ zapfd = open("/dev/zap/channel", O_RDWR);
+ if (zapfd < 0) {
+ fatal("Unable to open zaptel channel interface: '%s'\n", strerror(errno));
+ return zapfd;
+ }
+
+ /* Specify which channel we really want */
+ x = zapchan;
+ res = ioctl(zapfd, ZT_SPECIFY, &x);
+ if (res) {
+ fatal("Unable to specify channel %d: %s\n", zapchan, strerror(errno));
+ close(zapfd);
+ zapfd = -1;
+ return -1;
+ }
+ } else
+ zapfd = STDIN_FILENO;
+
+
+ /* Get channel parameters */
+ memset(&ztp, 0, sizeof(ztp));
+ ztp.channo = -1;
+
+ res = ioctl(zapfd, ZT_GET_PARAMS, &ztp);
+
+ if (res) {
+ fatal("Device '%s' does not appear to be a zaptel device\n", devnam ? devnam : "<stdin>");
+ }
+
+ x = 1;
+
+ /* Throw into HDLC/PPP mode */
+ res = ioctl(zapfd, ZT_HDLCPPP, &x);
+
+ if (res) {
+ fatal("Unable to put device '%s' into HDLC mode\n", devnam);
+ close(zapfd);
+ zapfd = -1;
+ return -1;
+ }
+
+ /* Once the logging is fixed, print a message here indicating
+ connection parameters */
+ zapchan = ztp.channo;
+ info("Connected to zaptel device '%s' (%d)\n", ztp.name, ztp.channo);
+
+ return zapfd;
+}
+
+static void disconnect_zaptel(void)
+{
+ int res;
+ int x = 0;
+ /* Throw out of HDLC mode */
+ res = ioctl(zapfd, ZT_HDLCPPP, &x);
+
+ if (res) {
+ warn("Unable to take device '%s' out of HDLC mode\n", devnam);
+ }
+
+ /* Close if it's not stdin */
+ if (strlen(devnam))
+ close(zapfd);
+ warn("Disconnect from zaptel");
+
+}
+
+
+static int setspeed_zaptel(const char *cp)
+{
+ return 0;
+}
+
+static void zaptel_extra_options()
+{
+ int ret;
+ char buf[256];
+ snprintf(buf, 256, _PATH_ZAPOPT "%s",devnam);
+ if(!options_from_file(buf, 0, 0, 1))
+ exit(EXIT_OPTION_ERROR);
+
+}
+
+
+
+static void send_config_zaptel(int mtu,
+ u_int32_t asyncmap,
+ int pcomp,
+ int accomp)
+{
+ int sock;
+
+ if (mtu > ZAP_MTU) {
+ warn("Couldn't increase MTU to %d.", mtu);
+ mtu = ZAP_MTU;
+ }
+}
+
+
+static void recv_config_zaptel(int mru,
+ u_int32_t asyncmap,
+ int pcomp,
+ int accomp)
+{
+ if (mru > ZAP_MTU)
+ error("Couldn't increase MRU to %d", mru);
+}
+
+static void set_xaccm_pppoe(int unit, ext_accm accm)
+{
+ /* NOTHING */
+}
+
+
+
+struct channel zaptel_channel;
+
+/* Check is cp is a valid zaptel device
+ * return either 1 if "cp" is a reasonable thing to name a device
+ * or die.
+ * Note that we don't actually open the device at this point
+ * We do need to fill in:
+ * devnam: a string representation of the device
+ */
+
+int (*old_setdevname_hook)(const char* cp) = NULL;
+int setdevname_zaptel(const char *cp)
+{
+ int ret;
+ int chan;
+
+ /* If already set, forgoe */
+ if (strlen(devnam))
+ return 1;
+
+
+ if (strcmp(cp, "stdin")) {
+ ret = sscanf(cp, "%d", &chan);
+ if (ret != 1) {
+ fatal("Zaptel: Invalid channel: '%s'\n", cp);
+ return -1;
+ }
+ }
+
+ zap_copy_string(devnam, cp, sizeof(devnam));
+
+ info("Using zaptel device '%s'\n", devnam);
+
+ ret = 1;
+
+ if( ret == 1 && the_channel != &zaptel_channel ){
+
+ the_channel = &zaptel_channel;
+
+ modem = 0;
+
+ lcp_allowoptions[0].neg_accompression = 0;
+ lcp_wantoptions[0].neg_accompression = 0;
+
+ lcp_allowoptions[0].neg_pcompression = 0;
+ lcp_wantoptions[0].neg_pcompression = 0;
+
+ ccp_allowoptions[0].deflate = 0 ;
+ ccp_wantoptions[0].deflate = 0 ;
+
+ ipcp_allowoptions[0].neg_vj=0;
+ ipcp_wantoptions[0].neg_vj=0;
+
+ ccp_allowoptions[0].bsd_compress = 0;
+ ccp_wantoptions[0].bsd_compress = 0;
+
+ lcp_allowoptions[0].neg_asyncmap = 0;
+ lcp_wantoptions[0].neg_asyncmap = 0;
+
+ }
+ return ret;
+}
+
+
+
+void plugin_init(void)
+{
+ if (!ppp_available() && !new_style_driver)
+ fatal("Kernel doesn't support ppp_generic needed for Zaptel PPP");
+ add_options(zaptel_options);
+
+ info("Zaptel Plugin Initialized");
+}
+
+struct channel zaptel_channel = {
+ options: zaptel_options,
+ process_extra_options: &zaptel_extra_options,
+ check_options: NULL,
+ connect: &connect_zaptel,
+ disconnect: &disconnect_zaptel,
+ establish_ppp: &generic_establish_ppp,
+ disestablish_ppp: &generic_disestablish_ppp,
+ send_config: &send_config_zaptel,
+ recv_config: &recv_config_zaptel,
+ close: NULL,
+ cleanup: NULL
+};
+
diff --git a/sethdlc.c b/sethdlc.c
new file mode 100644
index 0000000..09f8348
--- /dev/null
+++ b/sethdlc.c
@@ -0,0 +1,693 @@
+/*
+ * sethdlc.c
+ *
+ * Copyright (C) 1999 - 2002 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <asm/types.h>
+#include <linux/hdlc.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include "kernel/zaptel.h"
+
+#if GENERIC_HDLC_VERSION != 4
+#error Generic HDLC layer version mismatch, please get correct sethdlc.c
+#endif
+
+#if !defined(IF_PROTO_HDLC_ETH) || !defined(IF_PROTO_FR_ETH_PVC)
+#warning "No kernel support for Ethernet over Frame Relay / HDLC, skipping it"
+#endif
+
+
+static struct ifreq req; /* for ioctl */
+static int argc;
+static char **argv;
+int sock;
+
+
+static void error(const char *format, ...) __attribute__ ((noreturn));
+
+static void error(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ fprintf(stderr, "%s: ", req.ifr_name);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ exit(1);
+}
+
+
+
+typedef struct {
+ const char *name;
+ const unsigned int value;
+} parsertab;
+
+
+
+static int checkkey(const char* name)
+{
+ if (argc < 1)
+ return -1; /* no enough parameters */
+
+ if (strcmp(name, argv[0]))
+ return -1;
+ argc--;
+ argv++;
+ return 0;
+}
+
+
+
+static int checktab(parsertab *tab, unsigned int *value)
+{
+ int i;
+
+ if (argc < 1)
+ return -1; /* no enough parameters */
+
+ for (i = 0; tab[i].name; i++)
+ if (!strcmp(tab[i].name, argv[0])) {
+ argc--;
+ argv++;
+ *value = tab[i].value;
+ return 0;
+ }
+
+ return -1; /* Not found */
+}
+
+
+
+static const char* tabstr(unsigned int value, parsertab *tab,
+ const char* unknown)
+{
+ int i;
+ for (i = 0; tab[i].name; i++)
+ if (tab[i].value == value)
+ return tab[i].name;
+
+ return unknown; /* Not found */
+}
+
+
+
+static unsigned int match(const char* name, unsigned int *value,
+ unsigned int minimum, unsigned int maximum)
+{
+ char test;
+
+ if (argc < 1)
+ return -1; /* no enough parameters */
+
+ if (name) {
+ if (strcmp(name, argv[0]))
+ return -1;
+ argc--;
+ argv++;
+ }
+
+ if (argc < 1)
+ error("Missing parameter\n");
+
+ if (sscanf(argv[0], "%u%c", value, &test) != 1)
+ error("Invalid parameter: %s\n", argv[0]);
+
+ if ((*value > maximum) || (*value < minimum))
+ error("Parameter out of range [%u - %u]: %u\n",
+ minimum, maximum, *value);
+
+ argc--;
+ argv++;
+ return 0;
+}
+
+
+static parsertab ifaces[] = {{ "v35", IF_IFACE_V35 },
+ { "v24", IF_IFACE_V24 },
+ { "x21", IF_IFACE_X21 },
+ { "e1", IF_IFACE_E1 },
+ { "t1", IF_IFACE_T1 },
+ { NULL, 0 }};
+
+static parsertab clocks[] = {{ "int", CLOCK_INT },
+ { "ext", CLOCK_EXT },
+ { "txint", CLOCK_TXINT },
+ { "txfromrx", CLOCK_TXFROMRX },
+ { NULL, 0 }};
+
+
+static parsertab protos[] = {{ "hdlc", IF_PROTO_HDLC},
+ { "cisco", IF_PROTO_CISCO},
+ { "fr", IF_PROTO_FR},
+ { "ppp", IF_PROTO_PPP},
+ { "x25", IF_PROTO_X25},
+#ifdef IF_PROTO_HDLC_ETH
+ { "hdlc-eth", IF_PROTO_HDLC_ETH},
+#endif
+ { NULL, 0 }};
+
+
+static parsertab hdlc_enc[] = {{ "nrz", ENCODING_NRZ },
+ { "nrzi", ENCODING_NRZI },
+ { "fm-mark", ENCODING_FM_MARK },
+ { "fm-space", ENCODING_FM_SPACE },
+ { "manchester", ENCODING_MANCHESTER },
+ { NULL, 0 }};
+
+static parsertab hdlc_par[] = {{ "no-parity", PARITY_NONE },
+ { "crc16", PARITY_CRC16_PR1 },
+ { "crc16-pr0", PARITY_CRC16_PR0 },
+ { "crc16-itu", PARITY_CRC16_PR1_CCITT },
+ { "crc16-itu-pr0", PARITY_CRC16_PR0_CCITT },
+ { "crc32-itu", PARITY_CRC32_PR1_CCITT },
+ { NULL, 0 }};
+
+static parsertab lmi[] = {{ "none", LMI_NONE },
+ { "ansi", LMI_ANSI },
+ { "ccitt", LMI_CCITT },
+ { NULL, 0 }};
+
+
+static void set_iface(void)
+{
+ int orig_argc = argc;
+ te1_settings te1;
+
+ memset(&te1, 0, sizeof(te1));
+ req.ifr_settings.type = IF_IFACE_SYNC_SERIAL;
+
+ while (argc > 0) {
+ if (req.ifr_settings.type == IF_IFACE_SYNC_SERIAL)
+ if (!checktab(ifaces, &req.ifr_settings.type))
+ continue;
+
+ if (!te1.clock_type)
+ if (!checkkey("clock")) {
+ if (!checktab(clocks, &te1.clock_type))
+ continue;
+ error("Invalid clock type\n");
+ }
+
+ if (!te1.clock_rate &&
+ (te1.clock_type == CLOCK_INT ||
+ te1.clock_type == CLOCK_TXINT))
+ if (!match("rate", &te1.clock_rate, 1, 0xFFFFFFFF))
+ continue;
+ if (!te1.loopback) {
+ if (!checkkey("loopback") ||
+ !checkkey("lb")) {
+ te1.loopback = 1;
+ continue;
+ }
+ }
+ /* slotmap goes here */
+
+ if (orig_argc == argc)
+ return; /* not an iface definition */
+ error("Invalid parameter: %s\n", argv[0]);
+ }
+
+ if (!te1.clock_rate &&
+ (te1.clock_type == CLOCK_INT ||
+ te1.clock_type == CLOCK_TXINT))
+ te1.clock_rate = 64000;
+
+ /* FIXME stupid hack, will remove it later */
+ req.ifr_settings.ifs_ifsu.te1 = &te1;
+ if (req.ifr_settings.type == IF_IFACE_E1 ||
+ req.ifr_settings.type == IF_IFACE_T1)
+ req.ifr_settings.size = sizeof(te1_settings);
+ else
+ req.ifr_settings.size = sizeof(sync_serial_settings);
+
+ if (ioctl(sock, SIOCWANDEV, &req))
+ error("Unable to set interface information: %s\n",
+ strerror(errno));
+
+ exit(0);
+}
+
+
+
+static void set_proto_fr(void)
+{
+ unsigned int lmi_type = 0;
+ fr_proto fr;
+
+ memset(&fr, 0, sizeof(fr));
+
+ while (argc > 0) {
+ if (!lmi_type)
+ if (!checkkey("lmi")) {
+ if (!checktab(lmi, &lmi_type))
+ continue;
+ error("Invalid LMI type: %s\n",
+ argv[0]);
+ }
+
+ if (lmi_type && lmi_type != LMI_NONE) {
+ if (!fr.dce)
+ if (!checkkey("dce")) {
+ fr.dce = 1;
+ continue;
+ }
+
+ if (!fr.t391)
+ if (!match("t391", &fr.t391,
+ 1, 1000))
+ continue;
+ if (!fr.t392)
+ if (!match("t392", &fr.t392,
+ 1, 1000))
+ continue;
+ if (!fr.n391)
+ if (!match("n391", &fr.n391,
+ 1, 1000))
+ continue;
+ if (!fr.n392)
+ if (!match("n392", &fr.n392,
+ 1, 1000))
+ continue;
+ if (!fr.n393)
+ if (!match("n393", &fr.n393,
+ 1, 1000))
+ continue;
+ }
+ error("Invalid parameter: %s\n", argv[0]);
+ }
+
+ /* polling verification timer*/
+ if (!fr.t391) fr.t391 = 10;
+ /* link integrity verification polling timer */
+ if (!fr.t392) fr.t392 = 15;
+ /* full status polling counter*/
+ if (!fr.n391) fr.n391 = 6;
+ /* error threshold */
+ if (!fr.n392) fr.n392 = 3;
+ /* monitored events count */
+ if (!fr.n393) fr.n393 = 4;
+
+ if (!lmi_type)
+ fr.lmi = LMI_DEFAULT;
+ else
+ fr.lmi = lmi_type;
+
+ req.ifr_settings.ifs_ifsu.fr = &fr;
+ req.ifr_settings.size = sizeof(fr);
+
+ if (ioctl(sock, SIOCWANDEV, &req))
+ error("Unable to set FR protocol information: %s\n",
+ strerror(errno));
+}
+
+
+
+static void set_proto_hdlc(int eth)
+{
+ unsigned int enc = 0, par = 0;
+ raw_hdlc_proto raw;
+
+ memset(&raw, 0, sizeof(raw));
+
+ while (argc > 0) {
+ if (!enc)
+ if (!checktab(hdlc_enc, &enc))
+ continue;
+ if (!par)
+ if (!checktab(hdlc_par, &par))
+ continue;
+
+ error("Invalid parameter: %s\n", argv[0]);
+ }
+
+ if (!enc)
+ raw.encoding = ENCODING_DEFAULT;
+ else
+ raw.encoding = enc;
+
+ if (!par)
+ raw.parity = ENCODING_DEFAULT;
+ else
+ raw.parity = par;
+
+ req.ifr_settings.ifs_ifsu.raw_hdlc = &raw;
+ req.ifr_settings.size = sizeof(raw);
+
+ if (ioctl(sock, SIOCWANDEV, &req))
+ error("Unable to set HDLC%s protocol information: %s\n",
+ eth ? "-ETH" : "", strerror(errno));
+}
+
+
+
+static void set_proto_cisco(void)
+{
+ cisco_proto cisco;
+ memset(&cisco, 0, sizeof(cisco));
+
+ while (argc > 0) {
+ if (!cisco.interval)
+ if (!match("interval", &cisco.interval,
+ 1, 100))
+ continue;
+ if (!cisco.timeout)
+ if (!match("timeout", &cisco.timeout,
+ 1, 100))
+ continue;
+
+ error("Invalid parameter: %s\n",
+ argv[0]);
+ }
+
+ if (!cisco.interval)
+ cisco.interval = 10;
+ if (!cisco.timeout)
+ cisco.timeout = 25;
+
+ req.ifr_settings.ifs_ifsu.cisco = &cisco;
+ req.ifr_settings.size = sizeof(cisco);
+
+ if (ioctl(sock, SIOCWANDEV, &req))
+ error("Unable to set Cisco HDLC protocol information: %s\n",
+ strerror(errno));
+}
+
+
+
+static void set_proto(void)
+{
+ if (checktab(protos, &req.ifr_settings.type))
+ return;
+
+ switch(req.ifr_settings.type) {
+ case IF_PROTO_HDLC: set_proto_hdlc(0); break;
+#ifdef IF_PROTO_HDLC_ETH
+ case IF_PROTO_HDLC_ETH: set_proto_hdlc(1); break;
+#endif
+ case IF_PROTO_CISCO: set_proto_cisco(); break;
+ case IF_PROTO_FR: set_proto_fr(); break;
+
+ case IF_PROTO_PPP:
+ case IF_PROTO_X25:
+ req.ifr_settings.ifs_ifsu.sync = NULL; /* FIXME */
+ req.ifr_settings.size = 0;
+
+ if (!ioctl(sock, SIOCWANDEV, &req))
+ break;
+
+ error("Unable to set %s protocol information: %s\n",
+ req.ifr_settings.type == IF_PROTO_PPP
+ ? "PPP" : "X.25", strerror(errno));
+
+ default: error("Unknown protocol %u\n", req.ifr_settings.type);
+ }
+
+ if (argc > 0)
+ error("Unexpected parameter: %s\n", argv[0]);
+
+ close(sock);
+ exit(0);
+}
+
+
+
+static void set_pvc(void)
+{
+ char *op = argv[0];
+ parsertab ops[] = {{ "create", IF_PROTO_FR_ADD_PVC },
+ { "delete", IF_PROTO_FR_DEL_PVC },
+ { NULL, 0 }};
+ fr_proto_pvc pvc;
+
+ memset(&pvc, 0, sizeof(pvc));
+
+ if (checktab(ops, &req.ifr_settings.type))
+ return;
+
+#ifdef IF_PROTO_FR_ETH_PVC
+ if (!match("ether", &pvc.dlci, 0, 1023)) {
+ if (req.ifr_settings.type == IF_PROTO_FR_ADD_PVC)
+ req.ifr_settings.type = IF_PROTO_FR_ADD_ETH_PVC;
+ else
+ req.ifr_settings.type = IF_PROTO_FR_DEL_ETH_PVC;
+
+ } else
+#endif
+ if (match(NULL, &pvc.dlci, 0, 1023))
+ return;
+
+ if (argc != 0)
+ return;
+
+ req.ifr_settings.ifs_ifsu.fr_pvc = &pvc;
+ req.ifr_settings.size = sizeof(pvc);
+
+ if (ioctl(sock, SIOCWANDEV, &req))
+ error("Unable to %s PVC: %s\n", op, strerror(errno));
+ exit(0);
+}
+
+
+
+static void private(void)
+{
+ if (argc < 1)
+ return;
+
+ if (!strcmp(argv[0], "private")) {
+ if (argc != 1)
+ return;
+ if (ioctl(sock, SIOCDEVPRIVATE, &req))
+ error("SIOCDEVPRIVATE: %s\n", strerror(errno));
+ exit(0);
+ }
+}
+
+
+
+static void show_port(void)
+{
+ const char *s;
+ char buffer[128];
+ const te1_settings *te1 = (void*)buffer;
+ const raw_hdlc_proto *raw = (void*)buffer;
+ const cisco_proto *cisco = (void*)buffer;
+ const fr_proto *fr = (void*)buffer;
+#ifdef IF_PROTO_FR_PVC
+ const fr_proto_pvc_info *pvc = (void*)buffer;
+#endif
+ req.ifr_settings.ifs_ifsu.sync = (void*)buffer; /* FIXME */
+
+ printf("%s: ", req.ifr_name);
+
+ req.ifr_settings.size = sizeof(buffer);
+ req.ifr_settings.type = IF_GET_IFACE;
+
+ if (ioctl(sock, SIOCWANDEV, &req))
+ if (errno != EINVAL) {
+ printf("unable to get interface information: %s\n",
+ strerror(errno));
+ close(sock);
+ exit(1);
+ }
+
+ /* Get and print physical interface settings */
+ if (req.ifr_settings.type == IF_IFACE_SYNC_SERIAL)
+ s = ""; /* Unspecified serial interface */
+ else
+ s = tabstr(req.ifr_settings.type, ifaces, NULL);
+
+ if (!s)
+ printf("unknown interface 0x%x\n", req.ifr_settings.type);
+ else {
+ if (*s)
+ printf("interface %s ", s);
+
+ printf("clock %s", tabstr(te1->clock_type, clocks,
+ "type unknown"));
+ if (te1->clock_type == CLOCK_INT ||
+ te1->clock_type == CLOCK_TXINT)
+ printf(" rate %u", te1->clock_rate);
+
+ if (te1->loopback)
+ printf(" loopback");
+
+ if (req.ifr_settings.type == IF_IFACE_E1 ||
+ req.ifr_settings.type == IF_IFACE_T1) {
+ unsigned int u;
+ printf(" slotmap ");
+ for (u = te1->slot_map; u != 0; u /= 2)
+ printf("%u", u % 2);
+ }
+ printf("\n");
+ }
+
+ /* Get and print protocol settings */
+ do {
+ printf("\t");
+ req.ifr_settings.size = sizeof(buffer);
+ req.ifr_settings.type = IF_GET_PROTO;
+
+ if (ioctl(sock, SIOCWANDEV, &req)) {
+ if (errno == EINVAL)
+ printf("no protocol set\n");
+ else
+ printf("unable to get protocol information: "
+ "%s\n", strerror(errno));
+ break;
+ }
+
+ switch(req.ifr_settings.type) {
+ case IF_PROTO_FR:
+ printf("protocol fr lmi %s",
+ tabstr(fr->lmi, lmi, "unknown"));
+ if (fr->lmi == LMI_ANSI ||
+ fr->lmi == LMI_CCITT)
+ printf("%s t391 %u t392 %u n391 %u n392 %u "
+ "n393 %u\n",
+ fr->dce ? " dce" : "",
+ fr->t391,
+ fr->t392,
+ fr->n391,
+ fr->n392,
+ fr->n393);
+ else
+ putchar('\n');
+ break;
+
+#ifdef IF_PROTO_FR_PVC
+ case IF_PROTO_FR_PVC:
+ printf("Frame-Relay PVC: DLCI %u, master device %s\n",
+ pvc->dlci, pvc->master);
+ break;
+#endif
+
+#ifdef IF_PROTO_FR_ETH_PVC
+ case IF_PROTO_FR_ETH_PVC:
+ printf("Frame-Relay PVC (Ethernet emulation): DLCI %u,"
+ " master device %s\n", pvc->dlci, pvc->master);
+ break;
+#endif
+
+ case IF_PROTO_HDLC:
+ printf("protocol hdlc %s %s\n",
+ tabstr(raw->encoding, hdlc_enc, "unknown"),
+ tabstr(raw->parity, hdlc_par, "unknown"));
+ break;
+
+#ifdef IF_PROTO_HDLC_ETH
+ case IF_PROTO_HDLC_ETH:
+ printf("protocol hdlc-eth %s %s\n",
+ tabstr(raw->encoding, hdlc_enc, "unknown"),
+ tabstr(raw->parity, hdlc_par, "unknown"));
+ break;
+#endif
+
+ case IF_PROTO_CISCO:
+ printf("protocol cisco interval %u timeout %u\n",
+ cisco->interval,
+ cisco->timeout);
+ break;
+
+ case IF_PROTO_PPP:
+ printf("protocol ppp\n");
+ break;
+
+ case IF_PROTO_X25:
+ printf("protocol x25\n");
+ break;
+
+ default:
+ printf("unknown protocol %u\n", req.ifr_settings.type);
+ }
+ }while(0);
+
+ close(sock);
+ exit(0);
+}
+
+
+
+static void usage(void)
+{
+ fprintf(stderr, "sethdlc version 1.15\n"
+ "Copyright (C) 2000 - 2003 Krzysztof Halasa <khc@pm.waw.pl>\n"
+ "\n"
+ "Usage: sethdlc INTERFACE [PHYSICAL] [clock CLOCK] [LOOPBACK] "
+ "[slotmap SLOTMAP]\n"
+ " sethdlc INTERFACE [PROTOCOL]\n"
+ " sethdlc INTERFACE create | delete"
+#ifdef IF_PROTO_FR_ETH_PVC
+ " [ether]"
+#endif
+ " DLCI\n"
+ " sethdlc INTERFACE private...\n"
+ "\n"
+ "PHYSICAL := v24 | v35 | x21 | e1 | t1\n"
+ "CLOCK := int [rate RATE] | ext | txint [rate RATE] | txfromrx\n"
+ "LOOPBACK := loopback | lb\n"
+ "\n"
+ "PROTOCOL := hdlc [ENCODING] [PARITY] |\n"
+#ifdef IF_PROTO_HDLC_ETH
+ " hdlc-eth [ENCODING] [PARITY] |\n"
+#endif
+ " cisco [interval val] [timeout val] |\n"
+ " fr [lmi LMI] |\n"
+ " ppp |\n"
+ " x25\n"
+ "\n"
+ "ENCODING := nrz | nrzi | fm-mark | fm-space | manchester\n"
+ "PARITY := no-parity | crc16 | crc16-pr0 | crc16-itu | crc16-itu-pr0 | crc32-itu\n"
+ "LMI := none | ansi [LMI_SPEC] | ccitt [LMI_SPEC]\n"
+ "LMI_SPEC := [dce] [t391 val] [t392 val] [n391 val] [n392 val] [n393 val]\n");
+ exit(0);
+}
+
+
+
+int main(int arg_c, char *arg_v[])
+{
+ argc = arg_c;
+ argv = arg_v;
+
+ if (argc <= 1)
+ usage();
+
+ sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (sock < 0)
+ error("Unable to create socket: %s\n", strerror(errno));
+
+ zap_copy_string(req.ifr_name, argv[1], sizeof(req.ifr_name)); /* Device name */
+
+ if (argc == 2)
+ show_port();
+
+ argc -= 2;
+ argv += 2;
+
+ set_iface();
+ set_proto();
+ set_pvc();
+ private();
+
+ close(sock);
+ usage();
+ exit(0);
+}
diff --git a/timertest.c b/timertest.c
new file mode 100644
index 0000000..3a0c2e4
--- /dev/null
+++ b/timertest.c
@@ -0,0 +1,54 @@
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int x = 8000;
+ int res;
+ fd_set fds;
+ struct timeval orig, now;
+ fd = open("/dev/zap/timer", O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open timer: %s\n", strerror(errno));
+ exit(1);
+ }
+ printf("Opened timer...\n");
+ if (ioctl(fd, ZT_TIMERCONFIG, &x)) {
+ fprintf(stderr, "Unable to set timer: %s\n", strerror(errno));
+ exit(1);
+ }
+ printf("Set timer duration to %d samples (%d ms)\n", x, x/8);
+ printf("Waiting...\n");
+ gettimeofday(&orig, NULL);
+ for(;;) {
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ res = select(fd + 1, NULL, NULL, &fds, NULL);
+ if (res != 1) {
+ fprintf(stderr, "Unexpected result %d: %s\n", res, strerror(errno));
+ exit(1);
+ }
+ x = -1;
+ if (ioctl(fd, ZT_TIMERACK, &x)) {
+ fprintf(stderr, "Unable to ack timer: %s\n", strerror(errno));
+ exit(1);
+ }
+ gettimeofday(&now, NULL);
+ printf("Timer Expired (%ld ms)!\n", (now.tv_sec - orig.tv_sec) * 1000 + (now.tv_usec - orig.tv_usec) / 1000);
+ }
+ exit(0);
+}
diff --git a/tonezone.c b/tonezone.c
new file mode 100644
index 0000000..f48cf88
--- /dev/null
+++ b/tonezone.c
@@ -0,0 +1,512 @@
+/*
+ * BSD Telephony Of Mexico "Tormenta" Tone Zone Support 2/22/01
+ *
+ * Working with the "Tormenta ISA" Card
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under thet erms of the GNU Lesser 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 Lesser 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.
+ *
+ * Primary Author: Mark Spencer <markster@digium.com>
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "kernel/zaptel.h"
+#include "tonezone.h"
+
+#define DEFAULT_ZT_DEV "/dev/zap/ctl"
+
+#define MAX_SIZE 16384
+#define CLIP 32635
+#define BIAS 0x84
+
+struct tone_zone *tone_zone_find(char *country)
+{
+ struct tone_zone *z;
+ z = builtin_zones;
+ while(z->zone > -1) {
+ if (!strcasecmp(country, z->country))
+ return z;
+ z++;
+ }
+ return NULL;
+}
+
+struct tone_zone *tone_zone_find_by_num(int id)
+{
+ struct tone_zone *z;
+ z = builtin_zones;
+ while(z->zone > -1) {
+ if (z->zone == id)
+ return z;
+ z++;
+ }
+ return NULL;
+}
+
+#define LEVEL -10
+
+static int build_tone(void *data, int size, struct tone_zone_sound *t, int *count)
+{
+ char *dup, *s;
+ struct zt_tone_def *td=NULL;
+ int firstnobang = -1;
+ int freq1, freq2, time;
+ int modulate = 0;
+ float gain;
+ int used = 0;
+ dup = strdup(t->data);
+ s = strtok(dup, ",");
+ while(s && strlen(s)) {
+ /* Handle optional ! which signifies don't start here*/
+ if (s[0] == '!')
+ s++;
+ else if (firstnobang < 0) {
+#if 0
+ printf("First no bang: %s\n", s);
+#endif
+ firstnobang = *count;
+ }
+ if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &time) == 3) {
+ /* f1+f2/time format */
+#if 0
+ printf("f1+f2/time format: %d, %d, %d\n", freq1, freq2, time);
+#endif
+ } else if (sscanf(s, "%d*%d/%d", &freq1, &freq2, &time) == 3) {
+ /* f1*f2/time format */
+ modulate = 1;
+#if 0
+ printf("f1+f2/time format: %d, %d, %d\n", freq1, freq2, time);
+#endif
+ } else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) {
+#if 0
+ printf("f1+f2 format: %d, %d\n", freq1, freq2);
+#endif
+ time = 0;
+ } else if (sscanf(s, "%d*%d", &freq1, &freq2) == 2) {
+ modulate = 1;
+#if 0
+ printf("f1+f2 format: %d, %d\n", freq1, freq2);
+#endif
+ time = 0;
+ } else if (sscanf(s, "%d/%d", &freq1, &time) == 2) {
+#if 0
+ printf("f1/time format: %d, %d\n", freq1, time);
+#endif
+ freq2 = 0;
+ } else if (sscanf(s, "%d", &freq1) == 1) {
+#if 0
+ printf("f1 format: %d\n", freq1);
+#endif
+ firstnobang = *count;
+ freq2 = 0;
+ time = 0;
+ } else {
+ fprintf(stderr, "tone component '%s' of '%s' is a syntax error\n", s,t->data);
+ return -1;
+ }
+#if 0
+ printf("Using %d samples for %d and %d\n", time * 8, freq1, freq2);
+#endif
+ if (size < sizeof(*td)) {
+ fprintf(stderr, "Not enough space for tones\n");
+ return -1;
+ }
+ td = data;
+
+ /* Bring it down -8 dbm */
+ gain = pow(10.0, (LEVEL - 3.14) / 20.0) * 65536.0 / 2.0;
+
+ td->fac1 = 2.0 * cos(2.0 * M_PI * (freq1 / 8000.0)) * 32768.0;
+ td->init_v2_1 = sin(-4.0 * M_PI * (freq1 / 8000.0)) * gain;
+ td->init_v3_1 = sin(-2.0 * M_PI * (freq1 / 8000.0)) * gain;
+
+ td->fac2 = 2.0 * cos(2.0 * M_PI * (freq2 / 8000.0)) * 32768.0;
+ td->init_v2_2 = sin(-4.0 * M_PI * (freq2 / 8000.0)) * gain;
+ td->init_v3_2 = sin(-2.0 * M_PI * (freq2 / 8000.0)) * gain;
+
+ td->modulate = modulate;
+
+ data += sizeof(*td);
+ used += sizeof(*td);
+ size -= sizeof(*td);
+ td->tone = t->toneid;
+ if (time) {
+ /* We should move to the next tone */
+ td->next = *count + 1;
+ td->samples = time * 8;
+ } else {
+ /* Stay with us */
+ td->next = *count;
+ td->samples = 8000;
+ }
+ *count += 1;
+ s = strtok(NULL, ",");
+ }
+ if (td && time) {
+ /* If we don't end on a solid tone, return */
+ td->next = firstnobang;
+ }
+ if (firstnobang < 0)
+ fprintf(stderr, "tone '%s' does not end with a solid tone or silence (all tone components have an exclamation mark)\n", t->data);
+
+ return used;
+}
+
+char *tone_zone_tone_name(int id)
+{
+ static char tmp[80];
+ switch(id) {
+ case ZT_TONE_DIALTONE:
+ return "Dialtone";
+ case ZT_TONE_BUSY:
+ return "Busy";
+ case ZT_TONE_RINGTONE:
+ return "Ringtone";
+ case ZT_TONE_CONGESTION:
+ return "Congestion";
+ case ZT_TONE_CALLWAIT:
+ return "Call Waiting";
+ case ZT_TONE_DIALRECALL:
+ return "Dial Recall";
+ case ZT_TONE_RECORDTONE:
+ return "Record Tone";
+ case ZT_TONE_CUST1:
+ return "Custom 1";
+ case ZT_TONE_CUST2:
+ return "Custom 2";
+ case ZT_TONE_INFO:
+ return "Special Information";
+ case ZT_TONE_STUTTER:
+ return "Stutter Dialtone";
+ default:
+ snprintf(tmp, sizeof(tmp), "Unknown tone %d", id);
+ return tmp;
+ }
+}
+
+#ifdef TONEZONE_DRIVER
+static void dump_tone_zone(void *data, int size)
+{
+ struct zt_tone_def_header *z;
+ struct zt_tone_def *td;
+ int x;
+ int len = sizeof(*z);
+
+ z = data;
+ data += sizeof(*z);
+ printf("Header: %d tones, %d bytes of data, zone %d (%s)\n",
+ z->count, size, z->zone, z->name);
+ for (x = 0; x < z->count; x++) {
+ td = data;
+ printf("Tone Fragment %d: tone is %d, next is %d, %d samples\n",
+ x, td->tone, td->next, td->samples);
+ data += sizeof(*td);
+ len += sizeof(*td);
+ }
+ printf("Total measured bytes of data: %d\n", len);
+}
+#endif
+
+/* Tone frequency tables */
+struct mf_tone {
+ int tone;
+ float f1; /* first freq */
+ float f2; /* second freq */
+};
+
+static struct mf_tone dtmf_tones[] = {
+ { ZT_TONE_DTMF_0, 941.0, 1336.0 },
+ { ZT_TONE_DTMF_1, 697.0, 1209.0 },
+ { ZT_TONE_DTMF_2, 697.0, 1336.0 },
+ { ZT_TONE_DTMF_3, 697.0, 1477.0 },
+ { ZT_TONE_DTMF_4, 770.0, 1209.0 },
+ { ZT_TONE_DTMF_5, 770.0, 1336.0 },
+ { ZT_TONE_DTMF_6, 770.0, 1477.0 },
+ { ZT_TONE_DTMF_7, 852.0, 1209.0 },
+ { ZT_TONE_DTMF_8, 852.0, 1336.0 },
+ { ZT_TONE_DTMF_9, 852.0, 1477.0 },
+ { ZT_TONE_DTMF_s, 941.0, 1209.0 },
+ { ZT_TONE_DTMF_p, 941.0, 1477.0 },
+ { ZT_TONE_DTMF_A, 697.0, 1633.0 },
+ { ZT_TONE_DTMF_B, 770.0, 1633.0 },
+ { ZT_TONE_DTMF_C, 852.0, 1633.0 },
+ { ZT_TONE_DTMF_D, 941.0, 1633.0 },
+ { 0, 0, 0 }
+};
+
+static struct mf_tone mfr1_tones[] = {
+ { ZT_TONE_MFR1_0, 1300.0, 1500.0 },
+ { ZT_TONE_MFR1_1, 700.0, 900.0 },
+ { ZT_TONE_MFR1_2, 700.0, 1100.0 },
+ { ZT_TONE_MFR1_3, 900.0, 1100.0 },
+ { ZT_TONE_MFR1_4, 700.0, 1300.0 },
+ { ZT_TONE_MFR1_5, 900.0, 1300.0 },
+ { ZT_TONE_MFR1_6, 1100.0, 1300.0 },
+ { ZT_TONE_MFR1_7, 700.0, 1500.0 },
+ { ZT_TONE_MFR1_8, 900.0, 1500.0 },
+ { ZT_TONE_MFR1_9, 1100.0, 1500.0 },
+ { ZT_TONE_MFR1_KP, 1100.0, 1700.0 }, /* KP */
+ { ZT_TONE_MFR1_ST, 1500.0, 1700.0 }, /* ST */
+ { ZT_TONE_MFR1_STP, 900.0, 1700.0 }, /* KP' or ST' */
+ { ZT_TONE_MFR1_ST2P, 1300.0, 1700.0 }, /* KP'' or ST'' */
+ { ZT_TONE_MFR1_ST3P, 700.0, 1700.0 }, /* KP''' or ST''' */
+ { 0, 0, 0 }
+};
+
+static struct mf_tone mfr2_fwd_tones[] = {
+ { ZT_TONE_MFR2_FWD_1, 1380.0, 1500.0 },
+ { ZT_TONE_MFR2_FWD_2, 1380.0, 1620.0 },
+ { ZT_TONE_MFR2_FWD_3, 1500.0, 1620.0 },
+ { ZT_TONE_MFR2_FWD_4, 1380.0, 1740.0 },
+ { ZT_TONE_MFR2_FWD_5, 1500.0, 1740.0 },
+ { ZT_TONE_MFR2_FWD_6, 1620.0, 1740.0 },
+ { ZT_TONE_MFR2_FWD_7, 1380.0, 1860.0 },
+ { ZT_TONE_MFR2_FWD_8, 1500.0, 1860.0 },
+ { ZT_TONE_MFR2_FWD_9, 1620.0, 1860.0 },
+ { ZT_TONE_MFR2_FWD_10, 1740.0, 1860.0 },
+ { ZT_TONE_MFR2_FWD_11, 1380.0, 1980.0 },
+ { ZT_TONE_MFR2_FWD_12, 1500.0, 1980.0 },
+ { ZT_TONE_MFR2_FWD_13, 1620.0, 1980.0 },
+ { ZT_TONE_MFR2_FWD_14, 1740.0, 1980.0 },
+ { ZT_TONE_MFR2_FWD_15, 1860.0, 1980.0 },
+ { 0, 0, 0 }
+};
+
+static struct mf_tone mfr2_rev_tones[] = {
+ { ZT_TONE_MFR2_REV_1, 1020.0, 1140.0 },
+ { ZT_TONE_MFR2_REV_2, 900.0, 1140.0 },
+ { ZT_TONE_MFR2_REV_3, 900.0, 1020.0 },
+ { ZT_TONE_MFR2_REV_4, 780.0, 1140.0 },
+ { ZT_TONE_MFR2_REV_5, 780.0, 1020.0 },
+ { ZT_TONE_MFR2_REV_6, 780.0, 900.0 },
+ { ZT_TONE_MFR2_REV_7, 660.0, 1140.0 },
+ { ZT_TONE_MFR2_REV_8, 660.0, 1020.0 },
+ { ZT_TONE_MFR2_REV_9, 660.0, 900.0 },
+ { ZT_TONE_MFR2_REV_10, 660.0, 780.0 },
+ { ZT_TONE_MFR2_REV_11, 540.0, 1140.0 },
+ { ZT_TONE_MFR2_REV_12, 540.0, 1020.0 },
+ { ZT_TONE_MFR2_REV_13, 540.0, 900.0 },
+ { ZT_TONE_MFR2_REV_14, 540.0, 780.0 },
+ { ZT_TONE_MFR2_REV_15, 540.0, 660.0 },
+ { 0, 0, 0 }
+};
+
+static int build_mf_tones(void *data, int size, int *count, struct mf_tone *tone, int low_tone_level, int high_tone_level)
+{
+ struct zt_tone_def *td;
+ float gain;
+ int used = 0;
+
+ while (tone->tone) {
+ if (size < sizeof(*td)) {
+ fprintf(stderr, "Not enough space for samples\n");
+ return -1;
+ }
+ td = data;
+ data += sizeof(*td);
+ used += sizeof(*td);
+ size -= sizeof(*td);
+ td->tone = tone->tone;
+ *count += 1;
+
+ /* Bring it down 6 dBm */
+ gain = pow(10.0, (low_tone_level - 3.14) / 20.0) * 65536.0 / 2.0;
+ td->fac1 = 2.0 * cos(2.0 * M_PI * (tone->f1 / 8000.0)) * 32768.0;
+ td->init_v2_1 = sin(-4.0 * M_PI * (tone->f1 / 8000.0)) * gain;
+ td->init_v3_1 = sin(-2.0 * M_PI * (tone->f1 / 8000.0)) * gain;
+
+ gain = pow(10.0, (high_tone_level - 3.14) / 20.0) * 65536.0 / 2.0;
+ td->fac2 = 2.0 * cos(2.0 * M_PI * (tone->f2 / 8000.0)) * 32768.0;
+ td->init_v2_2 = sin(-4.0 * M_PI * (tone->f2 / 8000.0)) * gain;
+ td->init_v3_2 = sin(-2.0 * M_PI * (tone->f2 / 8000.0)) * gain;
+
+ tone++;
+ }
+
+ return used;
+}
+
+int tone_zone_register_zone(int fd, struct tone_zone *z)
+{
+ char buf[MAX_SIZE];
+ int res;
+ int count = 0;
+ int x;
+ int space = MAX_SIZE;
+ void *ptr = buf;
+ int iopenedit = 1;
+ struct zt_tone_def_header *h;
+
+ memset(buf, 0, sizeof(buf));
+
+ h = ptr;
+ ptr += sizeof(*h);
+ space -= sizeof(*h);
+ h->zone = z->zone;
+
+ zap_copy_string(h->name, z->description, sizeof(h->name));
+
+ for (x = 0; x < ZT_MAX_CADENCE; x++)
+ h->ringcadence[x] = z->ringcadence[x];
+
+ for (x = 0; x < ZT_TONE_MAX; x++) {
+ if (!strlen(z->tones[x].data))
+ continue;
+
+#if 0
+ printf("Tone: %d, string: %s\n", z->tones[x].toneid, z->tones[x].data);
+#endif
+ if ((res = build_tone(ptr, space, &z->tones[x], &count)) < 0) {
+ fprintf(stderr, "Tone %d not built.\n", x);
+ return -1;
+ }
+ ptr += res;
+ space -= res;
+ }
+
+ if ((res = build_mf_tones(ptr, space, &count, dtmf_tones, z->dtmf_low_level, z->dtmf_high_level)) < 0) {
+ fprintf(stderr, "Could not build DTMF tones.\n");
+ return -1;
+ }
+ ptr += res;
+ space -= res;
+
+ if ((res = build_mf_tones(ptr, space, &count, mfr1_tones, z->mfr1_level, z->mfr1_level)) < 0) {
+ fprintf(stderr, "Could not build MFR1 tones.\n");
+ return -1;
+ }
+ ptr += res;
+ space -= res;
+
+ if ((res = build_mf_tones(ptr, space, &count, mfr2_fwd_tones, z->mfr2_level, z->mfr2_level)) < 0) {
+ fprintf(stderr, "Could not build MFR2 FWD tones.\n");
+ return -1;
+ }
+ ptr += res;
+ space -= res;
+
+ if ((res = build_mf_tones(ptr, space, &count, mfr2_rev_tones, z->mfr2_level, z->mfr2_level)) < 0) {
+ fprintf(stderr, "Could not build MFR2 REV tones.\n");
+ return -1;
+ }
+ ptr += res;
+ space -= res;
+
+ h->count = count;
+
+ if (fd < 0) {
+ if ((fd = open(DEFAULT_ZT_DEV, O_RDWR)) < 0) {
+ fprintf(stderr, "Unable to open %s and fd not provided\n", DEFAULT_ZT_DEV);
+ return -1;
+ }
+ iopenedit = 1;
+ }
+
+ x = z->zone;
+ if ((res = ioctl(fd, ZT_FREEZONE, &x))) {
+ if (errno != EBUSY)
+ fprintf(stderr, "ioctl(ZT_FREEZONE) failed: %s\n", strerror(errno));
+ return res;
+ }
+
+#if defined(TONEZONE_DRIVER)
+ dump_tone_zone(h, MAX_SIZE - space);
+#endif
+
+ if ((res = ioctl(fd, ZT_LOADZONE, h))) {
+ fprintf(stderr, "ioctl(ZT_LOADZONE) failed: %s\n", strerror(errno));
+ return res;
+ }
+
+ if (iopenedit)
+ close(fd);
+
+ return res;
+}
+
+int tone_zone_register(int fd, char *country)
+{
+ struct tone_zone *z;
+ z = tone_zone_find(country);
+ if (z) {
+ return tone_zone_register_zone(-1, z);
+ } else {
+ return -1;
+ }
+}
+
+int tone_zone_set_zone(int fd, char *country)
+{
+ int res=-1;
+ struct tone_zone *z;
+ if (fd > -1) {
+ z = tone_zone_find(country);
+ if (z)
+ res = ioctl(fd, ZT_SETTONEZONE, &z->zone);
+ if ((res < 0) && (errno == ENODATA)) {
+ tone_zone_register_zone(fd, z);
+ res = ioctl(fd, ZT_SETTONEZONE, &z->zone);
+ }
+ }
+ return res;
+}
+
+int tone_zone_get_zone(int fd)
+{
+ int x=-1;
+ if (fd > -1) {
+ ioctl(fd, ZT_GETTONEZONE, &x);
+ return x;
+ }
+ return -1;
+}
+
+int tone_zone_play_tone(int fd, int tone)
+{
+ struct tone_zone *z;
+ int res = -1;
+ int zone;
+
+#if 0
+ fprintf(stderr, "Playing tone %d (%s) on %d\n", tone, tone_zone_tone_name(tone), fd);
+#endif
+ if (fd > -1) {
+ res = ioctl(fd, ZT_SENDTONE, &tone);
+ if ((res < 0) && (errno == ENODATA)) {
+ ioctl(fd, ZT_GETTONEZONE, &zone);
+ z = tone_zone_find_by_num(zone);
+ if (z) {
+ res = tone_zone_register_zone(fd, z);
+ /* Recall the zone */
+ ioctl(fd, ZT_SETTONEZONE, &zone);
+ if (res < 0) {
+ fprintf(stderr, "Failed to register zone '%s': %s\n", z->description, strerror(errno));
+ } else {
+ res = ioctl(fd, ZT_SENDTONE, &tone);
+ }
+ } else
+ fprintf(stderr, "Don't know anything about zone %d\n", zone);
+ }
+ }
+ return res;
+}
diff --git a/tonezone.h b/tonezone.h
new file mode 100644
index 0000000..ca795f6
--- /dev/null
+++ b/tonezone.h
@@ -0,0 +1,86 @@
+/*
+ * BSD Telephony Of Mexico "Tormenta" Tone Zone Support 2/22/01
+ *
+ * Working with the "Tormenta ISA" Card
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser 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 Lesser 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.
+ *
+ * Primary Author: Mark Spencer <markster@linux-support.net>
+ *
+ */
+
+#ifndef _TONEZONE_H
+#define _TONEZONE_H
+
+#ifdef STANDALONE_ZAPATA
+#include "kernel/zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+struct tone_zone_sound {
+ int toneid;
+ char data[256]; /* Actual zone description */
+ /* Description is a series of tones of the format:
+ [!]freq1[+freq2][/time] separated by commas. There
+ are no spaces. The sequence is repeated back to the
+ first tone description not preceeded by !. time is
+ specified in milliseconds */
+};
+
+struct tone_zone {
+ int zone; /* Zone number */
+ char country[10]; /* Country code */
+ char description[40]; /* Description */
+ int ringcadence[ZT_MAX_CADENCE]; /* Ring cadence */
+ struct tone_zone_sound tones[ZT_TONE_MAX];
+ int dtmf_high_level; /* Power level of high frequency component
+ of DTMF, expressed in dBm0. */
+ int dtmf_low_level; /* Power level of low frequency component
+ of DTMF, expressed in dBm0. */
+ int mfr1_level; /* Power level of MFR1, expressed in dBm0. */
+ int mfr2_level; /* Power level of MFR2, expressed in dBm0. */
+};
+
+extern struct tone_zone builtin_zones[];
+
+/* Register a given two-letter tone zone if we can */
+int tone_zone_register(int fd, char *country);
+
+/* Register a given two-letter tone zone if we can */
+int tone_zone_register_zone(int fd, struct tone_zone *z);
+
+/* Retrieve a raw tone zone structure */
+struct tone_zone *tone_zone_find(char *country);
+
+/* Retrieve a raw tone zone structure by id instead of country*/
+struct tone_zone *tone_zone_find_by_num(int id);
+
+/* Retrieve a string name for a given tone id */
+char *tone_zone_tone_name(int id);
+
+/* Set a given file descriptor into a given country -- USE THIS
+ INTERFACE INSTEAD OF THE IOCTL ITSELF. Auto-loads tone
+ zone if necessary */
+int tone_zone_set_zone(int fd, char *country);
+
+/* Get the current tone zone */
+int tone_zone_get_zone(int fd);
+
+/* Play a given tone, loading tone zone automatically
+ if necessary */
+int tone_zone_play_tone(int fd, int toneid);
+
+#endif
diff --git a/zonedata.c b/zonedata.c
new file mode 100644
index 0000000..7cb2938
--- /dev/null
+++ b/zonedata.c
@@ -0,0 +1,931 @@
+/*
+ * BSD Telephony Of Mexico "Tormenta" Tone Zone Support 2/22/01
+ *
+ * Working with the "Tormenta ISA" Card
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under thet erms of the GNU Lesser 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 Lesser 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.
+ *
+ * Primary Author: Mark Spencer <markster@digium.com>
+ *
+ * This information from ITU E.180 Supplement 2.
+ * UK information from BT SIN 350 Issue 1.1
+ * Helpful reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf
+ */
+#include "tonezone.h"
+
+struct tone_zone builtin_zones[] =
+{
+ { .zone = 0,
+ .country = "us",
+ .description = "United States / North America",
+ .ringcadence = { 2000, 4000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "350+440" },
+ { ZT_TONE_BUSY, "480+620/500,0/500" },
+ { ZT_TONE_RINGTONE, "440+480/2000,0/4000" },
+ { ZT_TONE_CONGESTION, "480+620/250,0/250" },
+ { ZT_TONE_CALLWAIT, "440/300,0/10000" },
+ { ZT_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+ { ZT_TONE_STUTTER, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 1,
+ .country = "au",
+ .description = "Australia",
+ .ringcadence = { 400, 200, 400, 2000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "413+438" },
+ { ZT_TONE_BUSY, "425/375,0/375" },
+ { ZT_TONE_RINGTONE, "413+438/400,0/200,413+438/400,0/2000" },
+ /* XXX Congestion: Should reduce by 10 db every other cadence XXX */
+ { ZT_TONE_CONGESTION, "425/375,0/375,420/375,0/375" },
+ { ZT_TONE_CALLWAIT, "425/100,0/200,425/200,0/4400" },
+ { ZT_TONE_DIALRECALL, "413+428" },
+ { ZT_TONE_RECORDTONE, "!425/1000,!0/15000,425/360,0/15000" },
+ { ZT_TONE_INFO, "425/2500,0/500" },
+ { ZT_TONE_STUTTER, "413+438/100,0/40" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 2,
+ .country = "fr",
+ .description = "France",
+ .ringcadence = { 1500, 3500 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ /* Dialtone can also be 440+330 */
+ { ZT_TONE_DIALTONE, "440" },
+ { ZT_TONE_BUSY, "440/500,0/500" },
+ { ZT_TONE_RINGTONE, "440/1500,0/3500" },
+ /* CONGESTION - not specified */
+ { ZT_TONE_CONGESTION, "440/250,0/250" },
+ { ZT_TONE_CALLWAIT, "440/300,0/10000" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+ { ZT_TONE_STUTTER, "!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,440" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 3,
+ .country = "nl",
+ .description = "Netherlands",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ /* Most of these 425's can also be 450's */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/250,0/250" },
+ { ZT_TONE_CALLWAIT, "425/500,0/9500" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "425/500,0/50" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 4,
+ .country = "uk",
+ .description = "United Kingdom",
+ .ringcadence = { 400, 200, 400, 2000 },
+ .tones = {
+ /* From British Telecom SIN350 v1.2 */
+ { ZT_TONE_DIALTONE, "350+440" },
+ { ZT_TONE_BUSY, "400/375,0/375" },
+ { ZT_TONE_RINGTONE, "400+450/400,0/200,400+450/400,0/2000" },
+ { ZT_TONE_CONGESTION, "400/400,0/350,400/225,0/525" },
+ { ZT_TONE_CALLWAIT, "400/100,0/4000" },
+ { ZT_TONE_DIALRECALL, "350+440" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/60000" },
+ { ZT_TONE_INFO, "950/330,0/15,1400/330,0/15,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "350+440/750,440/750" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -13,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 5,
+ .country = "fi",
+ .description = "Finland",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/300,0/300" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/200,0/200" },
+ { ZT_TONE_CALLWAIT, "425/150,0/150,425/150,0/8000" },
+ { ZT_TONE_DIALRECALL, "425/650,0/25" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "950/650,0/325,950/325,0/30,1400/1300,0/2600" },
+ { ZT_TONE_STUTTER, "425/650,0/25" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 6,
+ .country = "es",
+ .description = "Spain",
+ .ringcadence = { 1500, 3000},
+ .tones = {
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/200,0/200" },
+ { ZT_TONE_RINGTONE, "425/1500,0/3000" },
+ { ZT_TONE_CONGESTION, "425/200,0/200,425/200,0/200,425/200,0/600" },
+ { ZT_TONE_CALLWAIT, "425/175,0/175,425/175,0/3500" },
+ { ZT_TONE_DIALRECALL, "!425/200,!0/200,!425/200,!0/200,!425/200,!0/200,425" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "950/330,0/1000" },
+ { ZT_TONE_STUTTER, "425/500,0/50" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -13,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 7,
+ .country = "jp",
+ .description = "Japan",
+ .ringcadence = { 1000, 2000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "400" },
+ { ZT_TONE_BUSY, "400/500,0/500" },
+ { ZT_TONE_RINGTONE, "400+15/1000,0/2000" },
+ { ZT_TONE_CONGESTION, "400/500,0/500" },
+ { ZT_TONE_CALLWAIT, "400+16/500,0/8000" },
+ { ZT_TONE_DIALRECALL, "!400/200,!0/200,!400/200,!0/200,!400/200,!0/200,400" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+ { ZT_TONE_STUTTER, "!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400" },
+ },
+ .dtmf_high_level = -7,
+ .dtmf_low_level = -7,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 8,
+ .country = "no",
+ .description = "Norway",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/200,0/200" },
+ { ZT_TONE_CALLWAIT, "425/200,0/600,425/200,0/10000" },
+ { ZT_TONE_DIALRECALL, "470/400,425/400" },
+ { ZT_TONE_RECORDTONE, "1400/400,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+ { ZT_TONE_STUTTER, "470/400,425/400" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 9,
+ .country = "at",
+ .description = "Austria",
+ .ringcadence = { 1000, 5000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "420" },
+ { ZT_TONE_BUSY, "420/400,0/400" },
+ { ZT_TONE_RINGTONE, "420/1000,0/5000" },
+ { ZT_TONE_CONGESTION, "420/200,0/200" },
+ { ZT_TONE_CALLWAIT, "420/40,0/1960" },
+ { ZT_TONE_DIALRECALL, "420" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/80,0/14920" },
+ { ZT_TONE_INFO, "950/330,1450/330,1850/330,0/1000" },
+ { ZT_TONE_STUTTER, "380+420" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 10,
+ .country = "nz",
+ .description = "New Zealand",
+ .ringcadence = { 400, 200, 400, 2000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "400" },
+ { ZT_TONE_BUSY, "400/500,0/500" },
+ { ZT_TONE_RINGTONE, "400+450/400,0/200,400+450/400,0/2000" },
+ { ZT_TONE_CONGESTION, "400/250,0/250" },
+ { ZT_TONE_CALLWAIT, "400/250,0/250,400/250,0/3250" },
+ { ZT_TONE_DIALRECALL, "!400/100!0/100,!400/100,!0/100,!400/100,!0/100,400" },
+ { ZT_TONE_RECORDTONE, "1400/425,0/15000" },
+ { ZT_TONE_INFO, "400/750,0/100,400/750,0/100,400/750,0/100,400/750,0/400" },
+ { ZT_TONE_STUTTER, "!400/100!0/100,!400/100,!0/100,!400/100,!0/100,!400/100!0/100,!400/100,!0/100,!400/100,!0/100,400" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 11,
+ .country = "it",
+ .description = "Italy",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425/200,0/200,425/600,0/1000" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/200,0/200" },
+ { ZT_TONE_CALLWAIT, "425/400,0/100,425/250,0/100,425/150,0/14000" },
+ { ZT_TONE_DIALRECALL, "470/400,425/400" },
+ { ZT_TONE_RECORDTONE, "1400/400,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+ { ZT_TONE_STUTTER, "470/400,425/400" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 12,
+ .country = "us-old",
+ .description = "United States Circa 1950 / North America",
+ .ringcadence = { 2000, 4000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "600*120" },
+ { ZT_TONE_BUSY, "500*100/500,0/500" },
+ { ZT_TONE_RINGTONE, "420*40/2000,0/4000" },
+ { ZT_TONE_CONGESTION, "500*100/250,0/250" },
+ { ZT_TONE_CALLWAIT, "440/300,0/10000" },
+ { ZT_TONE_DIALRECALL, "!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,600*120" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+ { ZT_TONE_STUTTER, "!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,600*120" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 13,
+ .country = "gr",
+ .description = "Greece",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "425/200,0/300,425/700,0/800" },
+ { ZT_TONE_BUSY, "425/300,0/300" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/200,0/200" },
+ { ZT_TONE_CALLWAIT, "425/150,0/150,425/150,0/8000" },
+ { ZT_TONE_DIALRECALL, "425/650,0/25" },
+ { ZT_TONE_RECORDTONE, "1400/400,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+ { ZT_TONE_STUTTER, "425/650,0/25" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 14,
+ .country = "tw",
+ .description = "Taiwan",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "350+440" },
+ { ZT_TONE_BUSY, "480+620/500,0/500" },
+ { ZT_TONE_RINGTONE, "440+480/1000,0/2000" },
+ { ZT_TONE_CONGESTION, "480+620/250,0/250" },
+ { ZT_TONE_CALLWAIT, "350+440/250,0/250,350+440/250,0/3250" },
+ { ZT_TONE_DIALRECALL, "300/1500,0/500" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+ { ZT_TONE_STUTTER, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 15,
+ .country = "cl",
+ .description = "Chile",
+ .ringcadence = { 1000, 3000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "400" },
+ { ZT_TONE_BUSY, "400/500,0/500" },
+ { ZT_TONE_RINGTONE, "400/1000,0/3000" },
+ { ZT_TONE_CONGESTION, "400/200,0/200" },
+ { ZT_TONE_CALLWAIT, "400/250,0/8750" },
+ { ZT_TONE_DIALRECALL, "!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/333,!1400/333,!1800/333,0" },
+ { ZT_TONE_STUTTER, "!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 16,
+ .country = "se",
+ .description = "Sweden",
+ .ringcadence = { 1000, 5000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/250,0/250" },
+ { ZT_TONE_RINGTONE, "425/1000,0/5000" },
+ { ZT_TONE_CONGESTION, "425/250,0/750" },
+ { ZT_TONE_CALLWAIT, "425/200,0/500,425/200,0/9100" },
+ { ZT_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,"
+ "!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,"
+ "!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,"
+ "!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,"
+ "!950/332,!0/24,!1400/332,!0/24,!1800/332,0" },
+ /*{ ZT_TONE_STUTTER, "425/320,0/20" }, Real swedish standard, not used for now */
+ { ZT_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ },
+ .dtmf_high_level = -9,
+ .dtmf_low_level = -10,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 17,
+ .country = "be",
+ .description = "Belgium",
+ .ringcadence = { 1000, 3000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/1000,0/3000" },
+ { ZT_TONE_CONGESTION, "425/167,0/167" },
+ { ZT_TONE_CALLWAIT, "1400/175,0/175,1400/175,0/3500" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "900/330,1400/330,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "425/1000,0/250" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 18,
+ .country = "sg",
+ .description = "Singapore",
+ .ringcadence = { 400, 200, 400, 2000 },
+ .tones = {
+ /* Reference: http://www.ida.gov.sg/idaweb/doc/download/I397/ida_ts_pstn1_i4r2.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/750,0/750" },
+ { ZT_TONE_RINGTONE, "425*24/400,0/200,425*24/400,0/2000" },
+ { ZT_TONE_CONGESTION, "425/250,0/250" },
+ { ZT_TONE_CALLWAIT, "425*24/300,0/200,425*24/300,0/3200" },
+ /* DIALRECALL - not specified - use repeating Holding Tone A,B*/
+ { ZT_TONE_DIALRECALL, "425*24/500,0/500,425/500,0/2500" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,425" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 19,
+ .country = "il",
+ .description = "Israel",
+ .ringcadence = { 1000, 3000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "414" },
+ { ZT_TONE_BUSY, "414/500,0/500" },
+ { ZT_TONE_RINGTONE, "414/1000,0/3000" },
+ { ZT_TONE_CONGESTION, "414/250,0/250" },
+ { ZT_TONE_CALLWAIT, "414/100,0/100,414/100,0/100,414/600,0/3000" },
+ { ZT_TONE_DIALRECALL, "!414/100,!0/100,!414/100,!0/100,!414/100,!0/100,414" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "1000/330,1400/330,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,414" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 20,
+ .country = "br",
+ .description = "Brazil",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/250,0/250" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/250,0/250,425/750,0/250" },
+ { ZT_TONE_CALLWAIT, "425/50,0/1000" },
+ { ZT_TONE_DIALRECALL, "350+440" },
+ { ZT_TONE_RECORDTONE, "425/250,0/250" },
+ { ZT_TONE_INFO, "950/330,1400/330,1800/330" },
+ { ZT_TONE_STUTTER, "350+440" } },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -12,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 21,
+ .country = "hu",
+ .description = "Hungary",
+ .ringcadence = { 1250, 3750 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/300,0/300" },
+ { ZT_TONE_RINGTONE, "425/1250,0/3750" },
+ { ZT_TONE_CONGESTION, "425/300,0/300" },
+ { ZT_TONE_CALLWAIT, "425/40,0/1960" },
+ { ZT_TONE_DIALRECALL, "425+450" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/400,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+ { ZT_TONE_STUTTER, "350+375+400" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 22,
+ .country = "lt",
+ .description = "Lithuania",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/350,0/350" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/200,0/200" },
+ { ZT_TONE_CALLWAIT, "425/150,0/150,425/150,0/4000" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+ /* STUTTER not specified */
+ { ZT_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 23,
+ .country = "pl",
+ .description = "Poland",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/500,0/500" },
+ { ZT_TONE_CALLWAIT, "425/150,0/150,425/150,0/4000" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,0" },
+ /* STUTTER not specified */
+ { ZT_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 24,
+ .country = "za",
+ .description = "South Africa",
+ .ringcadence = { 400, 200, 400, 2000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "400*33" },
+ { ZT_TONE_BUSY, "400/500,0/500" },
+ { ZT_TONE_RINGTONE, "400*33/400,0/200,400*33/400,0/2000" },
+ { ZT_TONE_CONGESTION, "400/250,0/250" },
+ { ZT_TONE_CALLWAIT, "400*33/250,0/250,400*33/250,0/250,400*33/250,0/250,400*33/250,0/250" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "350+440" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+ /* STUTTER not specified */
+ { ZT_TONE_STUTTER, "!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,400*33" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -13,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 25,
+ .country = "pt",
+ .description = "Portugal",
+ .ringcadence = { 1000, 5000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/1000,0/5000" },
+ { ZT_TONE_CONGESTION, "425/200,0/200" },
+ { ZT_TONE_CALLWAIT, "425/200,425/200,425/200,0/5000" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "425/1000,0/200" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+ /* STUTTER not specified */
+ { ZT_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 26,
+ .country = "ee",
+ .description = "Estonia",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/300,0/300" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/200,0/200" },
+ { ZT_TONE_CALLWAIT, "950/650,0/325,950/325,0/30,1400/1300,0/2600" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "425/650,0/25" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "950/0,0/325,950/325,0/30,1400/1300,0/2600" },
+ /* STUTTER not specified */
+ { ZT_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 27,
+ .country = "mx",
+ .description = "Mexico",
+ .ringcadence = { 2000, 4000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/250,0/250" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/250,0/250" },
+ { ZT_TONE_CALLWAIT, "425/200,0/600,425/200,0/10000" },
+ { ZT_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "950/330,0/30,1400/330,0/30,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ },
+ .dtmf_high_level = -8,
+ .dtmf_low_level = -6,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 28,
+ .country = "in",
+ .description = "India",
+ .ringcadence = { 400, 200, 400, 2000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "400*25" },
+ { ZT_TONE_BUSY, "400/750,0/750" },
+ { ZT_TONE_RINGTONE, "400*25/400,0/200,400*25/400,0/2000" },
+ { ZT_TONE_CONGESTION, "400/250,0/250" },
+ { ZT_TONE_CALLWAIT, "400/200,0/100,400/200,0/7500" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ /* INFO - not specified */
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,0/1000" },
+ /* STUTTER - not specified */
+ { ZT_TONE_STUTTER, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 29,
+ .country = "de",
+ .description = "Germany",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/480,0/480" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/240,0/240" },
+ { ZT_TONE_CALLWAIT, "!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,0" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/80,0/15000" },
+ { ZT_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "425+400" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 30,
+ .country = "ch",
+ .description = "Switzerland",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/200,0/200" },
+ { ZT_TONE_CALLWAIT, "425/200,0/200,425/200,0/4000" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/80,0/15000" },
+ { ZT_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "425+340/1100,0/1100" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 31,
+ .country = "dk",
+ .description = "Denmark",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/200,0/200" },
+ { ZT_TONE_CALLWAIT, "!425/200,!0/600,!425/200,!0/3000,!425/200,!0/200,!425/200,0" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/80,0/15000" },
+ { ZT_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+ /* STUTTER - not specified */
+ { ZT_TONE_STUTTER, "425/450,0/50" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 32,
+ .country = "cz",
+ .description = "Czech Republic",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425/330,0/330,425/660,0/660" },
+ { ZT_TONE_BUSY, "425/330,0/330" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/165,0/165" },
+ { ZT_TONE_CALLWAIT, "425/330,0/9000" },
+ /* DIALRECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425/330,0/330,425/660,0/660" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/14000" },
+ { ZT_TONE_INFO, "950/330,0/30,1400/330,0/30,1800/330,0/1000" },
+ /* STUTTER - not specified */
+ { ZT_TONE_STUTTER, "425/450,0/50" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 33,
+ .country = "cn",
+ .description = "China",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "450" },
+ { ZT_TONE_BUSY, "450/350,0/350" },
+ { ZT_TONE_RINGTONE, "450/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "450/700,0/700" },
+ { ZT_TONE_CALLWAIT, "450/400,0/4000" },
+ { ZT_TONE_DIALRECALL, "450" },
+ { ZT_TONE_RECORDTONE, "950/400,0/10000" },
+ { ZT_TONE_INFO, "450/100,0/100,450/100,0/100,450/100,0/100,450/400,0/400" },
+ /* STUTTER - not specified */
+ { ZT_TONE_STUTTER, "450+425" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 34,
+ .country = "ar",
+ .description = "Argentina",
+ .ringcadence = { 1000, 4500 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/300,0/300" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4500" },
+ { ZT_TONE_CONGESTION, "425/200,0/300" },
+ { ZT_TONE_CALLWAIT, "425/200,0/9000" },
+ { ZT_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425/330,0/330,425/660,0/660" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/14000" },
+ { ZT_TONE_INFO, "425/100,0/100" },
+ { ZT_TONE_STUTTER, "425/450,0/50" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 35,
+ .country = "my",
+ .description = "Malaysia",
+ .ringcadence = { 400, 200, 400, 2000 },
+ .tones = {
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/400,0/200,425/400,0/2000" },
+ { ZT_TONE_CONGESTION, "425/500,0/500" },
+ { ZT_TONE_CALLWAIT, "425/100,0/4000" },
+ { ZT_TONE_DIALRECALL, "350+440" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/60000" },
+ { ZT_TONE_INFO, "950/330,0/15,1400/330,0/15,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "450+425" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 36,
+ .country = "th",
+ .description = "Thailand",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "400*50" },
+ { ZT_TONE_BUSY, "400/500,0/500" },
+ { ZT_TONE_RINGTONE, "400/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "400/300,0/300" },
+ { ZT_TONE_CALLWAIT, "1000/400,10000/400,1000/400" },
+ /* DIALRECALL - not specified - use special dial tone instead. */
+ { ZT_TONE_DIALRECALL, "400*50/400,0/100,400*50/400,0/100" },
+ /* RECORDTONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ /* INFO - specified as an announcement - use tones instead. */
+ { ZT_TONE_INFO, "950/330,1400/330,1800/330" },
+ /* STUTTER - not specified */
+ { ZT_TONE_STUTTER, "!400/200,!0/200,!400/600,!0/200,!400/200,!0/200,!400/600,!0/200,!400/200,!0/200,!400/600,!0/200,!400/200,!0/200,!400/600,!0/200,400" },
+ },
+ .dtmf_high_level = -11,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 37,
+ .country = "bg",
+ .description = "Bulgaria",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/250,0/250" },
+ { ZT_TONE_CALLWAIT, "425/150,0/150,425/150,0/4000" },
+ { ZT_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ { ZT_TONE_RECORDTONE, "1400/425,0/15000" },
+ { ZT_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "425/1500,0/100" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 38,
+ .country = "ve",
+ .description = "Venezuela",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/500,0/500" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/250,0/250" },
+ { ZT_TONE_CALLWAIT, "400+450/300,0/6000" },
+ { ZT_TONE_DIALRECALL, "425" },
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ { ZT_TONE_INFO, "!950/330,!1440/330,!1800/330,0/1000" },
+ /* STUTTER - not specified */
+ { ZT_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ },
+ .dtmf_high_level = -7,
+ .dtmf_low_level = -9,
+ .mfr1_level = -7,
+ .mfr2_level = -8,
+ },
+ { .zone = 39,
+ .country = "ph",
+ .description = "Philippines",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "480+620/500,0/500" },
+ { ZT_TONE_RINGTONE, "425+480/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "480+620/250,0/250" },
+ { ZT_TONE_CALLWAIT, "440/300,0/10000" },
+ /* DIAL RECALL - not specified */
+ { ZT_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ /* RECORD TONE - not specified */
+ { ZT_TONE_RECORDTONE, "1400/500,0/15000" },
+ /* INFO TONE - not specified */
+ { ZT_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+ /* STUTTER TONE - not specified */
+ { ZT_TONE_STUTTER, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = 40,
+ .country = "ru",
+ .description = "Russian Federation",
+ .ringcadence = { 1000, 4000 },
+ .tones = {
+ /* References:
+ http://www.minsvyaz.ru/site.shtml?id=1806
+ http://www.aboutphone.info/lib/gost/45-223-2001.html */
+ { ZT_TONE_DIALTONE, "425" },
+ { ZT_TONE_BUSY, "425/350,0/350" },
+ { ZT_TONE_RINGTONE, "425/1000,0/4000" },
+ { ZT_TONE_CONGESTION, "425/175,0/175" },
+ { ZT_TONE_CALLWAIT, "425/200,0/5000" },
+ { ZT_TONE_RECORDTONE, "1400/400,0/15000" },
+ { ZT_TONE_INFO, "950/330,1440/330,1800/330,0/1000" },
+ { ZT_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+ },
+ .dtmf_high_level = -10,
+ .dtmf_low_level = -10,
+ .mfr1_level = -10,
+ .mfr2_level = -8,
+ },
+ { .zone = -1 }
+};