summaryrefslogtreecommitdiff
path: root/kernel/xpp/utils
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/xpp/utils')
-rw-r--r--kernel/xpp/utils/Makefile38
-rwxr-xr-xkernel/xpp/utils/astribank_hook61
-rw-r--r--kernel/xpp/utils/genconf_parameters114
-rwxr-xr-xkernel/xpp/utils/genzaptelconf11
-rwxr-xr-xkernel/xpp/utils/migrate_xpp102
-rw-r--r--kernel/xpp/utils/print_modes.c22
-rw-r--r--kernel/xpp/utils/test_parse.c22
-rwxr-xr-xkernel/xpp/utils/waitfor_xpds54
-rwxr-xr-xkernel/xpp/utils/xpp_sync26
-rwxr-xr-xkernel/xpp/utils/zapconf667
-rwxr-xr-xkernel/xpp/utils/zaptel_drivers151
-rw-r--r--kernel/xpp/utils/zconf/Zaptel.pm2
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Chans.pm10
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Config/Defaults.pm12
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Config/Gen.pm212
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Config/Gen/Unicall.pm70
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Config/Gen/Users.pm177
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Config/Gen/Zapata.pm213
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Config/Gen/Zaptel.pm158
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Config/Params.pm149
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Hardware/PCI.pm7
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Span.pm71
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Xpp.pm125
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm68
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm148
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm244
-rwxr-xr-xkernel/xpp/utils/zt_registration69
27 files changed, 2203 insertions, 800 deletions
diff --git a/kernel/xpp/utils/Makefile b/kernel/xpp/utils/Makefile
index 2a12166..b88bb75 100644
--- a/kernel/xpp/utils/Makefile
+++ b/kernel/xpp/utils/Makefile
@@ -1,6 +1,5 @@
PEDANTIC = -ansi -pedantic -std=c99
-RANLIB = ranlib
INSTALL = install
INSTALL_DATA = install -m 644
@@ -36,8 +35,8 @@ PERL_MODS_PAT := *.pm $(PERL_DIRS:%=%/*.pm)
PERL_MODS := $(shell cd zconf; echo $(PERL_MODS_PAT))
XPD_FIRMWARE = $(wildcard ../firmwares/*.hex)
-XPD_INIT_DATA = $(XPD_FIRMWARE) init_fxo_modes
-XPD_INIT = $(wildcard ../init_card_?_*) xpp_fxloader
+XPD_INIT_DATA = $(XPD_FIRMWARE) init_fxo_modes ../XppConfig.pm
+XPD_INIT = $(wildcard ../init_card_?_*) xpp_fxloader waitfor_xpds zaptel_drivers
# Variables that should be defined above, but need sane defaults:
# FIXME: Are those values really sane?
@@ -49,7 +48,7 @@ ifeq (,$(PBX_LIBUSB))
PBX_LIBUSB = $(shell if [ -r /usr/include/usb.h ]; then echo 1; else echo 0; fi)
endif
-WCTDM=$(shell for i in $(ZAP_KERNEL)/wctdm.c $(ZAP_KERNEL)/fxo_modes.h; do [ -f "$$i" ] && echo "$$i"; done)
+WCTDM=$(shell for i in $(ZAP_KERNEL)/wctdm.c $(ZAP_KERNEL)/fxo_modes.h fxo_modes.h; do [ -f "$$i" ] && echo "$$i"; done)
CFLAGS = -g -Wall $(EXTRA_CFLAGS)
@@ -70,7 +69,8 @@ TARGETS = init_fxo_modes print_modes perlcheck
PROG_INSTALL = genzaptelconf
MAN_INSTALL = $(PROG_INSTALL:%=%.8)
ifeq (1,$(PBX_LIBUSB))
-TARGETS += libhexfile.a fpga_load test_parse
+TARGETS += fpga_load \
+ test_parse
PROG_INSTALL += fpga_load
endif
ifneq (,$(PERLLIBDIR))
@@ -108,28 +108,19 @@ ifneq (,$(PERLLIBDIR))
done
endif
-libhexfile.a: hexfile.o
- $(AR) cru $@ $^
- $(RANLIB) $@
-
-fpga_load: fpga_load.o libhexfile.a
- $(CC) -L. -o $@ $@.o $(EXTRA_LIBS) -lhexfile -lusb
+fpga_load: fpga_load.o hexfile.o
+ $(CC) -L. -o $@ $^ $(EXTRA_LIBS) -lusb
fpga_load.o: CFLAGS+=-D_GNU_SOURCE # We use memrchr()
-hexfile.o: hexfile.c hexfile.h
- $(CC) $(CFLAGS) $(PEDANTIC) -c $<
-
-test_parse.o: test_parse.c hexfile.h
- $(CC) $(CFLAGS) $(PEDANTIC) -c $<
-
-test_parse: test_parse.o libhexfile.a
- $(CC) -L. -o $@ $@.o $(EXTRA_LIBS) -lhexfile -lusb
+test_parse: test_parse.o hexfile.o
+ $(CC) -L. -o $@ $^ $(EXTRA_LIBS) -lusb
print_modes: print_modes.c wctdm_fxomodes.h
$(HOSTCC) -o $@ $(CFLAGS) $<
wctdm_fxomodes.h: $(WCTDM)
+ @if [ "$(WCTDM)" = "" ]; then echo 1>&2 "WCTDM is not defined. Aborting."; exit 1; fi
@echo Building FXO modes from: $(WCTDM)
perl -n -e 'print if (/^static struct fxo_mode {$$/ .. /};$$/)' $(WCTDM) >$@ || rm -f $@
@@ -141,4 +132,11 @@ perlcheck: $(PERL_SCRIPTS)
touch $@
clean:
- $(RM) *.o $(TARGETS) wctdm_fxomodes.h
+ $(RM) .depend *.o $(TARGETS) wctdm_fxomodes.h
+
+.PHONY: depend
+depend: .depend
+.depend: *.c *.h wctdm_fxomodes.h
+ @$(CC) -MM *.c > $@ || rm -f $@
+
+include .depend
diff --git a/kernel/xpp/utils/astribank_hook b/kernel/xpp/utils/astribank_hook
index 8dd13c9..9510f7b 100755
--- a/kernel/xpp/utils/astribank_hook
+++ b/kernel/xpp/utils/astribank_hook
@@ -1,57 +1,42 @@
#! /bin/sh
-# This is an example of an Astribank device hook. The xpp.rules file
-# calls /usr/share/zaptel/astribank_hook after a new Astribank is ready
-# and after and old Astribank device has been destroyed.
-#
-
-set -e
-
me=`basename $0`
-INIT_DIR=`dirname $0`
-XPP_BASE=/proc/xpp
-export XPP_BASE
-LOGGER="logger -s -t $me"
-
-ZAPTEL_BOOT_DEBIAN=${ZAPTEL_BOOT_DEBIAN:-/etc/default/zaptel}
-ZAPTEL_BOOT_FEDORA=${ZAPTEL_BOOT_FEDORA:-/etc/sysconfig/zaptel}
-
-# read default configuration from /etc/default/zaptel
-if [ -r $ZAPTEL_BOOT_DEBIAN ]; then . $ZAPTEL_BOOT_DEBIAN; fi
-if [ -r $ZAPTEL_BOOT_FEDORA ]; then . $ZAPTEL_BOOT_FEDORA; fi
-
-if [ "$ASTRIBANK_HOOK_DISABLED" != '' ]; then
- $LOGGER -p kern.info "Exiting... ASTRIBANK_HOOK_DISABLED"
- exit 0
-fi
+dir=`dirname $0`
+LOGGER="logger -i -t '$me'"
# Always redirect stderr somewhere, otherwise the shell script will die
# when it tries to do I/O related stuff on closed file descriptor.
# Our default is to throw it down the bit-bucket.
#exec 2> /dev/console
## If you wish to trace this script:
-#exec 2> "/tmp/astribank_hook_$XBUS_NAME"
+#exec 2> "/tmp/${me}_$XBUS_NAME" 1>&2
-# Maybe add some logging
-#$LOGGER -p kern.info "$0: $ACTION: $*."
+PATH="$dir:/usr/sbin:/sbin:/usr/bin:/bin"
+
+set -e
+
+echo "starting($ACTION): '$*'" | $LOGGER
case "$ACTION" in
add)
- # An Astribank was added and is initialized and ready.
- # Put your shell commands bellow
- :
;;
remove)
- # An Astribank was Removed.
- # Put your shell commands bellow
- # You should not access /proc/xpp/... or run related utilities
- # like xpp_sync, since this is likely to cause very bad race
- # conditions during driver removal.
- :
;;
-*)
+online)
+ if [ -x "$dir/twinstar_hook" ]; then
+ "$dir/twinstar_hook"
+ fi
+ ;;
+offline)
+ if [ -x "$dir/twinstar_hook" ]; then
+ "$dir/twinstar_hook"
+ fi
;;
+*)
+ echo "$0: Unknown ACTION='$ACTION'" | $LOGGER
+ echo "$0: ARGS='$*'" | $LOGGER
+ echo "$0: ENV:" | $LOGGER
+ env | $LOGGER
+ exit 1
esac
-# Maybe add some logging
-#$LOGGER -p kern.info "$0: Done: $ACTION: $*."
diff --git a/kernel/xpp/utils/genconf_parameters b/kernel/xpp/utils/genconf_parameters
new file mode 100644
index 0000000..d1b8f62
--- /dev/null
+++ b/kernel/xpp/utils/genconf_parameters
@@ -0,0 +1,114 @@
+#
+# /etc/dahdi/genconf_parameters
+#
+# This file contains parameters that affect the
+# dahdi_genconf configurator generator.
+#
+# Syntax:
+# * A comment from '#' to end of line
+# * Blank lines ignored
+# * Whitespace at end of line trimmed
+# * Single valued items:
+# key <whitespaces...> value
+# * List valued items:
+# key
+# <whitespaces...>value1
+# <whitespaces...>value2
+# ...
+#
+
+# When generating extensions for zapata.conf or users.conf etc: the
+# extension number will be channel_number+base_exten . The default is:
+#base_exten 4000
+#
+# Make FXS (analog phones) extentions answer immediately (sets
+# 'immediate = yes' for them in zapata.conf). Don't enable this before
+# you're read documentation about this option.
+#fxs_immediate yes
+#
+# For FXS (analog phones) - use KS or LS? ks is the only method for
+# Asterisk to provide disconnect supervision and thus it would normally
+# be preffered and is the default.
+#fxs_default_start ls
+#
+# For FXO (analog lines) - use KS or LS? KS is the default and is
+# normally the better choice as it allows detecting handups on many
+# lines.
+#fxo_default_start ls
+
+# Set tone zone values. This is used for playing tones (busy, dialtone
+# and such). The default is 'us'. This sets the value for both loadzone
+# and defaultzone in zaptel.conf .
+#lc_country il
+
+# The dialplan contenxt into which to send trunks in zapata.conf or
+# users.conf. The default value is:
+#context_lines from-pstn
+#
+# The dialplan context into which to send extensions in zapata.conf or
+# users.conf. The default value is:
+#context_phones from-internal
+#
+# Two extea contexts for the input ports and output ports of an
+# Astribank. Default values are:
+#context_input astbank-input
+#context_output astbank-output
+
+# A group to put all analog phones in. By default 0, so you can dial to
+# the 'first phone available' using Zap/g5 .
+#group_phones 5
+#
+# A group in which to put all the channels belonging to some trunk.
+# Thus you can dial through "some trunk" using Zap/G0/NUMBER
+#group_lines 0
+
+# Channels of digital trunk of span N are also added to group 10+N (that
+# is: 14 for channels of span 4).
+
+# Do we want to use PtP ('bri') or PtMP ('bri_ptmp') for BRI? PtMP
+# allows connecting several CPE devices on the same network device
+# (several BRI phones on the same line, kind of like several analog
+# phones on the same analog line). However it is generally brings
+# unnecessary complexity for a pbx-pbx connection. It is still the
+# default as this is normally what you get for a BRI PSTN connection.
+#bri_sig_style bri
+#
+# If this option is set (that is: not remmed-out), BRI NT ports will
+# also be set as overlap. This is useful if you want to connect ISDN
+# phones.
+#brint_overlap
+
+# bri_hardhdlc: If this parameter is set to 'yes', in the entries for
+# BRI cards 'hardhdlc' will be used instead of 'dchan' (an alias for
+# 'fcshdlc').
+#bri_hardhdlc yes
+
+# For MFC/R2 Support: 'R2' will make E1 spans CAS and with the
+# 'r2_idle_bits' bit in zaptel.conf . It will also make zapconf default
+# to generating the channels of this card in unicall.conf rather than in
+# zapata.conf . The meaning of this may be extended somehow to support
+# R2 through openr2/chan_dahdi later on.
+#pri_connection_type R2
+#r2_idle_bits 1101
+
+# pri_termtype contains a list of settings:
+# Currently the only setting is for TE or NT (the default is TE). This
+# sets two different but normally related configuration items:
+#
+# A TE span will have *_cpe signalling in Asterisk and will also get
+# timing from the remote party.
+#
+# A NT span will have *_new signalling in Asterisk and will provide
+# timing to the remote party.
+#
+# pri_termtype is a list if span specs and configuration (TE/NT) for
+# them. The first spec that matches is used. The matching is of perl
+# regular expressions, but with '*' and '?' have their meaning from
+# basic regular expressions.
+#pri_termtype
+# SPAN/2 NT
+# SPAN/4 NT
+#
+#pri_termtype
+# SPAN/* NT
+#
diff --git a/kernel/xpp/utils/genzaptelconf b/kernel/xpp/utils/genzaptelconf
index 163f595..5f28c50 100755
--- a/kernel/xpp/utils/genzaptelconf
+++ b/kernel/xpp/utils/genzaptelconf
@@ -79,6 +79,11 @@ SPAN_GROUP_BASE=10
# and other devices).
brint_overlap=no
+# Wait for all the Astribanks to load.
+# If you don't have latest zaptel, you may need to set this to
+# 'waitfor_xpds_internal'
+WAITFOR_XPDS=${WAITFOR_XPDS:-/usr/share/zaptel/waitfor_xpds}
+
# a temporary directory to store whatever we need to remember.
#
# The main loop of genconf is run in a sub-process.
@@ -265,6 +270,10 @@ zap_reg_xpp() {
done
}
+waitfor_xpds_internal() {
+ cat /proc/xpp/XBUS-[0-9]*/waitfor_xpds 2>/dev/null || true
+}
+
# Initialize the Xorcom Astribank (xpp/)
xpp_startup() {
# do nothing if the module xpp was not loaded, or if no
@@ -273,7 +282,7 @@ xpp_startup() {
if ! grep -q 'STATUS=connected' /proc/xpp/xbuses; then return 0; fi
echo "Waiting for Astribank devices to initialize:"
- cat /proc/xpp/XBUS-[0-9]*/waitfor_xpds 2>/dev/null || true
+ $WAITFOR_XPDS
# overriding locales for the above two, as perl can be noisy
# when locales are missing.
diff --git a/kernel/xpp/utils/migrate_xpp b/kernel/xpp/utils/migrate_xpp
new file mode 100755
index 0000000..98d45e7
--- /dev/null
+++ b/kernel/xpp/utils/migrate_xpp
@@ -0,0 +1,102 @@
+#! /usr/bin/perl -w
+use strict;
+use POSIX;
+#
+# Migrate the information from XPP_PRI_SETUP variable in
+# /etc/sysconig/zaptel or /etc/default/zaptel into the
+# modern configuration:
+# - pri_protocol defined in /etc/xpp.conf
+# - pri_termtype defined in /etc/genconf_parameters
+#
+
+my $conf_rh="/etc/sysconfig/zaptel";
+my $conf_debian="/etc/default/zaptel";
+my $conf;
+my $marker = '##';
+my @origlines;
+my @lines;
+
+if (-f "$conf_rh") {
+ $conf="$conf_rh";
+} elsif (-f "$conf_debian") {
+ $conf="$conf_debian";
+} else {
+ warn "$0: No '$conf_rh' and no '$conf_debian'. Skipping";
+ exit 0;
+}
+
+print STDERR "$0: Reading old config from '$conf'\n";
+open(F, ". $conf; echo \$XPP_PRI_SETUP |") || die "$0: Failed: $!";
+my $line = <F>;
+close F;
+
+sub write_file($@) {
+ my $fname = shift;
+ my @lines = @_;
+
+ open(G, ">$fname.new") || die "$0: Failed opening $fname.new: $!\n";
+ print G @lines;
+ close G;
+ rename($fname, "$fname.backup") ||
+ die "$0: rename($fname, $fname.backup): $!";
+ rename("$fname.new", $fname) ||
+ die "$0: rename($fname.new, $fname): $!";
+}
+
+my @wordlist = split(/\s+/, $line);
+my @spans;
+my $global_pri_protocol;
+foreach my $w (@wordlist) {
+ my ($span, $val) = split(/=/, $w);
+ my ($termtype, $pri_protocol) = split(/,/, $val);
+ if(! defined $global_pri_protocol) {
+ $global_pri_protocol = $pri_protocol;
+ } elsif($global_pri_protocol ne $pri_protocol) {
+ die "different pri_protocol (E1/T1/J1) in different spans\n";
+ }
+ push(@spans, "$span\t$termtype");
+}
+
+my $xppconf = '/etc/xpp.conf';
+print STDERR "$0: Updating PRI protocol in $xppconf\n";
+open(F, "$xppconf") || die "$0: Failed opening $xppconf: $!\n";
+@origlines = <F>;
+close F;
+undef @lines;
+foreach (@origlines) {
+ next if /^#$marker:/;
+ if(s/^pri_protocol.*/pri_protocol\t$global_pri_protocol/) {
+ $_ =
+ "#$marker: Automatically copied from '$conf'\n" .
+ sprintf("#$marker: On %s", ctime(time)) .
+ $_;
+ }
+ push(@lines, $_);
+}
+write_file($xppconf, @lines);
+
+my $genconf = '/etc/genconf_parameters';
+undef @origlines;
+undef @lines;
+print STDERR "$0: Updating PRI termtypes in '$genconf'\n";
+open(F, "$genconf") || die "$0: Failed opening $genconf: $!\n";
+my $in_termtype_block = 0;
+while(<F>) {
+ next if /^#$marker:/;
+ next if $in_termtype_block && /^\s+/;
+ if(/^pri_termtype/) {
+ $in_termtype_block = 1;
+ next;
+ }
+ push(@lines, $_);
+}
+close F;
+my $pri_termtype =
+ "#$marker: Automatically copied from '$conf'\n" .
+ sprintf("#$marker: On %s", ctime(time)) .
+ "pri_termtype\n";
+foreach my $span (@spans) {
+ $pri_termtype .= "\t$span\n";
+}
+push(@lines, $pri_termtype);
+write_file($genconf, @lines);
diff --git a/kernel/xpp/utils/print_modes.c b/kernel/xpp/utils/print_modes.c
index 77e0e33..e6586f0 100644
--- a/kernel/xpp/utils/print_modes.c
+++ b/kernel/xpp/utils/print_modes.c
@@ -1,3 +1,25 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2006, 2007, 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
#include <stdio.h>
#include "wctdm_fxomodes.h"
diff --git a/kernel/xpp/utils/test_parse.c b/kernel/xpp/utils/test_parse.c
index 8ac2023..700a0f7 100644
--- a/kernel/xpp/utils/test_parse.c
+++ b/kernel/xpp/utils/test_parse.c
@@ -1,3 +1,25 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2006, 2007, 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
#include <stdio.h>
#include <stdarg.h>
#include "hexfile.h"
diff --git a/kernel/xpp/utils/waitfor_xpds b/kernel/xpp/utils/waitfor_xpds
new file mode 100755
index 0000000..ebac3a0
--- /dev/null
+++ b/kernel/xpp/utils/waitfor_xpds
@@ -0,0 +1,54 @@
+#! /bin/sh
+
+# waitfor_xpds: wait until all Astribanks were initialized
+
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2008, Xorcom
+#
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+
+set -e
+
+ab_list() {
+ ab=`find /sys/bus/astribanks/devices/xbus-*/ -name waitfor_xpds 2> /dev/null || :`
+ if [ "$ab" = "" ]; then
+ ab=`find /proc/xpp/XBUS-[0-9]*/ -name waitfor_xpds 2> /dev/null || :`
+ procfiles=1
+ fi
+ if [ "$ab" = "" ]; then
+ echo 1>&2 "$0: No XBUSES to wait for. Aborting..."
+ exit 1
+ fi
+ if [ -n "$procfiles" ]; then
+ echo 1>&2 "$0: No /sys attributes, fallback to /proc interface..."
+ fi
+ echo $ab
+}
+
+
+while
+ if ! ab=`ab_list`; then
+ exit 1
+ fi
+ test "$oldab" != "$ab"
+do
+ oldab="$ab"
+ echo 1>&2 "Waiting for XPDS"
+ cat $ab
+done
diff --git a/kernel/xpp/utils/xpp_sync b/kernel/xpp/utils/xpp_sync
index d5b340a..2840271 100755
--- a/kernel/xpp/utils/xpp_sync
+++ b/kernel/xpp/utils/xpp_sync
@@ -51,21 +51,9 @@ sub get_sorted_xpds() {
push(@good_xpds, $xpd);
}
}
- my @pri_nt_xpds = grep { $_->type =~ /(E1|T1|J1)_NT/; } @good_xpds;
- my @pri_te_xpds = grep { $_->type =~ /(E1|T1|J1)_TE/; } @good_xpds;
- my @bri_nt_xpds = grep { $_->type eq 'BRI_NT'; } @good_xpds;
- my @bri_te_xpds = grep { $_->type eq 'BRI_TE'; } @good_xpds;
- my @fxo_xpds = grep { $_->type eq 'FXO'; } @good_xpds;
- my @fxs_xpds = grep { $_->type eq 'FXS'; } @good_xpds;
-
- # Sync Priority
- return
- @pri_te_xpds,
- @bri_te_xpds,
- @fxo_xpds,
- @pri_nt_xpds,
- @bri_nt_xpds,
- @fxs_xpds;
+ my @xpd_prio = Zaptel::Xpp::Xpd::xpds_by_rank(@good_xpds);
+ #Zaptel::Xpp::Xpd::show_xpd_rank(@xpd_prio);
+ return @xpd_prio;
}
sub do_select(@) {
@@ -108,7 +96,7 @@ sub show_sync() {
my $xpdstr = '[ ' . $xbus->pretty_xpds . ' ]';
my $label = '[' . $xbus->label() . ']';
my $connector = '(' . $xbus->connector . ')';
- my $mark = ($curr_sync =~ /\d+/ and $xbus->num == $curr_sync)?"+":"";
+ my $mark = ($curr_sync =~ /^\d+$/ and $xbus->num == $curr_sync)?"+":"";
my $padding = ' ' x (40 - length $xpdstr);
printf " %1s %s %-25s %-14s %s\n", $mark, $xbus->name, $connector, $label, $xpdstr;
}
@@ -131,7 +119,7 @@ END
}
}
-if($sync) {
+if(defined $sync) {
if($autoselect) {
do_select(@sync_xpds);
} else {
@@ -207,8 +195,8 @@ In this example we see that the recommended xpp sync master is XBUS-02 -
it is the first on the list. It is also the actual syncer, as we can see
from the '+' beside it.
-xpp_sync is normally called from both the zaptel init.d script and the
-the Astribank udev script. The parameter it is called with defaults to
+xpp_sync is normally called from the zaptel init.d script.
+The parameter it is called with defaults to
I<auto>, but it is possible to override that parameter (e.g: set it to
I<zaptel>) through the value of XPP_SYNC in either /etc/defualt/zaptel
or /etc/sysconfig/zaptel .
diff --git a/kernel/xpp/utils/zapconf b/kernel/xpp/utils/zapconf
index 78a20b9..ac1af0b 100755
--- a/kernel/xpp/utils/zapconf
+++ b/kernel/xpp/utils/zapconf
@@ -11,555 +11,101 @@ use strict;
use File::Basename;
BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
+use Getopt::Std;
use Zaptel;
use Zaptel::Xpp;
-use Zaptel::Config::Defaults;
-
-my %default_context = (
- FXO => 'from-pstn',
- FXS => 'from-internal',
- IN => 'astbank-input',
- OUT => 'astbank-output',
- BRI_TE => 'from-pstn',
- BRI_NT => 'from-internal',
- E1_TE => 'from-pstn',
- T1_TE => 'from-pstn',
- J1_TE => 'from-pstn',
- E1_NT => 'from-internal',
- T1_NT => 'from-internal',
- J1_NT => 'from-internal',
- );
-
-my %default_group = (
- FXO => 0,
- FXS => "5",
- IN => '',
- OUT => '',
- BRI_TE => 0,
- BRI_NT => 6,
- E1_TE => 0,
- T1_TE => 0,
- J1_TE => 0,
- E1_NT => 6,
- T1_NT => 6,
- J1_NT => 6,
- );
-
-my $fxs_default_start = 'ls';
-
-my %default_zaptel_signalling = (
- FXO => 'fxsks',
- FXS => "fxo{fxs_default_start}",
- IN => "fxo{fxs_default_start}",
- OUT => "fxo{fxs_default_start}",
- );
-
-my %default_zapata_signalling = (
- FXO => 'fxs_ks',
- FXS => "fxo_{fxs_default_start}",
- IN => "fxo_{fxs_default_start}",
- OUT => "fxo_{fxs_default_start}",
- );
-
-my $base_exten = 4000;
-my $fxs_immediate = 'no';
-my $lc_country = 'us';
-my $loadzone = $lc_country;
-my $defaultzone = $lc_country;
-my $bri_sig_style = 'bri_ptmp';
-my $brint_overlap = 'no';
-
-my %zaptel_default_vars = (
- base_exten => \$base_exten,
- fxs_immediate => \$fxs_immediate,
- fxs_default_start => \$fxs_default_start,
- lc_country => [
- \$loadzone,
- \$defaultzone,
- ],
- context_lines => \$default_context{FXO},
- context_phones => \$default_context{FXS},
- context_input => \$default_context{IN},
- context_output => \$default_context{OUT},
- group_phones => [
- \$default_group{FXS},
- \$default_group{IN},
- \$default_group{OUT},
- ],
- group_lines => \$default_group{FXO},
- ZAPBRI_SIGNALLING => \$bri_sig_style,
- brint_overlap => \$brint_overlap,
- );
-
-sub map_zaptel_defaults {
- my %defaults = @_;
- foreach my $name (keys %defaults) {
- my $val = $defaults{$name};
- my $ref = $zaptel_default_vars{$name};
- my $type = ref $ref;
- my @vars = ();
- # Some broken shells (msh) export even variables
- # That where not defined. Work around that.
- next unless defined $val && $val ne '';
- if($type eq 'SCALAR') {
- @vars = ($ref);
- } elsif($type eq 'ARRAY') {
- @vars = @$ref;
- } else {
- die "$0: Don't know how to map '$name' (type=$type)\n";
- }
- foreach my $v (@vars) {
- $$v = $val;
- }
- }
-}
-
-
-my $zapconf_file;
-my $zapatachannels_file;
-my $users_file;
-my $zapataconf_file;
-
-my %files = (
- zaptel => { file => \$zapconf_file, func => \&gen_zaptelconf },
- zapata => { file => \$zapatachannels_file, func => \&gen_zapatachannelsconf },
- users => { file => \$users_file, func => \&gen_usersconf },
- zapataconf => { file => \$zapataconf_file, func => \&gen_zapataconf },
-);
-
-my @default_files = ("zaptel", "zapata");
-
-my @spans = Zaptel::spans();
+use Zaptel::Config::Gen;
+use Zaptel::Config::Params;
-sub bchan_range($) {
- my $span = shift || die;
- my $first_chan = ($span->chans())[0];
- my $first_num = $first_chan->num();
- my $range_start = $first_num;
- my @range;
- my $prev = undef;
-
- die unless $span->is_digital();
- foreach my $c (@{$span->bchan_list()}) {
- my $curr = $c + $first_num;
- if(!defined($prev)) {
- $prev = $curr;
- } elsif($curr != $prev + 1) {
- push(@range, sprintf("%d-%d", $range_start, $prev));
- $range_start = $curr;
- }
- $prev = $curr;
- }
- if($prev >= $first_num) {
- push(@range, sprintf("%d-%d", $range_start, $prev));
- }
- return join(',', @range);
-}
+my $version = '1'; # Functionality version (integer)
+my $revision = '$Revision$';
-sub gen_zaptel_signalling($) {
- my $chan = shift || die;
- my $type = $chan->type;
- my $num = $chan->num;
-
- die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
- if($type eq 'EMPTY') {
- printf "# channel %d, %s, no module.\n", $num, $chan->fqn;
- return;
- }
- my $sig = $default_zaptel_signalling{$type} || die "unknown default zaptel signalling for chan $num type $type";
- if ($type eq 'IN') {
- printf "# astbanktype: input\n";
- } elsif ($type eq 'OUT') {
- printf "# astbanktype: output\n";
- }
- printf "$sig=$num\n";
-}
+my %opts;
-my $bri_te_last_timing = 1;
-
-sub gen_zaptel_digital($) {
- my $span = shift || die;
- my $num = $span->num() || die;
- die "Span #$num is analog" unless $span->is_digital();
- my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
- my $timing;
- my $lbo = 0;
- my $framing = $span->framing() || die "$0: No framing information for span #$num\n";
- my $coding = $span->coding() || die "$0: No coding information for span #$num\n";
- my $span_crc4 = $span->crc4();
- $span_crc4 = (defined $span_crc4) ? ",$span_crc4" : '';
- my $span_yellow = $span->yellow();
- $span_yellow = (defined $span_yellow) ? ",$span_yellow" : '';
-
- $timing = ($termtype eq 'NT') ? 0 : $bri_te_last_timing++;
- printf "span=%d,%d,%d,%s,%s%s%s\n",
- $num,
- $timing,
- $lbo,
- $framing,
- $coding,
- $span_crc4,
- $span_yellow;
- printf "# termtype: %s\n", lc($termtype);
- printf "bchan=%s\n", bchan_range($span);
- my $dchan = $span->dchan();
- printf "dchan=%d\n", $dchan->num();
+sub set_defaults {
+ my $default_file = $ENV{GENCONF_PARAMETERS} || "/etc/genconf_parameters";
+ my $params = Zaptel::Config::Params->new($default_file);
+ #$params->dump;
+ if($opts{v}) {
+ print "Default parameters from ", $params->{GENCONF_FILE}, "\n";
+ }
+ my $gconfig = Zaptel::Config::Gen->new($params);
+ #$gconfig->dump;
+ return $gconfig;
}
-sub gen_zaptelconf($) {
- my $file = shift || die;
- rename "$file", "$file.bak"
- or $! == 2 # ENOENT (No dependency on Errno.pm)
- or die "Failed to backup old config: $!\n";
- open(F, ">$file") || die "$0: Failed to open $file: $!\n";
- my $old = select F;
- printf "# Autogenerated by %s on %s -- do not hand edit\n", $0, scalar(localtime);
- print <<"HEAD";
-# Zaptel Configuration File
-#
-# This file is parsed by the Zaptel Configurator, ztcfg
-#
-HEAD
+sub spans_prep($@) {
+ my $gconfig = shift || die;
+ my @spans = @_;
foreach my $span (@spans) {
- printf "# Span %d: %s %s\n", $span->num, $span->name, $span->description;
- if($span->is_digital()) {
- gen_zaptel_digital($span);
- } else {
- foreach my $chan ($span->chans()) {
- if(1 || !defined $chan->type) {
- my $type = $chan->probe_type;
- my $num = $chan->num;
- die "Failed probing type for channel $num"
- unless defined $type;
- $chan->type($type);
- }
- gen_zaptel_signalling($chan);
- }
+ if($span->is_pri) {
+ $span->pri_set_fromconfig($gconfig);
}
- print "\n";
}
- print <<"TAIL";
-# Global data
-
-loadzone = $loadzone
-defaultzone = $defaultzone
-TAIL
- close F;
- select $old;
}
-my %DefaultConfigs = (
- context => 'default',
- group => '63', # FIXME: should not be needed.
- overlapdial => 'no',
- busydetect => 'no',
- rxgain => 0,
- txgain => 0,
-);
-
-sub reset_zapata_values {
- foreach my $arg (@_) {
- if (exists $DefaultConfigs{$arg}) {
- print "$arg = $DefaultConfigs{$arg}\n";
- } else {
- print "$arg =\n";
- }
- }
-}
+sub generator_list($) {
+ my $gconfig = shift || die;
+ my @genlist;
-sub gen_zapata_digital($) {
- my $span = shift || die;
- my $num = $span->num() || die;
- die "Span #$num is analog" unless $span->is_digital();
- my $type = $span->type() || die "$0: Span #$num -- unkown type\n";
- my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
- my $group = $default_group{"$type"};
- my $context = $default_context{"$type"};
- my @to_reset = qw/context group/;
-
- die "$0: missing default group (termtype=$termtype)\n" unless defined($group);
- die "$0: missing default context\n" unless $context;
-
- my $sig = $span->signalling || die "missing signalling info for span #$num type $type";
- grep($bri_sig_style eq $_, 'bri', 'bri_ptmp', 'pri') or die "unknown signalling style for BRI";
- if($span->is_bri() and $bri_sig_style eq 'bri_ptmp') {
- $sig .= '_ptmp';
- }
- if ($span->is_bri() && $termtype eq 'NT' && $brint_overlap eq 'yes') {
- print "overlapdial = yes\n";
- push(@to_reset, qw/overlapdial/);
- }
-
- $group .= "," . (10 + $num); # Invent unique group per span
- printf "group=$group\n";
- printf "context=$context\n";
- printf "switchtype = %s\n", $span->switchtype;
- printf "signalling = %s\n", $sig;
- printf "channel => %s\n", bchan_range($span);
- reset_zapata_values(@to_reset);
-}
-
-sub gen_zapata_channel($) {
- my $chan = shift || die;
- my $type = $chan->type;
- my $num = $chan->num;
- die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
- my $exten = $base_exten + $num;
- my $sig = $default_zapata_signalling{$type};
- my $context = $default_context{$type};
- my $group = $default_group{$type};
- my $callerid;
- my $immediate;
-
- return if $type eq 'EMPTY';
- die "missing default_zapata_signalling for chan #$num type $type" unless $sig;
- $callerid = ($type eq 'FXO')
- ? 'asreceived'
- : sprintf "\"Channel %d\" <%04d>", $num, $exten;
- if($type eq 'IN') {
- $immediate = 'yes';
- }
- # FIXME: $immediage should not be set for 'OUT' channels, but meanwhile
- # it's better to be compatible with genzaptelconf
- $immediate = 'yes' if $fxs_immediate eq 'yes' and $sig =~ /^fxo_/;
- my $signalling = $chan->signalling;
- $signalling = " " . $signalling if $signalling;
- my $info = $chan->info;
- $info = " " . $info if $info;
- printf ";;; line=\"%d %s%s%s\"\n", $num, $chan->fqn, $signalling, $info;
- printf "signalling=$sig\n";
- printf "callerid=$callerid\n";
- printf "mailbox=%04d\n", $exten unless $type eq 'FXO';
- if(defined $group) {
- printf "group=$group\n";
- }
- printf "context=$context\n";
- printf "immediate=$immediate\n" if defined $immediate;
- printf "channel => %d\n", $num;
- # Reset following values to default
- printf "callerid=\n";
- printf "mailbox=\n" unless $type eq 'FXO';
- if(defined $group) {
- printf "group=\n";
- }
- printf "context=default\n";
- printf "immediate=no\n" if defined $immediate;
- print "\n";
-}
-
-sub gen_zapatachannelsconf($) {
- my $file = shift || die;
- rename "$file", "$file.bak"
- or $! == 2 # ENOENT (No dependency on Errno.pm)
- or die "Failed to backup old config: $!\n";
- open(F, ">$file") || die "$0: Failed to open $file: $!\n";
- my $old = select F;
- printf "; Autogenerated by %s on %s -- do not hand edit\n", $0, scalar(localtime);
- print <<"HEAD";
-; Zaptel Channels Configurations (zapata.conf)
-;
-; This is not intended to be a complete zapata.conf. Rather, it is intended
-; to be #include-d by /etc/zapata.conf that will include the global settings
-;
-
-HEAD
- foreach my $span (@spans) {
- printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
- if($span->is_digital()) {
- gen_zapata_digital($span);
- } else {
- foreach my $chan ($span->chans()) {
- gen_zapata_channel($chan);
- }
+ if (@ARGV) {
+ for my $gen (@ARGV) {
+ push @genlist, $gen;
+ }
+ } else {
+ # No files given. Use the defaults.
+ @genlist = ('zaptel', 'zapata');
+ if($gconfig->{'pri_connection_type'} eq 'R2') {
+ push @genlist, 'unicall';
}
- print "\n";
}
- close F;
- select $old;
+ return @genlist;
}
-sub gen_users_channel($) {
- my $chan = shift || die;
- my $type = $chan->type;
- my $num = $chan->num;
- die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
- my $exten = $base_exten + $num;
- my $sig = $default_zapata_signalling{$type};
- my $full_name = "$type $num";
-
- die "missing default_zapata_signalling for chan #$num type $type" unless $sig;
- print << "EOF";
-[$exten]
-callwaiting = yes
-context = numberplan-custom-1
-fullname = $full_name
-cid_number = $exten
-hasagent = no
-hasdirectory = no
-hasiax = no
-hasmanager = no
-hassip = no
-hasvoicemail = yes
-host = dynamic
-mailbox = $exten
-threewaycalling = yes
-vmsecret = 1234
-secret = 1234
-signalling = $sig
-zapchan = $num
-registeriax = no
-registersip = no
-canreinvite = no
-nat = no
-dtmfmode = rfc2833
-disallow = all
-allow = all
-
-EOF
-}
+sub parse_genopts($) {
+ my $optstr = shift;
+ my %genopts;
-# generate users.conf . The specific users.conf is strictly oriented
-# towards using with the asterisk-gui .
-#
-# This code could have generated a much simpler and smaller
-# configuration file, had there been minimal level of support for
-# configuration templates in the asterisk configuration rewriting. Right
-# now Asterisk's configuration rewriting simply freaks out in the face
-# of templates: http://bugs.digium.com/11442 .
-sub gen_usersconf($) {
- my $file = shift || die;
- rename "$file", "$file.bak"
- or $! == 2 # ENOENT (No dependency on Errno.pm)
- or die "Failed to backup old config: $!\n";
- open(F, ">$file") || die "$0: Failed to open $file: $!\n";
- my $old = select F;
- print <<"HEAD";
-;!
-;! Automatically generated configuration file
-;! Filename: @{[basename($file)]} ($file)
-;! Generator: $0
-;! Creation Date: @{[scalar(localtime)]}
-;!
-[general]
-;
-; Full name of a user
-;
-fullname = New User
-;
-; Starting point of allocation of extensions
-;
-userbase = @{[$base_exten+1]}
-;
-; Create voicemail mailbox and use use macro-stdexten
-;
-hasvoicemail = yes
-;
-; Set voicemail mailbox @{[$base_exten+1]} password to 1234
-;
-vmsecret = 1234
-;
-; Create SIP Peer
-;
-hassip = no
-;
-; Create IAX friend
-;
-hasiax = no
-;
-; Create Agent friend
-;
-hasagent = no
-;
-; Create H.323 friend
-;
-;hash323 = yes
-;
-; Create manager entry
-;
-hasmanager = no
-;
-; Remaining options are not specific to users.conf entries but are general.
-;
-callwaiting = yes
-threewaycalling = yes
-callwaitingcallerid = yes
-transfer = yes
-canpark = yes
-cancallforward = yes
-callreturn = yes
-callgroup = 1
-pickupgroup = 1
-localextenlength = @{[length($base_exten)]}
-
-
-HEAD
- foreach my $span (@spans) {
- next unless grep { $_ eq $span->type} ( 'FXS', 'IN', 'OUT' );
- printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
- foreach my $chan ($span->chans()) {
- gen_users_channel($chan);
- }
- print "\n";
+ $optstr = '' unless defined $optstr;
+ foreach my $o (split(/,/, $optstr)) {
+ my ($k, $v) = split(/=/, $o, 2);
+ $v = 1 unless defined $v and $v;
+ $genopts{$k} = $v;
}
- close F;
- select $old;
+ return %genopts;
}
-sub gen_zapataconf($) {
- my $file = shift || die;
- open(F, ">>$file") || die "$0: Failed to open $file: $!\n";
- my $old = select F;
- foreach my $span (@spans) {
- next unless $span->type eq 'FXO';
- my $current_sig = "";
- for my $chan ($span->chans()) {
- my $chan_num = $chan->num;
- if ($default_zapata_signalling{$chan->type} ne $current_sig) {
- $current_sig = $default_zapata_signalling{$chan->type};
- print "\nsignalling = $current_sig";
- print "\nchannel => $chan_num";
- } else {
- print ",$chan_num";
- }
+sub generate_files($@) {
+ my $gconfig = shift || die;
+ my @spans = @_;
+ my @generators = generator_list($gconfig);
+
+ for my $gen (@generators) {
+ my ($name, $optstr) = split(/=/, $gen, 2);
+ die "Illegal name '$name'\n" unless $name =~ /^\w+$/;
+ $name =~ s/(.)(.*)/\u$1\L$2/;
+ my %genopts = parse_genopts($optstr);
+ $genopts{'freepbx'} = 'yes' if $opts{'F'};
+ if(defined $opts{'v'}) {
+ $genopts{'verbose'} = $opts{v};
}
- print "\n";
- }
- close F;
- select $old;
-}
-
-sub set_defaults {
- # Source default files
- my ($default_file, %source_defaults) =
- Zaptel::Config::Defaults::source_vars(keys(%zaptel_default_vars));
- map_zaptel_defaults(%source_defaults);
- # Fixups
- foreach my $val (values %default_zaptel_signalling, values %default_zapata_signalling) {
- $val =~ s/{fxs_default_start}/$fxs_default_start/g;
+ $gconfig->run_generator($name, \%genopts, @spans);
}
- $zapconf_file = $ENV{ZAPCONF_FILE} || "/etc/zaptel.conf";
- $zapatachannels_file = $ENV{ZAPATA_FILE} || "/etc/asterisk/zapata-channels.conf";
- $users_file = $ENV{USERS_FILE} || "/etc/asterisk/users.conf";
- $zapataconf_file = $ENV{ZAPATACONF_FILE} || "/etc/asterisk/zapata.conf";
}
-sub parse_args {
- return if @ARGV == 0;
- @default_files = ();
- for my $file (@ARGV) {
- die "$0: Unknown file '$file'" unless defined $files{$file};
- push @default_files, $file;
- }
+getopts('vVF', \%opts) || die "$0: Bad option\n";
+if($opts{'V'}) {
+ my $revstr = $revision;
+ $revstr =~ s/[^$]*\$[^:]+:\s*//;
+ $revstr =~ s/\s*\$.*//;
+ print "$0: version=$version revision=$revstr\n";
+ exit 0;
}
-sub generate_files {
- for my $file (@default_files) {
- &{$files{$file}->{func}}(${$files{$file}->{file}});
- }
-}
-set_defaults;
-parse_args;
-generate_files;
+my $gconfig = set_defaults;
+my @spans = Zaptel::spans();
+spans_prep($gconfig, @spans);
+generate_files($gconfig, @spans);
__END__
@@ -569,35 +115,82 @@ zapconf - Generate configuration for zaptel channels.
=head1 SYNOPSIS
-zapconf [FILES...]
+zapconf [options] [generator...]
=head1 DESCRIPTION
This script generate configuration files for Zaptel hardware.
-Currently it can generate three files: zaptel, zapata, users and zapataconf (see below).
-Without arguments, it generates only zaptel and zapata.
+It uses two information sources:
=over 4
-=item zaptel - /etc/zaptel.conf
+=item Hardware
+
+ The actual zaptel hardware is automatically detected on the host.
+
+=item /etc/genconf_params
+
+A configuration file that supplements the hardware information.
+Its location may be overriden via the C<GENCONF_PARAMETERS> environment
+variable.
+
+=back
-Configuration for ztcfg(1). It's location may be overriden by the
-environment variable ZAPCONF_FILE.
+The zapconf script can generate various kinds of configuration files
+as specificed by the generator arguments. Each generator is a perl classes
+in Zaptel::Config::Gen namespace. The generator names on the command line
+are the class names in lowercase.
-=item zapata - /etc/asterisk/zapata-channels.conf
+The following generators are currently implemented: zaptel, zapata, unicall, users.
+For further documentation on each, please user perldoc on the relevant
+class. E.g: C<perldoc Zaptel::Config::Gen::Zapata>
+
+Each generator on the command line may be passed custom options by assigning
+a comma separated list of options to the generator name. E.g:
+
+ zapconf zaptel zapata=verbose unicall
+
+=head2 Global options:
+
+=over 4
+
+=item -V
+
+Version -- print version string and exit.
+
+=item -v
+
+Verbose -- sets the C<'verbose'> option for all generators.
+
+=item -F
+
+Freepbx -- sets the C<'freepbx'> option for all generators.
+Currently, zapata is affected.
+
+
+=back
+
+=head2 Implementation notes:
+
+=over 4
-Configuration for asterisk(1). It should be included in the main /etc/asterisk/zapata.conf.
-It's location may be overriden by the environment variable ZAPATA_FILE.
+=item *
-=item users - /etc/asterisk/users.conf
+F<genconf_parameters> parsing is done via C<Zaptel::Config::Params>.
+An object representing the parsed data is instanciated by:
+C<Zaptel::Config::Params-E<gt>new()>.
+The C<item()> method of this object contains all the hard coded
+defaults of the configuration directives.
-Configuration for asterisk(1) and AsteriskGUI.
-It's location may be overriden by the environment variable USERS_FILE.
+=item *
-=item zapataconf - /etc/asterisk/zapata.conf
+A configuration object is instanciated by C<Zaptel::Config::Gen-E<gt>new($params)>.
+The mapping of configuration directives into semantic configuration is
+done in the constructor.
-Configuration for asterisk(1) and AsteriskGUI.
-It's location may be overriden by the environment variable ZAPATACONF_FILE.
+=item *
+A single generator is run via the the C<run_generator()> method of the
+configuration object.
=back
diff --git a/kernel/xpp/utils/zaptel_drivers b/kernel/xpp/utils/zaptel_drivers
index d7904c0..5ace08b 100755
--- a/kernel/xpp/utils/zaptel_drivers
+++ b/kernel/xpp/utils/zaptel_drivers
@@ -3,7 +3,156 @@ use strict;
use File::Basename;
BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
+use Errno;
+use Getopt::Std;
use Zaptel::Hardware;
+my %opts;
+my $etc_modules = '/etc/modules';
+my $zaptel_redhat = '/etc/sysconfig/zaptel';
+my $zaptel_debian = '/etc/default/zaptel';
+my $zaptel_conffile;
+
+getopts('vdM', \%opts) || die "$0: Bad options\n";
+
+if(-f $zaptel_redhat) {
+ $zaptel_conffile = $zaptel_redhat;
+} elsif(-f $zaptel_debian) {
+ $zaptel_conffile = $zaptel_debian;
+ $opts{'d'} = 1 if $opts{'M'};
+} else {
+ die "$0: Could not find '$zaptel_redhat' nor '$zaptel_debian'\n";
+}
+
my $hardware = Zaptel::Hardware->scan;
-print join("\n", $hardware->drivers),"\n";
+
+sub update_zaptel_distro(@) {
+ my @driver_list = @_;
+ my $varname = 'MODULES';
+ my $newfile = "${zaptel_conffile}.new";
+ my $backupfile = "${zaptel_conffile}.bak";
+
+ print "Updating $zaptel_conffile\n" if $opts{'v'};
+ open(NEWFILE, ">$newfile") || die "$0: Failed to open '$newfile': $!\n";
+ open(BACKUPFILE, ">$backupfile") || die "$0: Failed to open '$backupfile': $!\n";
+ if(open(IN, $zaptel_conffile)) {
+ while(my $line = <IN>) {
+ print BACKUPFILE $line;
+ chomp $line;
+ next if $line =~ /^${varname}=/; # Skip old defs.
+ print NEWFILE "$line\n";
+ }
+ close IN;
+ } elsif(defined($!{ENOENT})) {
+ print "Creating $zaptel_conffile\n" if $opts{'v'};
+ } else {
+ die "$0: Failed opening '$zaptel_conffile': $!\n";
+ }
+ print NEWFILE "${varname}='@driver_list'\n";
+ close NEWFILE;
+ close BACKUPFILE;
+ rename($newfile, $zaptel_conffile) ||
+ die "$0: rename($newfile, $zaptel_conffile) failed: $!\n";
+}
+
+# This is for Debian.
+sub update_etc_modules(@) {
+ my @driver_list = @_;
+ my $newfile = "${etc_modules}.new";
+ my $backupfile = "${etc_modules}.bak";
+ # Just to make module loading order deterministic.
+ my @module_order = qw(
+ wct4xxp
+ wcte12xp
+ wcte11xp
+ wct1xxp
+ wanpipe
+ tor2
+ torisa
+ qozap
+ vzaphfc
+ zaphfc
+ ztgsm
+ wctdm24xxp
+ wctdm
+ opvxa1200
+ wcfxo
+ pciradio
+ wcusb
+ xpp_usb
+ ystdm8xx
+ zma8xx
+ );
+
+ open(NEWFILE, ">$newfile") || die "$0: Failed to open '$newfile': $!\n";
+ open(BACKUPFILE, ">$backupfile") || die "$0: Failed to open '$backupfile': $!\n";
+ if(open(IN, $etc_modules)) {
+ print "Updating $etc_modules\n" if $opts{'v'};
+ while(my $line = <IN>) {
+ print BACKUPFILE $line;
+ chomp $line;
+ next if grep(/^\s*${line}\s*$/, @module_order, @driver_list);
+ print NEWFILE "$line\n";
+ }
+ close IN;
+ } elsif(defined($!{ENOENT})) {
+ print "Creating $etc_modules\n" if $opts{'v'};
+ } else {
+ die "$0: Failed opening '$etc_modules': $!\n";
+ }
+ foreach my $d (@module_order) {
+ print NEWFILE "$d\n" if grep($d eq $_, @driver_list);
+ }
+ close NEWFILE;
+ close BACKUPFILE;
+ rename($newfile, $etc_modules) ||
+ die "$0: rename($newfile, $etc_modules) failed: $!\n";
+}
+
+if($opts{'d'}) {
+ update_etc_modules($hardware->drivers);
+}
+if($opts{'M'}) {
+ update_zaptel_distro($hardware->drivers);
+}
+
+if(!$opts{'d'} && !$opts{'M'}) {
+ print join("\n", $hardware->drivers),"\n";
+}
+
+__END__
+
+=head1 NAME
+
+zaptel_drivers - Show drivers required for installed zaptel devices.
+
+=head1 SYNOPSIS
+
+zaptel_drivers [-vdM]
+
+=head1 DESCRIPTION
+
+This script shows by default the list of drivers required for currently
+installed zaptel devices.
+
+Options:
+
+=over 4
+
+=item -v
+
+Verbose
+
+=item -d
+
+Generate /etc/modules for Debian systems.
+
+=item -M
+
+Generate distribution dependent module configuration file:
+ /etc/sysconfig/zaptel # For RedHat like systems
+ /etc/default/zaptel # For Debian like systems
+
+On debian systems, specifying this option turns on the '-d' option as well.
+
+=back
diff --git a/kernel/xpp/utils/zconf/Zaptel.pm b/kernel/xpp/utils/zconf/Zaptel.pm
index 431689e..1b73d5b 100644
--- a/kernel/xpp/utils/zconf/Zaptel.pm
+++ b/kernel/xpp/utils/zconf/Zaptel.pm
@@ -25,7 +25,7 @@ hardware and loaded Zaptel devices.
my @spans = Zaptel::spans();
for my $span (@spans) {
next if ($span->is_digital);
- $span->num. " - [". $span->type ."] ". $span->name. "\n";
+ $span->num. " - [". $span->type ."] ". $span->name. "\n";
for my $chan ($span->chans) {
print " - ".$chan->num . " - [". $chan->type. "] ". $chan->fqn". \n";
}
diff --git a/kernel/xpp/utils/zconf/Zaptel/Chans.pm b/kernel/xpp/utils/zconf/Zaptel/Chans.pm
index 53ed277..aa58d1d 100644
--- a/kernel/xpp/utils/zconf/Zaptel/Chans.pm
+++ b/kernel/xpp/utils/zconf/Zaptel/Chans.pm
@@ -149,18 +149,19 @@ sub new($$$$$$) {
# WP[TE]1: Sangoma. TODO: this one tells us if it is TE or NT.
# cwain: Junghanns E1 card.
$type = "PRI";
- } elsif ($fqn =~ m{\b(ZTHFC%d*|ztqoz\d*)/.*}) {
+ } elsif ($fqn =~ m{\b(B4|ZTHFC\d*|ztqoz\d*)/.*}) {
+ # B4: The Digium wcb4xxp ZAPTEL driver
# ZTHFC: HFC-s single-port card (zaphfc/vzaphfc)
# ztqoz: qozap (Junghanns) multi-port HFC card
$type = "BRI";
} elsif ($fqn =~ m{\bztgsm/.*}) {
# Junghanns GSM card
$type = "GSM";
- } elsif(defined $signalling) {
+ } elsif($signalling ne '') {
$type = 'FXO' if $signalling =~ /^FXS/;
$type = 'FXS' if $signalling =~ /^FXO/;
} else {
- $type = undef;
+ $type = $self->probe_type();
}
$self->type($type);
$self->span()->type($type)
@@ -216,8 +217,7 @@ sub battery($) {
my $self = shift or die;
my $span = $self->span or die;
- return undef if (not defined $self->type);
- return undef unless $self->type eq 'FXO';
+ return undef unless defined $self->type && $self->type eq 'FXO';
return $self->{BATTERY} if defined $self->{BATTERY};
my $xpd = $span->xpd;
diff --git a/kernel/xpp/utils/zconf/Zaptel/Config/Defaults.pm b/kernel/xpp/utils/zconf/Zaptel/Config/Defaults.pm
index 360ca0a..9a3dec9 100644
--- a/kernel/xpp/utils/zconf/Zaptel/Config/Defaults.pm
+++ b/kernel/xpp/utils/zconf/Zaptel/Config/Defaults.pm
@@ -1,4 +1,16 @@
package Zaptel::Config::Defaults;
+
+#
+# !!!! DEPRECATION WARNING!!!
+#
+# This module is used by older versions of init_card_* scripts and
+# their related drivers.
+#
+# Zaptel drivers *after* 1.4.12.1 and DAHDI drivers do not use it.
+# Their configuration is read via XppConfig.pm which is always
+# bundled with the init_card_* scripts.
+#
+
#
# Written by Oron Peled <oron@actcom.co.il>
# Copyright (C) 2007, Xorcom
diff --git a/kernel/xpp/utils/zconf/Zaptel/Config/Gen.pm b/kernel/xpp/utils/zconf/Zaptel/Config/Gen.pm
new file mode 100644
index 0000000..05bb9be
--- /dev/null
+++ b/kernel/xpp/utils/zconf/Zaptel/Config/Gen.pm
@@ -0,0 +1,212 @@
+package Zaptel::Config::Gen;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2009, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+
+=head1 NAME
+
+Zaptel::Config::Gen -- Wrapper class for configuration generators.
+
+=head1 SYNOPSIS
+
+ use Zaptel::Config::Gen qw(is_true);
+ my $params = Zaptel::Config::Params->new('the-config-file');
+ my $gconfig = Zaptel::Config::Gen->new($params);
+ my $num = $gconfig->{'base_exten'};
+ my $overlap = is_true($gconfig->{'brint_overlap'});
+ $gconfig->dump; # For debugging
+ $gconfig->run_generator('system', {}, @spans);
+
+=head1 DESCRIPTION
+
+The constructor must be given an C<Zaptel::Config::Params> object.
+The returned object contains all data required for generation in the
+form of a hash.
+
+The constructor maps the C<item()>s from the parameter object into semantic
+configuration keys. E.g: the C<lc_country> item is mapped to C<loadzone> and
+C<defaultzone> keys.
+
+The actual generation is done by delegation to one of the generators.
+This is done via the C<run_generator()> method which receive the
+generator name, a generator specific options hash and a list of
+span objects (from C<Zaptel::Span>) for which to generate configuration.
+
+This module contains few helper functions. E.g: C<is_true()>, C<bchan_range()>.
+
+=cut
+
+require Exporter;
+@ISA = qw(Exporter);
+
+@EXPORT_OK = qw(is_true);
+
+use strict;
+
+# Parse values as true/false
+sub is_true($) {
+ my $val = shift;
+ return undef unless defined $val;
+ return $val =~ /^(1|y|yes)$/i;
+}
+
+# Generate channel range strings from span objects
+# E.g: "63-77,79-93"
+sub bchan_range($) {
+ my $span = shift || die;
+ my $first_chan = ($span->chans())[0];
+ my $first_num = $first_chan->num();
+ my $range_start = $first_num;
+ my @range;
+ my $prev = undef;
+
+ die unless $span->is_digital();
+ foreach my $c (@{$span->bchan_list()}) {
+ my $curr = $c + $first_num;
+ if(!defined($prev)) {
+ $prev = $curr;
+ } elsif($curr != $prev + 1) {
+ push(@range, sprintf("%d-%d", $range_start, $prev));
+ $range_start = $curr;
+ }
+ $prev = $curr;
+ }
+ if($prev >= $first_num) {
+ push(@range, sprintf("%d-%d", $range_start, $prev));
+ }
+ return join(',', @range);
+}
+
+sub new($) {
+ my $pack = shift || die "$0: Missing package argument";
+ my $p = shift || die "$0: Missing parameters argument";
+
+ # Set defaults
+ my $fxs_default_start = $p->item('fxs_default_start');
+ my $fxo_default_start = $p->item('fxo_default_start');
+
+ my %default_context = (
+ FXO => $p->item('context_lines'),
+ FXS => $p->item('context_phones'),
+ IN => $p->item('context_input'),
+ OUT => $p->item('context_output'),
+ BRI_TE => $p->item('context_lines'),
+ BRI_NT => $p->item('context_phones'),
+ E1_TE => $p->item('context_lines'),
+ T1_TE => $p->item('context_lines'),
+ J1_TE => $p->item('context_lines'),
+ E1_NT => $p->item('context_phones'),
+ T1_NT => $p->item('context_phones'),
+ J1_NT => $p->item('context_phones'),
+ );
+ my %default_group = (
+ FXO => $p->item('group_lines'),
+ FXS => $p->item('group_phones'),
+ IN => '',
+ OUT => '',
+ BRI_TE => $p->item('group_lines'),
+ BRI_NT => $p->item('group_lines'),
+ E1_TE => $p->item('group_lines'),
+ T1_TE => $p->item('group_lines'),
+ J1_TE => $p->item('group_lines'),
+ E1_NT => $p->item('group_lines'),
+ T1_NT => $p->item('group_lines'),
+ J1_NT => $p->item('group_lines'),
+ );
+ my %default_zaptel_signalling = (
+ FXO => "fxs$fxo_default_start",
+ FXS => "fxo$fxs_default_start",
+ IN => "fxo$fxs_default_start",
+ OUT => "fxo$fxs_default_start",
+ );
+ my %default_zapata_signalling = (
+ FXO => "fxs_$fxo_default_start",
+ FXS => "fxo_$fxs_default_start",
+ IN => "fxo_$fxs_default_start",
+ OUT => "fxo_$fxs_default_start",
+ );
+
+ # First complex mapping
+ my $gconfig = {
+ PARAMETERS => $p,
+ 'loadzone' => $p->item('lc_country'),
+ 'defaultzone' => $p->item('lc_country'),
+ 'context' => \%default_context,
+ 'group' => \%default_group,
+ 'zaptel_signalling' => \%default_zaptel_signalling,
+ 'zapata_signalling' => \%default_zapata_signalling,
+ };
+ # Now add trivial mappings
+ my @trivial = qw(
+ base_exten
+ freepbx
+ fxs_immediate
+ bri_hardhdlc
+ bri_sig_style
+ r2_idle_bits
+ brint_overlap
+ pri_termtype
+ pri_connection_type
+ );
+ foreach my $k (@trivial) {
+ $gconfig->{$k} = $p->item($k);
+ }
+ bless $gconfig,$pack;
+
+ return $gconfig;
+}
+
+sub run_generator($$@) {
+ my $gconfig = shift || die;
+ my $name = shift || die "$0: Missing generator name argument";
+ my $genopts = shift || die "$0: Missing genopts argument";
+ ref($genopts) eq 'HASH' or die "$0: Bad genopts argument";
+ my @spans = @_;
+
+ my $module = "Zaptel::Config::Gen::$name";
+ #print STDERR "DEBUG: $module\n";
+ eval "use $module";
+ if($@) {
+ die "Failed to load configuration generator for '$name'\n";
+ }
+ my $cfg = $module->new($gconfig, $genopts);
+ $cfg->generate(@spans);
+}
+
+sub dump($) {
+ my $self = shift || die;
+ printf STDERR "%s dump:\n", ref $self;
+ my $width = 30;
+ foreach my $k (sort keys %$self) {
+ my $val = $self->{$k};
+ my $ref = ref $val;
+ #print STDERR "DEBUG: '$k', '$ref', '$val'\n";
+ if($ref eq '') {
+ printf STDERR "%-${width}s %s\n", $k, $val;
+ } elsif($ref eq 'SCALAR') {
+ printf STDERR "%-${width}s %s\n", $k, ${$val};
+ } elsif($ref eq 'ARRAY') {
+ #printf STDERR "%s:\n", $k;
+ my $i = 0;
+ foreach my $v (@{$val}) {
+ printf STDERR "%-${width}s %s\n", "$k\->[$i]", $v;
+ $i++;
+ }
+ } elsif($ref eq 'HASH') {
+ #printf STDERR "%s:\n", $k;
+ foreach my $k1 (keys %{$val}) {
+ printf STDERR "%-${width}s %s\n", "$k\->\{$k1\}", ${$val}{$k1};
+ }
+ } else {
+ printf STDERR "%-${width}s (-> %s)\n", $k, $ref;
+ }
+ }
+}
+
+
+1;
diff --git a/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Unicall.pm b/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Unicall.pm
new file mode 100644
index 0000000..3e1048d
--- /dev/null
+++ b/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Unicall.pm
@@ -0,0 +1,70 @@
+package Zaptel::Config::Gen::Unicall;
+use strict;
+
+use Zaptel::Config::Gen qw(is_true);
+
+sub new($$$) {
+ my $pack = shift || die;
+ my $gconfig = shift || die;
+ my $genopts = shift || die;
+ my $file = $ENV{UNICALL_CHANNELS_FILE} || "/etc/asterisk/unicall-channels.conf";
+ my $self = {
+ FILE => $file,
+ GCONFIG => $gconfig,
+ GENOPTS => $genopts,
+ };
+ bless $self, $pack;
+ return $self;
+}
+
+sub generate($) {
+ my $self = shift || die;
+ my $file = $self->{FILE};
+ my $gconfig = $self->{GCONFIG};
+ my $genopts = $self->{GENOPTS};
+ #$gconfig->dump;
+ my @spans = @_;
+ warn "Empty configuration -- no spans\n" unless @spans;
+ die "Only for R2" unless $gconfig->{'pri_connection_type'} eq 'R2';
+ rename "$file", "$file.bak"
+ or $! == 2 # ENOENT (No dependency on Errno.pm)
+ or die "Failed to backup old config: $!\n";
+ print "Generating $file\n" if $genopts->{verbose};
+ open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+ my $old = select F;
+ printf "; Autogenerated by %s on %s -- do not hand edit\n", $0, scalar(localtime);
+ print "; This file should be #included in unicall.conf\n\n";
+ foreach my $span (@spans) {
+ next unless $span->is_digital();
+ printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
+ my $idle_bits = $gconfig->{'r2_idle_bits'};
+ printf "protocolend=%s\n", ($span->termtype() eq 'TE') ? 'cpe' : 'co';
+ printf "channel=%s\n", Zaptel::Config::Gen::bchan_range($span);
+ print "\n";
+ }
+ close F;
+ select $old;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+unicall - Generate configuration for unicall channels.
+
+=head1 SYNOPSIS
+
+ use Zaptel::Config::Gen::Unicall;
+
+ my $cfg = new Zaptel::Config::Gen::Unicall(\%global_config, \%genopts);
+ $cfg->generate(@span_list);
+
+=head1 DESCRIPTION
+
+Generate the F</etc/asterisk/unicall-channels.conf> to be included in
+F</etc/asterisk/unicall.conf>
+
+Its location may be overriden via the environment variable
+C<UNICALL_CHANNELS_FILE>.
diff --git a/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Users.pm b/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Users.pm
new file mode 100644
index 0000000..7c9e937
--- /dev/null
+++ b/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Users.pm
@@ -0,0 +1,177 @@
+package Zaptel::Config::Gen::Users;
+use strict;
+
+use File::Basename;
+use Zaptel::Config::Gen qw(is_true);
+
+sub new($$$) {
+ my $pack = shift || die;
+ my $gconfig = shift || die;
+ my $genopts = shift || die;
+ my $file = $ENV{USERS_FILE} || "/etc/asterisk/users.conf";
+ my $self = {
+ FILE => $file,
+ GCONFIG => $gconfig,
+ GENOPTS => $genopts,
+ };
+ bless $self, $pack;
+ return $self;
+}
+
+sub gen_channel($) {
+ my $self = shift || die;
+ my $chan = shift || die;
+ my $gconfig = $self->{GCONFIG};
+ my $type = $chan->type;
+ my $num = $chan->num;
+ die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
+ my $exten = $gconfig->{'base_exten'} + $num;
+ my $sig = $gconfig->{'zapata_signalling'}{$type};
+ my $full_name = "$type $num";
+
+ die "missing default_zapata_signalling for chan #$num type $type" unless $sig;
+ print << "EOF";
+[$exten]
+callwaiting = yes
+context = numberplan-custom-1
+fullname = $full_name
+cid_number = $exten
+hasagent = no
+hasdirectory = no
+hasiax = no
+hasmanager = no
+hassip = no
+hasvoicemail = yes
+host = dynamic
+mailbox = $exten
+threewaycalling = yes
+vmsecret = 1234
+secret = 1234
+signalling = $sig
+zapchan = $num
+registeriax = no
+registersip = no
+canreinvite = no
+nat = no
+dtmfmode = rfc2833
+disallow = all
+allow = all
+
+EOF
+}
+
+# generate users.conf . The specific users.conf is strictly oriented
+# towards using with the asterisk-gui .
+#
+# This code could have generated a much simpler and smaller
+# configuration file, had there been minimal level of support for
+# configuration templates in the asterisk configuration rewriting. Right
+# now Asterisk's configuration rewriting simply freaks out in the face
+# of templates: http://bugs.digium.com/11442 .
+sub generate($) {
+ my $self = shift || die;
+ my $file = $self->{FILE};
+ my $gconfig = $self->{GCONFIG};
+ my $genopts = $self->{GENOPTS};
+ #$gconfig->dump;
+ my @spans = @_;
+ warn "Empty configuration -- no spans\n" unless @spans;
+ rename "$file", "$file.bak"
+ or $! == 2 # ENOENT (No dependency on Errno.pm)
+ or die "Failed to backup old config: $!\n";
+ print "Generating $file\n" if $genopts->{verbose};
+ open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+ my $old = select F;
+ print <<"HEAD";
+;!
+;! Automatically generated configuration file
+;! Filename: @{[basename($file)]} ($file)
+;! Generator: $0
+;! Creation Date: @{[scalar(localtime)]}
+;!
+[general]
+;
+; Full name of a user
+;
+fullname = New User
+;
+; Starting point of allocation of extensions
+;
+userbase = @{[$gconfig->{'base_exten'}+1]}
+;
+; Create voicemail mailbox and use use macro-stdexten
+;
+hasvoicemail = yes
+;
+; Set voicemail mailbox @{[$gconfig->{'base_exten'}+1]} password to 1234
+;
+vmsecret = 1234
+;
+; Create SIP Peer
+;
+hassip = no
+;
+; Create IAX friend
+;
+hasiax = no
+;
+; Create Agent friend
+;
+hasagent = no
+;
+; Create H.323 friend
+;
+;hash323 = yes
+;
+; Create manager entry
+;
+hasmanager = no
+;
+; Remaining options are not specific to users.conf entries but are general.
+;
+callwaiting = yes
+threewaycalling = yes
+callwaitingcallerid = yes
+transfer = yes
+canpark = yes
+cancallforward = yes
+callreturn = yes
+callgroup = 1
+pickupgroup = 1
+localextenlength = @{[length($gconfig->{'base_exten'})]}
+
+
+HEAD
+ foreach my $span (@spans) {
+ next unless grep { $_ eq $span->type} ( 'FXS', 'IN', 'OUT' );
+ printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
+ foreach my $chan ($span->chans()) {
+ $self->gen_channel($chan);
+ }
+ print "\n";
+ }
+ close F;
+ select $old;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+users - Generate configuration for users.conf.
+
+=head1 SYNOPSIS
+
+ use Zaptel::Config::Gen::Users;
+
+ my $cfg = new Zaptel::Config::Gen::Users(\%global_config, \%genopts);
+ $cfg->generate(@span_list);
+
+=head1 DESCRIPTION
+
+Generate the F</etc/asterisk/users.conf> which is used by asterisk(1)
+and AsteriskGUI.
+
+Its location may be overriden via the environment variable F<USERS_FILE>.
diff --git a/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Zapata.pm b/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Zapata.pm
new file mode 100644
index 0000000..e8fd733
--- /dev/null
+++ b/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Zapata.pm
@@ -0,0 +1,213 @@
+package Zaptel::Config::Gen::Zapata;
+use strict;
+
+use Zaptel::Config::Gen qw(is_true);
+
+sub new($$$) {
+ my $pack = shift || die;
+ my $gconfig = shift || die;
+ my $genopts = shift || die;
+ my $file = $ENV{ZAPATA_FILE} || "/etc/asterisk/zapata-channels.conf";
+ my $self = {
+ FILE => $file,
+ GCONFIG => $gconfig,
+ GENOPTS => $genopts,
+ };
+ bless $self, $pack;
+ return $self;
+}
+
+# Since zapata definitions "leak" to the next ones, we try
+# To reset some important definitions to their chan_zap defaults.
+my %chan_zap_defaults = (
+ context => 'default',
+ group => '63', # FIXME: should not be needed.
+ overlapdial => 'no',
+ busydetect => 'no',
+ rxgain => 0,
+ txgain => 0,
+);
+
+sub reset_zapata_values {
+ foreach my $arg (@_) {
+ if (exists $chan_zap_defaults{$arg}) {
+ print "$arg = $chan_zap_defaults{$arg}\n";
+ } else {
+ print "$arg =\n";
+ }
+ }
+}
+
+sub gen_digital($$) {
+ my $self = shift || die;
+ my $span = shift || die;
+ my $gconfig = $self->{GCONFIG};
+ my $num = $span->num() || die;
+ die "Span #$num is analog" unless $span->is_digital();
+ if($span->is_pri && $gconfig->{'pri_connection_type'} eq 'R2') {
+ printf "; Skipped: $gconfig->{'pri_connection_type'}\n\n";
+ return;
+ }
+ my $type = $span->type() || die "$0: Span #$num -- unkown type\n";
+ my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
+ my $group = $gconfig->{'group'}{"$type"};
+ my $context = $gconfig->{'context'}{"$type"};
+ my @to_reset = qw/context group/;
+
+ die "$0: missing default group (termtype=$termtype)\n" unless defined($group);
+ die "$0: missing default context\n" unless $context;
+
+ my $sig = $span->signalling || die "missing signalling info for span #$num type $type";
+ grep($gconfig->{'bri_sig_style'} eq $_, 'bri', 'bri_ptmp', 'pri') or die "unknown signalling style for BRI";
+ if($span->is_bri() and $gconfig->{'bri_sig_style'} eq 'bri_ptmp') {
+ $sig .= '_ptmp';
+ }
+ if ($span->is_bri() && $termtype eq 'NT' && is_true($gconfig->{'brint_overlap'})) {
+ print "overlapdial = yes\n";
+ push(@to_reset, qw/overlapdial/);
+ }
+
+ $group .= "," . (10 + $num); # Invent unique group per span
+ printf "group=$group\n";
+ printf "context=$context\n";
+ printf "switchtype = %s\n", $span->switchtype;
+ printf "signalling = %s\n", $sig;
+ printf "channel => %s\n", Zaptel::Config::Gen::bchan_range($span);
+ reset_zapata_values(@to_reset);
+}
+
+sub gen_channel($$) {
+ my $self = shift || die;
+ my $chan = shift || die;
+ my $gconfig = $self->{GCONFIG};
+ my $type = $chan->type;
+ my $num = $chan->num;
+ die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
+ my $exten = $gconfig->{'base_exten'} + $num;
+ my $sig = $gconfig->{'zapata_signalling'}{$type};
+ my $context = $gconfig->{'context'}{$type};
+ my $group = $gconfig->{'group'}{$type};
+ my $callerid;
+ my $immediate;
+
+ return if $type eq 'EMPTY';
+ die "missing default_zapata_signalling for chan #$num type $type" unless $sig;
+ $callerid = ($type eq 'FXO')
+ ? 'asreceived'
+ : sprintf "\"Channel %d\" <%04d>", $num, $exten;
+ if($type eq 'IN') {
+ $immediate = 'yes';
+ }
+ # FIXME: $immediage should not be set for 'OUT' channels, but meanwhile
+ # it's better to be compatible with genzaptelconf
+ $immediate = 'yes' if $gconfig->{'fxs_immediate'} eq 'yes' and $sig =~ /^fxo_/;
+ my $signalling = $chan->signalling;
+ $signalling = " " . $signalling if $signalling;
+ my $info = $chan->info;
+ $info = " " . $info if $info;
+ printf ";;; line=\"%d %s%s%s\"\n", $num, $chan->fqn, $signalling, $info;
+ printf "signalling=$sig\n";
+ printf "callerid=$callerid\n";
+ printf "mailbox=%04d\n", $exten unless $type eq 'FXO';
+ if(defined $group) {
+ printf "group=$group\n";
+ }
+ printf "context=$context\n";
+ printf "immediate=$immediate\n" if defined $immediate;
+ printf "channel => %d\n", $num;
+ # Reset following values to default
+ printf "callerid=\n";
+ printf "mailbox=\n" unless $type eq 'FXO';
+ if(defined $group) {
+ printf "group=\n";
+ }
+ printf "context=default\n";
+ printf "immediate=no\n" if defined $immediate;
+ print "\n";
+}
+
+sub generate($) {
+ my $self = shift || die;
+ my $file = $self->{FILE};
+ my $gconfig = $self->{GCONFIG};
+ my $genopts = $self->{GENOPTS};
+ #$gconfig->dump;
+ my @spans = @_;
+ warn "Empty configuration -- no spans\n" unless @spans;
+ rename "$file", "$file.bak"
+ or $! == 2 # ENOENT (No dependency on Errno.pm)
+ or die "Failed to backup old config: $!\n";
+ print "Generating $file\n" if $genopts->{verbose};
+ open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+ my $old = select F;
+ printf "; Autogenerated by %s on %s -- do not hand edit\n", $0, scalar(localtime);
+ print <<"HEAD";
+; Zaptel Channels Configurations (zapata.conf)
+;
+; This is not intended to be a complete zapata.conf. Rather, it is intended
+; to be #include-d by /etc/zapata.conf that will include the global settings
+;
+
+HEAD
+ foreach my $span (@spans) {
+ printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
+ if($span->is_digital()) {
+ $self->gen_digital($span);
+ } else {
+ foreach my $chan ($span->chans()) {
+ if(is_true($genopts->{'freepbx'}) || is_true($gconfig->{'freepbx'})) {
+ # Freepbx has its own idea about channels
+ my $type = $chan->type;
+ if($type eq 'FXS' || $type eq 'OUT' || $type eq 'IN') {
+ printf "; Skip channel=%s($type) -- freepbx option.\n",
+ $chan->num;
+ next;
+ }
+ }
+ $self->gen_channel($chan);
+ }
+ }
+ print "\n";
+ }
+ close F;
+ select $old;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+zapata - Generate configuration for zapata channels.
+
+=head1 SYNOPSIS
+
+ use Zaptel::Config::Gen::Zapata;
+
+ my $cfg = new Zaptel::Config::Gen::Zapata(\%global_config, \%genopts);
+ $cfg->generate(@span_list);
+
+=head1 DESCRIPTION
+
+Generate the F</etc/asterisk/zapata-channels.conf>
+This is used as a configuration for asterisk(1).
+It should be included in the main F</etc/asterisk/zapata.conf>.
+
+Its location may be overriden via the environment variable
+C<ZAPATA_FILE>.
+
+=head1 OPTIONS
+
+=over 4
+
+=item freepbx
+
+With this option we do not generate channel definitions for FXS, Input and
+Output ports. This is done because these channel definitions need to be
+generated and inserted into I<freepbx> database anyway.
+
+=back
+
+The I<freepbx> option may be activated also by adding a C<freepbx yes> line
+to the C<genconf_parameters> file.
diff --git a/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Zaptel.pm b/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Zaptel.pm
new file mode 100644
index 0000000..2c30c33
--- /dev/null
+++ b/kernel/xpp/utils/zconf/Zaptel/Config/Gen/Zaptel.pm
@@ -0,0 +1,158 @@
+package Zaptel::Config::Gen::Zaptel;
+use strict;
+
+use Zaptel::Config::Gen qw(is_true);
+
+sub new($$$) {
+ my $pack = shift || die;
+ my $gconfig = shift || die;
+ my $genopts = shift || die;
+ my $file = $ENV{ZAPCONF_FILE} || "/etc/zaptel.conf";
+ my $self = {
+ FILE => $file,
+ GCONFIG => $gconfig,
+ GENOPTS => $genopts,
+ };
+ bless $self, $pack;
+ return $self;
+}
+
+my $bri_te_last_timing = 1;
+
+sub gen_digital($$) {
+ my $gconfig = shift || die;
+ my $span = shift || die;
+ my $num = $span->num() || die;
+ die "Span #$num is analog" unless $span->is_digital();
+ my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
+ my $timing;
+ my $lbo = 0;
+ my $framing = $span->framing() || die "$0: No framing information for span #$num\n";
+ my $coding = $span->coding() || die "$0: No coding information for span #$num\n";
+ my $span_crc4 = $span->crc4();
+ $span_crc4 = (defined $span_crc4) ? ",$span_crc4" : '';
+ my $span_yellow = $span->yellow();
+ $span_yellow = (defined $span_yellow) ? ",$span_yellow" : '';
+ # "MFC/R2 does not normally use CRC4"
+ # FIXME: a finer way to override:
+ if ($gconfig->{'pri_connection_type'} eq 'R2') {
+ $span_crc4 = '';
+ $framing = 'cas';
+ }
+ my $dchan_type = 'dchan';
+ if ($span->is_bri() && is_true($gconfig->{'bri_hardhdlc'})) {
+ $dchan_type = 'hardhdlc';
+ }
+
+ $timing = ($termtype eq 'NT') ? 0 : $bri_te_last_timing++;
+ printf "span=%d,%d,%d,%s,%s%s%s\n",
+ $num,
+ $timing,
+ $lbo,
+ $framing,
+ $coding,
+ $span_crc4,
+ $span_yellow;
+ printf "# termtype: %s\n", lc($termtype);
+ if ($gconfig->{'pri_connection_type'} eq 'PRI') {
+ printf "bchan=%s\n", Zaptel::Config::Gen::bchan_range($span);
+ my $dchan = $span->dchan();
+ printf "$dchan_type=%d\n", $dchan->num();
+ } elsif ($gconfig->{'pri_connection_type'} eq 'R2' ) {
+ my $idle_bits = $gconfig->{'r2_idle_bits'};
+ printf "cas=%s:$idle_bits\n", Zaptel::Config::Gen::bchan_range($span);
+ printf "dchan=%d\n", $span->dchan()->num();
+ }
+}
+
+sub gen_signalling($$) {
+ my $gconfig = shift || die;
+ my $chan = shift || die;
+ my $type = $chan->type;
+ my $num = $chan->num;
+
+ die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
+ if($type eq 'EMPTY') {
+ printf "# channel %d, %s, no module.\n", $num, $chan->fqn;
+ return;
+ }
+ my $signalling = $gconfig->{'zaptel_signalling'};
+ my $sig = $signalling->{$type} || die "unknown default zaptel signalling for chan $num type $type";
+ if ($type eq 'IN') {
+ printf "# astbanktype: input\n";
+ } elsif ($type eq 'OUT') {
+ printf "# astbanktype: output\n";
+ }
+ printf "$sig=$num\n";
+}
+
+sub generate($$$) {
+ my $self = shift || die;
+ my $file = $self->{FILE};
+ my $gconfig = $self->{GCONFIG};
+ my $genopts = $self->{GENOPTS};
+ my @spans = @_;
+ warn "Empty configuration -- no spans\n" unless @spans;
+ rename "$file", "$file.bak"
+ or $! == 2 # ENOENT (No dependency on Errno.pm)
+ or die "Failed to backup old config: $!\n";
+ #$gconfig->dump;
+ print "Generating $file\n" if $genopts->{verbose};
+ open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+ my $old = select F;
+ printf "# Autogenerated by %s on %s -- do not hand edit\n", $0, scalar(localtime);
+ print <<"HEAD";
+# Zaptel Configuration File
+#
+# This file is parsed by the Zaptel Configurator, ztcfg
+#
+HEAD
+ foreach my $span (@spans) {
+ printf "# Span %d: %s %s\n", $span->num, $span->name, $span->description;
+ if($span->is_digital()) {
+ gen_digital($gconfig, $span);
+ } else {
+ foreach my $chan ($span->chans()) {
+ if(1 || !defined $chan->type) {
+ my $type = $chan->probe_type;
+ my $num = $chan->num;
+ die "Failed probing type for channel $num"
+ unless defined $type;
+ $chan->type($type);
+ }
+ gen_signalling($gconfig, $chan);
+ }
+ }
+ print "\n";
+ }
+ print <<"TAIL";
+# Global data
+
+loadzone = $gconfig->{'loadzone'}
+defaultzone = $gconfig->{'defaultzone'}
+TAIL
+ close F;
+ select $old;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+zaptel - Generate configuration for zaptel drivers.
+
+=head1 SYNOPSIS
+
+ use Zaptel::Config::Gen::Zaptel;
+
+ my $cfg = new Zaptel::Config::Gen::Zaptel(\%global_config, \%genopts);
+ $cfg->generate(@span_list);
+
+=head1 DESCRIPTION
+
+Generate the F</etc/zaptel.conf>.
+This is the configuration for ztcfg(1).
+
+Its location may be overriden via the environment variable F<ZAPCONF_FILE>.
diff --git a/kernel/xpp/utils/zconf/Zaptel/Config/Params.pm b/kernel/xpp/utils/zconf/Zaptel/Config/Params.pm
new file mode 100644
index 0000000..7f6ae80
--- /dev/null
+++ b/kernel/xpp/utils/zconf/Zaptel/Config/Params.pm
@@ -0,0 +1,149 @@
+package Zaptel::Config::Params;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2009, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+
+=head1 NAME
+
+Zaptel::Config::Params -- Object oriented representation of F<genconf_parameters> file.
+
+=head1 SYNOPSIS
+
+ use Zaptel::Config::Params;
+ my $params = Zaptel::Config::Params->new('the-config-file');
+ print $params->item{'some-key'};
+ $params->dump; # For debugging
+
+=head1 DESCRIPTION
+
+The constructor must be given a configuration file name:
+
+=over 4
+
+=item * Missing file is B<not> an error.
+
+=item * Other opening errors cause a C<die> to be thrown.
+
+=item * The file name is saved as the value of C<GENCONF_FILE> key.
+
+=back
+
+The access to config keys should only be done via the C<item()> method:
+
+=over 4
+
+=item * It contains all hard-coded defaults.
+
+=item * All these values are overriden by directives in the config file.
+
+=back
+
+=cut
+
+sub new($$) {
+ my $pack = shift || die;
+ my $cfg_file = shift || die;
+ my $self = {
+ GENCONF_FILE => $cfg_file,
+ };
+ bless $self, $pack;
+ if(!open(F, $cfg_file)) {
+ if(defined($!{ENOENT})) {
+ #print STDERR "No $cfg_file. Assume empty config\n";
+ return $self; # Empty configuration
+ }
+ die "$pack: Failed to open '$cfg_file': $!\n";
+ }
+ #print STDERR "$pack: $cfg_file\n";
+ my $array_key;
+ while(<F>) {
+ my ($key, $val);
+ chomp;
+ s/#.*$//;
+ s/\s+$//; # trim tail whitespace
+ next unless /\S/;
+ if(defined $array_key && /^\s+/) {
+ s/^\s+//; # trim beginning whitespace
+ push(@{$self->{$array_key}}, $_);
+ next;
+ }
+ undef $array_key;
+ ($key, $val) = split(/\s+/, $_, 2);
+ $key = lc($key);
+ if(! defined $val) {
+ $array_key = $key;
+ next;
+ }
+ die "$cfg_file:$.: Duplicate key '$key'\n", if exists $self->{$key};
+ $self->{$key} = $val;
+ }
+ close F;
+ return $self;
+}
+
+sub item($$) {
+ my $self = shift || die;
+ my $key = shift || die;
+ my %defaults = (
+ base_exten => '4000',
+ freepbx => 'no', # Better via -F command line
+ fxs_immediate => 'no',
+ fxs_default_start => 'ks',
+ fxo_default_start => 'ks',
+ lc_country => 'us',
+ context_lines => 'from-pstn',
+ context_phones => 'from-internal',
+ context_input => 'astbank-input',
+ context_output => 'astbank-output',
+ group_phones => '5',
+ group_lines => '0',
+ brint_overlap => 'no',
+ bri_sig_style => 'bri_ptmp',
+ echo_can => 'mg2',
+ bri_hardhdlc => 'no',
+ pri_connection_type => 'PRI',
+ r2_idle_bits => '1101',
+ 'pri_termtype' => [ 'SPAN/* TE' ],
+ );
+
+ return (exists($self->{$key})) ? $self->{$key} :$defaults{$key};
+}
+
+sub dump($) {
+ my $self = shift || die;
+ printf STDERR "%s dump:\n", ref $self;
+ my $width = 30;
+ foreach my $k (sort keys %$self) {
+ my $val = $self->{$k};
+ my $ref = ref $val;
+ #print STDERR "DEBUG: '$k', '$ref', '$val'\n";
+ if($ref eq '') {
+ printf STDERR "%-${width}s %s\n", $k, $val;
+ } elsif($ref eq 'SCALAR') {
+ printf STDERR "%-${width}s %s\n", $k, ${$val};
+ } elsif($ref eq 'ARRAY') {
+ #printf STDERR "%s:\n", $k;
+ my $i = 0;
+ foreach my $v (@{$val}) {
+ printf STDERR "%-${width}s %s\n", "$k\->[$i]", $v;
+ $i++;
+ }
+ } elsif($ref eq 'HASH') {
+ #printf STDERR "%s:\n", $k;
+ foreach my $k1 (keys %{$val}) {
+ printf STDERR "%-${width}s %s\n", "$k\->\{$k1\}", ${$val}{$k1};
+ }
+ } else {
+ printf STDERR "%-${width}s (-> %s)\n", $k, $ref;
+ }
+ }
+}
+
+1;
+
diff --git a/kernel/xpp/utils/zconf/Zaptel/Hardware/PCI.pm b/kernel/xpp/utils/zconf/Zaptel/Hardware/PCI.pm
index c03b0d1..e9166c7 100644
--- a/kernel/xpp/utils/zconf/Zaptel/Hardware/PCI.pm
+++ b/kernel/xpp/utils/zconf/Zaptel/Hardware/PCI.pm
@@ -84,10 +84,13 @@ my %pci_ids = (
'd161:8000' => { DRIVER => 'wcte12xp', DESCRIPTION => 'Wildcard TE121' },
'd161:8001' => { DRIVER => 'wcte12xp', DESCRIPTION => 'Wildcard TE122' },
+ # from wcb4xxp
+ 'd161:b410' => { DRIVER => 'wcb4xxp', DESCRIPTION => 'Digium Wildcard B410P' },
+
# from tor2
'10b5:9030' => { DRIVER => 'tor2', DESCRIPTION => 'PLX 9030' },
'10b5:3001' => { DRIVER => 'tor2', DESCRIPTION => 'PLX Development Board' },
- '10b5:D00D' => { DRIVER => 'tor2', DESCRIPTION => 'Tormenta 2 Quad T1/PRI or E1/PRA' },
+ '10b5:d00d' => { DRIVER => 'tor2', DESCRIPTION => 'Tormenta 2 Quad T1/PRI or E1/PRA' },
'10b5:4000' => { DRIVER => 'tor2', DESCRIPTION => 'Tormenta 2 Quad T1/E1 (non-Digium clone)' },
# Cologne Chips:
@@ -97,6 +100,8 @@ my %pci_ids = (
'1397:16b8' => { DRIVER => 'qozap', DESCRIPTION => 'Junghanns OctoBRI ISDN card' },
'1397:30b1' => { DRIVER => 'cwain', DESCRIPTION => 'HFC-E1 ISDN E1 card' },
'1397:2bd0' => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+ # Has three submodels. Tested with 0675:1704:
+ '1043:0675' => { DRIVER => 'zaphfc', DESCRIPTION => 'ASUSTeK Computer Inc. ISDNLink P-IN100-ST-D' },
'1397:f001' => { DRIVER => 'ztgsm', DESCRIPTION => 'HFC-GSM Cologne Chips GSM' },
# Rhino cards (based on pci.ids)
diff --git a/kernel/xpp/utils/zconf/Zaptel/Span.pm b/kernel/xpp/utils/zconf/Zaptel/Span.pm
index be49c28..c771a26 100644
--- a/kernel/xpp/utils/zconf/Zaptel/Span.pm
+++ b/kernel/xpp/utils/zconf/Zaptel/Span.pm
@@ -133,12 +133,13 @@ my @bri_strings = (
'BRI_(NT|TE)',
'(?:quad|octo)BRI PCI ISDN Card.* \[(NT|TE)\]\ ',
'octoBRI \[(NT|TE)\] ',
- 'HFC-S PCI A ISDN.* \[(NT|TE)\] '
+ 'HFC-S PCI A ISDN.* \[(NT|TE)\] ',
+ '(B4XXP) \(PCI\) Card', # Does not expose NT/TE type
);
my @pri_strings = (
- '(E1|T1|J1)_(NT|TE)',
'Tormenta 2 .*Quad (E1|T1)', # tor2.
+ 'Xorcom XPD.*: (E1|T1)', # Astribank PRI
'Digium Wildcard .100P (T1|E1)/', # wct1xxp
'ISA Tormenta Span 1', # torisa
'TE110P T1/E1', # wcte11xp
@@ -189,10 +190,12 @@ sub new($$) {
$self->{IS_PRI} = 0;
foreach my $cardtype (@bri_strings) {
if($head =~ m/$cardtype/) {
+ my $termtype = $1;
+ $termtype = 'TE' if ( $1 eq 'B4XXP' );
$self->{IS_DIGITAL} = 1;
$self->{IS_BRI} = 1;
- $self->{TERMTYPE} = $1;
- $self->{TYPE} = "BRI_$1";
+ $self->{TERMTYPE} = $termtype;
+ $self->{TYPE} = "BRI_$termtype";
$self->{DCHAN_IDX} = 2;
$self->{BCHAN_LIST} = [ 0, 1 ];
last;
@@ -207,7 +210,7 @@ sub new($$) {
my ($proto) = grep(/(E1|T1|J1)/, @info);
$proto = 'UNKNOWN' unless defined $proto;
my ($termtype) = grep(/(NT|TE)/, @info);
- $termtype = 'TE' unless defined $termtype;
+ $termtype = 'UNKNOWN' unless defined $termtype;
$self->{IS_DIGITAL} = 1;
$self->{IS_PRI} = 1;
@@ -216,8 +219,6 @@ sub new($$) {
last;
}
}
- die "$0: Unkown TERMTYPE [NT/TE]\n"
- if $self->is_digital and !defined $self->{TERMTYPE};
($self->{NAME}, $self->{DESCRIPTION}) = (split(/\s+/, $head, 4))[2, 3];
$self->{IS_ZAPTEL_SYNC_MASTER} =
($self->{DESCRIPTION} =~ /\(MASTER\)/) ? 1 : 0;
@@ -262,7 +263,7 @@ sub new($$) {
# Infer some info from channel name:
my $first_chan = ($self->chans())[0] || die "$0: No channels in span #$num\n";
my $chan_fqn = $first_chan->fqn();
- if($chan_fqn =~ m(ZTHFC.*/|ztqoz.*/|XPP_BRI_.*/)) { # BRI
+ if($chan_fqn =~ m(ZTHFC.*/|ztqoz.*/|XPP_BRI_.*|B4/.*)) { # BRI
$self->{FRAMING} = 'ccs';
$self->{SWITCHTYPE} = 'euroisdn';
$self->{SIGNALLING} = ($self->{TERMTYPE} eq 'NT') ? $ZAPBRI_NET : $ZAPBRI_CPE ;
@@ -286,7 +287,6 @@ sub new($$) {
} else {
die "'$self->{PROTO}' unsupported yet";
}
- $self->{SIGNALLING} = ($self->{TERMTYPE} eq 'NT') ? $ZAPPRI_NET : $ZAPPRI_CPE ;
}
return $self;
}
@@ -297,4 +297,57 @@ sub bchans($) {
return @{$self->{BCHANS}};
}
+sub set_termtype($$) {
+ my $span = shift || die;
+ my $termtype = shift || die;
+ $span->{TERMTYPE} = $termtype;
+ $span->{SIGNALLING} = ($termtype eq 'NT') ? $ZAPPRI_NET : $ZAPPRI_CPE ;
+ $span->{TYPE} = $span->proto . "_$termtype";
+}
+
+sub pri_set_fromconfig($$) {
+ my $span = shift || die;
+ my $genconf = shift || die;
+ my $name = $span->name;
+# if(defined $termtype) {
+# die "Termtype for $name already defined as $termtype\n";
+# }
+ my $pri_termtype = $genconf->{pri_termtype};
+ my @pri_specs;
+ if(defined $pri_termtype) {
+ @pri_specs = @{$pri_termtype};
+ }
+ push(@pri_specs , 'SPAN/* TE'); # Default
+ my @patlist = ( "SPAN/" . $span->num );
+ my ($xbus_name, $xpd_name) = ($name =~ m|(XBUS-\d+)/(XPD-\d+)|);
+ if(defined $xbus_name) {
+ push(@patlist, "NUM/$xbus_name/$xpd_name");
+# push(@patlist, "CONNECTOR/$ENV{XBUS_CONNECTOR}/$xpd_name");
+ }
+ #print STDERR "PATLIST=@patlist\n";
+ my $match_termtype;
+SPEC:
+ for(my $i = 0; $i < @pri_specs; $i++) {
+ my $spec = $pri_specs[$i];
+ #print STDERR "spec: $spec\n";
+ my ($match, $termtype) = split(/\s+/, $spec);
+ next unless defined $match and defined $termtype;
+ # Convert "globs" to regex
+ $match =~ s/\*/.*/g;
+ $match =~ s/\?/./g;
+ #print STDERR "match: $match\n";
+ foreach my $pattern (@patlist) {
+ #print STDERR "testmatch: $pattern =~ $match\n";
+ if($pattern =~ $match) {
+ #print STDERR "$xpd_name: MATCH '$pattern' ~ '$match' termtype=$termtype\n";
+ $match_termtype = $termtype;
+ last SPEC;
+ }
+ }
+ }
+ die "Unknown pri_termtype" unless defined $match_termtype;
+ $span->set_termtype($match_termtype);
+}
+
+
1;
diff --git a/kernel/xpp/utils/zconf/Zaptel/Xpp.pm b/kernel/xpp/utils/zconf/Zaptel/Xpp.pm
index 8b7458f..b626bfa 100644
--- a/kernel/xpp/utils/zconf/Zaptel/Xpp.pm
+++ b/kernel/xpp/utils/zconf/Zaptel/Xpp.pm
@@ -30,6 +30,9 @@ Zaptel::Xpp - Perl interface to the Xorcom Astribank drivers.
my $proc_base = "/proc/xpp";
+our $sysfs_astribanks = "/sys/bus/astribanks/devices";
+our $sysfs_xpds = "/sys/bus/xpds/devices";
+our $sysfs_ab_driver = "/sys/bus/astribanks/drivers/xppdrv";
# Nominal sorters for xbuses
sub by_name {
@@ -46,12 +49,46 @@ sub by_label {
return $a->connector cmp $b->connector;
}
+sub score_type {
+ my $score;
+
+ return 1 if grep(/\b[ETJ]1/, @_);
+ return 2 if grep(/\bBRI/, @_);
+ return 3 if grep(/\bFXO/, @_);
+ return 4; # FXS
+}
+
+sub by_type {
+ my @a_types = map { $_->type } $a->xpds();
+ my @b_types = map { $_->type } $b->xpds();
+ my $res;
+
+ my $a_score = score_type(@a_types);
+ my $b_score = score_type(@b_types);
+ #printf STDERR "DEBUG-a: %s %s %s\n", $a->name, $a_score, join(',',@a_types);
+ #printf STDERR "DEBUG-b: %s %s %s\n", $b->name, $b_score, join(',',@b_types);
+ $res = $a_score <=> $b_score;
+ $res = $a->connector cmp $b->connector if $res == 0;
+ return $res;
+}
+
+
=head1 xbuses([sort_order])
Scans system (/proc and /sys) and returns a list of Astribank (Xbus)
objects. The optional parameter sort_order is the order in which
the Astribanks will be returns:
+
+=head1 sorters([sort_order])
+
+With no parameters, returns the names of built in sorters.
+With a single parameter, returns a reference to the requested built in sorter.
+Also, for convenience, a reference to a custom sorter function may be passed
+and returned as is.
+
+The built in sorters are:
+
=over
=item SORT_CONNECTOR
@@ -63,13 +100,20 @@ the device through controllers, hubs etc.
Sorts by the label of the Astribank. The label field is unique to the
Astribank. It can also be viewed through 'lsusb -v' without the drivers
-loaded (the iSerial field in the Device Descriptor).
+loaded (the iSerial field in the Device Descriptor). This is normally
+relieble, but some older Astribanks have an empty label.
=item SORT_NAME
Sort by the "name". e.g: "XBUS-00". The order of Astribank names depends
on the load order, and hence may change between different runs.
+=item SORT_TYPE
+
+Sort by XPD types. First Astribanks with E1/T1/J1 XPDs, then with BRI,
+then with FXO, then ones with only FXS ports. Within each type they
+are sorted by the connector field (as in SORT_CONNECTOR above).
+
=item custom function
Instead of using a predefined sorter, you can pass your own sorting
@@ -79,39 +123,36 @@ function. See the example sorters in the code of this module.
=cut
+sub sorters {
+ my %sorter_table = (
+ SORT_CONNECTOR => \&by_connector,
+ SORT_NAME => \&by_name,
+ SORT_LABEL => \&by_label,
+ SORT_TYPE => \&by_type,
+ # Aliases
+ connector => \&by_connector,
+ name => \&by_name,
+ label => \&by_label,
+ type => \&by_type,
+ );
+ my $which_sorter = shift || return sort keys %sorter_table;
+ return $which_sorter if ref($which_sorter) eq 'CODE';
+ return $sorter_table{$which_sorter};
+}
+
sub xbuses {
my $optsort = shift || 'SORT_CONNECTOR';
my @xbuses;
- -d "$proc_base" or return ();
- my @lines;
- local $/ = "\n";
- open(F, "$proc_base/xbuses") ||
- die "$0: Failed to open $proc_base/xbuses: $!\n";
- @lines = <F>;
- close F;
- foreach my $line (@lines) {
- chomp $line;
- my ($name, @attr) = split(/\s+/, $line);
- $name =~ s/://;
- $name =~ /XBUS-(\d\d)/ or die "Bad XBUS number: $name";
- my $num = $1;
- @attr = map { split(/=/); } @attr;
- my $xbus = Zaptel::Xpp::Xbus->new(NAME => $name, NUM => $num, @attr);
+ opendir(D, $sysfs_astribanks) || return();
+ while(my $entry = readdir D) {
+ next unless $entry =~ /xbus-(\d+)/;
+ my $xbus = Zaptel::Xpp::Xbus->new($1);
push(@xbuses, $xbus);
}
- my $sorter;
- if($optsort eq "SORT_CONNECTOR") {
- $sorter = \&by_connector;
- } elsif($optsort eq "SORT_NAME") {
- $sorter = \&by_name;
- } elsif($optsort eq "SORT_LABEL") {
- $sorter = \&by_label;
- } elsif(ref($optsort) eq 'CODE') {
- $sorter = $optsort;
- } else {
- die "Unknown optional sorter '$optsort'";
- }
+ closedir D;
+ my $sorter = sorters($optsort);
+ die "Unknown optional sorter '$optsort'" unless defined $sorter;
@xbuses = sort $sorter @xbuses;
return @xbuses;
}
@@ -137,7 +178,7 @@ For more information read that file and see README.Astribank .
=cut
-sub sync {
+sub sync_via_proc {
my $newsync = shift;
my $result;
my $newapi = 0;
@@ -171,6 +212,32 @@ sub sync {
return $result;
}
+sub sync {
+ my ($newsync) = @_;
+ my $result;
+ my $file = "$sysfs_ab_driver/sync";
+ if(! -f $file) { # Old /proc interface
+ return sync_via_proc(@_);
+ }
+ open(F, "$file") or die "Failed to open $file for reading: $!";
+ $result = <F>;
+ close F;
+ chomp $result;
+ $result =~ s/^SYNC=\D*//;
+ if(defined $newsync) { # Now change
+ $newsync =~ s/.*/\U$&/;
+ if($newsync =~ /^(\d+)$/) {
+ $newsync = "SYNC=$1";
+ } elsif($newsync ne 'ZAPTEL') {
+ die "Bad sync parameter '$newsync'";
+ }
+ open(F, ">$file") or die "Failed to open $file for writing: $!";
+ print F $newsync;
+ close(F) or die "Failed in closing $file: $!";
+ }
+ return $result;
+}
+
=head1 SEE ALSO
=over
diff --git a/kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm b/kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm
index 2472c3b..895e4f2 100644
--- a/kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm
+++ b/kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm
@@ -10,8 +10,6 @@ package Zaptel::Xpp::Line;
use strict;
use Zaptel::Utils;
-my $proc_base = "/proc/xpp";
-
sub new($$$) {
my $pack = shift or die "Wasn't called as a class method\n";
my $xpd = shift or die;
@@ -28,30 +26,15 @@ sub blink($$) {
my $self = shift;
my $on = shift;
my $xpd = $self->xpd;
- my $result;
-
- my $file = "$proc_base/" . $xpd->fqn . "/blink";
- die "$file is missing" unless -f $file;
- # First query
- open(F, "$file") or die "Failed to open $file for reading: $!";
- $result = <F>;
- chomp $result;
- close F;
+ my $result = $xpd->xpd_getattr("blink");
+ $result = hex($result);
if(defined($on)) { # Now change
my $onbitmask = 1 << $self->index;
my $offbitmask = $result & ~$onbitmask;
$result = $offbitmask;
$result |= $onbitmask if $on;
- open(F, ">$file") or die "Failed to open $file for writing: $!";
- print F "$result";
- if(!close(F)) {
- if($! == 17) { # EEXISTS
- # good
- } else {
- undef $result;
- }
- }
+ $result = $xpd->xpd_setattr("blink", $result);
}
return $result;
}
@@ -67,25 +50,36 @@ sub create_all($$) {
push(@lines, $line);
}
$xpd->{LINES} = \@lines;
- my ($infofile) = glob "$procdir/*_info";
- die "Failed globbing '$procdir/*_info'" unless defined $infofile;
- my $type = $xpd->type;
- open(F, "$infofile") || die "Failed opening '$infofile': $!";
- my $battery_info = 0;
- while (<F>) {
- chomp;
- if($type eq 'FXO') {
- $battery_info = 1 if /^Battery:/;
- if($battery_info && s/^\s*on\s*:\s*//) {
- my @batt = split;
- foreach my $l (@lines) {
- die unless @batt;
- my $state = shift @batt;
- $l->{BATTERY} = ($state eq '+') ? 1 : 0;
+ if($xpd->type eq 'FXO') {
+ my $battery = $xpd->xpd_getattr("fxo_battery");
+ if(defined $battery) {
+ my @batt = split(/\s+/, $battery);
+ foreach my $l (@lines) {
+ die unless @batt;
+ my $state = shift @batt;
+ $l->{BATTERY} = ($state eq '+') ? 1 : 0;
+ }
+ } else {
+ # Fallback to old interface
+ my ($infofile) = glob "$procdir/*_info";
+ die "Failed globbing '$procdir/*_info'" unless defined $infofile;
+ open(F, "$infofile") || die "Failed opening '$infofile': $!";
+ my $battery_info = 0;
+ while (<F>) {
+ chomp;
+ $battery_info = 1 if /^Battery:/;
+ if($battery_info && s/^\s*on\s*:\s*//) {
+ my @batt = split;
+ foreach my $l (@lines) {
+ die unless @batt;
+ my $state = shift @batt;
+ $l->{BATTERY} = ($state eq '+') ? 1 : 0;
+ }
+ $battery_info = 0;
+ die if @batt;
}
- $battery_info = 0;
- die if @batt;
}
+ close F;
}
}
close F;
diff --git a/kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm b/kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm
index e840f14..f87e2aa 100644
--- a/kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm
+++ b/kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm
@@ -40,49 +40,135 @@ sub get_xpd_by_number($$) {
my $xbus = shift;
my $xpdid = shift;
die "Missing XPD id parameter" unless defined $xpdid;
+ $xpdid = sprintf("%02d", $xpdid);
my @xpds = $xbus->xpds;
my ($wanted) = grep { $_->id eq $xpdid } @xpds;
return $wanted;
}
+my %file_warned; # Prevent duplicate warnings about same file.
+
+sub xbus_attr_path($$) {
+ my ($busnum, @attr) = @_;
+ foreach my $attr (@attr) {
+ my $file = sprintf "$Zaptel::Xpp::sysfs_astribanks/xbus-%02d/$attr", $busnum;
+ unless(-f $file) {
+ my $procfile = sprintf "/proc/xpp/XBUS-%02d/$attr", $busnum;
+ warn "$0: warning - OLD DRIVER: missing '$file'. Fall back to '$procfile'\n"
+ unless $file_warned{$attr}++;
+ $file = $procfile;
+ }
+ next unless -f $file;
+ return $file;
+ }
+ return undef;
+}
+
+sub xbus_getattr($$) {
+ my $xbus = shift || die;
+ my $attr = shift || die;
+ $attr = lc($attr);
+ my $file = xbus_attr_path($xbus->num, lc($attr));
+
+ open(F, $file) || die "Failed opening '$file': $!";
+ my $val = <F>;
+ close F;
+ chomp $val;
+ return $val;
+}
+
+sub read_attrs() {
+ my $xbus = shift || die;
+ my @attrnames = qw(CONNECTOR LABEL STATUS);
+ my @attrs;
+
+ foreach my $attr (@attrnames) {
+ my $val = xbus_getattr($xbus, $attr);
+ if($attr eq 'STATUS') {
+ # Some values are in all caps as well
+ $val = uc($val);
+ } elsif($attr eq 'LABEL') {
+ # Fix badly burned labels.
+ $val =~ s/[[:^print:]]/_/g;
+ }
+ $xbus->{$attr} = $val;
+ }
+}
+
+sub read_xpdnames_old($) {
+ my $xbus_num = shift || die;
+ my $pat = sprintf "/proc/xpp/XBUS-%02d/XPD-[0-9][0-9]", $xbus_num;
+ my @xpdnames;
+
+ #print STDERR "read_xpdnames_old($xbus_num): $pat\n";
+ foreach (glob $pat) {
+ die "Bad /proc entry: '$_'" unless /^.*XPD-([0-9])([0-9])$/;
+ my $name = sprintf("%02d:%1d:%1d", $xbus_num, $1, $2);
+ #print STDERR "\t> $_ ($name)\n";
+ push(@xpdnames, $name);
+ }
+ return @xpdnames;
+}
+
+sub read_xpdnames($) {
+ my $xbus_num = shift || die;
+ my $xbus_dir = "$Zaptel::Xpp::sysfs_astribanks/xbus-$xbus_num";
+ my $pat = sprintf "%s/xbus-%02d/[0-9][0-9]:[0-9]:[0-9]", $Zaptel::Xpp::sysfs_astribanks, $xbus_num;
+ my @xpdnames;
+
+ #print STDERR "read_xpdnames($xbus_num): $pat\n";
+ foreach (glob $pat) {
+ die "Bad /sys entry: '$_'" unless m/^.*\/([0-9][0-9]):([0-9]):([0-9])$/;
+ my ($busnum, $unit, $subunit) = ($1, $2, $3);
+ my $name = sprintf("%02d:%1d:%1d", $1, $2, $3);
+ #print STDERR "\t> $_ ($name)\n";
+ push(@xpdnames, $name);
+ }
+ return @xpdnames;
+}
+
+my $warned_notransport = 0;
+
sub new($$) {
my $pack = shift or die "Wasn't called as a class method\n";
- my $self = {};
+ my $num = shift;
+ my $xbus_dir = "$Zaptel::Xpp::sysfs_astribanks/xbus-$num";
+ my $self = {
+ NUM => $num,
+ NAME => "XBUS-$num",
+ SYSFS_DIR => $xbus_dir,
+ };
bless $self, $pack;
- while(@_) {
- my ($k, $v) = @_;
- shift; shift;
- # Keys in all caps
- $k = uc($k);
- # Some values are in all caps as well
- if($k =~ /^(STATUS)$/) {
- $v = uc($v);
+ $self->read_attrs;
+ # Get transport related info
+ my $transport = "$xbus_dir/transport";
+ my ($usbdev) = glob("$transport/usb_device:*");
+ if(defined $usbdev) { # It's USB
+ if($usbdev =~ /.*usb_device:usbdev(\d+)\.(\d+)/) {
+ my $busnum = $1;
+ my $devnum = $2;
+ #printf STDERR "DEBUG: %03d/%03d\n", $busnum, $devnum;
+ $self->{USB_DEVNAME} = sprintf("%03d/%03d", $busnum, $devnum);
+ } else {
+ warn "Bad USB transport='$transport' usbdev='$usbdev'\n";
}
- $self->{$k} = $v;
- }
- # backward compat for drivers without labels.
- if(!defined $self->{LABEL}) {
- $self->{LABEL} = '[]';
}
- $self->{LABEL} =~ s/^\[(.*)\]$/$1/ or die "$self->{NAME}: Bad label";
- # Fix badly burned labels.
- $self->{LABEL} =~ s/[[:^print:]]/_/g;
- $self->{NAME} or die "Missing xbus name";
- my $prefix = "$proc_base/" . $self->{NAME};
- my $usbfile = "$prefix/xpp_usb";
- if(open(F, "$usbfile")) {
- my $head = <F>;
- chomp $head;
- close F;
- $head =~ s/^device: +([^, ]+)/$1/i or die;
- $self->{USB_DEVNAME} = $head;
+ my @xpdnames;
+ my @xpds;
+ if(-e $transport) {
+ @xpdnames = read_xpdnames($num);
+ } else {
+ @xpdnames = read_xpdnames_old($num);
+ warn "$0: warning - OLD DRIVER: missing '$transport'. Fall back to /proc\n"
+ unless $warned_notransport++;
}
- @{$self->{XPDS}} = ();
- foreach my $dir (glob "$prefix/XPD-??") {
- my $xpd = Zaptel::Xpp::Xpd->new($self, $dir);
- push(@{$self->{XPDS}}, $xpd);
+ foreach my $xpdstr (@xpdnames) {
+ my ($busnum, $unit, $subunit) = split(/:/, $xpdstr);
+ my $procdir = "/proc/xpp/XBUS-$busnum/XPD-$unit$subunit";
+ my $xpd = Zaptel::Xpp::Xpd->new($self, $unit, $subunit, $procdir, "$xbus_dir/$xpdstr");
+ push(@xpds, $xpd);
}
- @{$self->{XPDS}} = sort { $a->id <=> $b->id } @{$self->{XPDS}};
+ @{$self->{XPDS}} = sort { $a->id <=> $b->id } @xpds;
return $self;
}
diff --git a/kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm b/kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm
index 1ddb5c8..30a0bad 100644
--- a/kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm
+++ b/kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm
@@ -12,31 +12,127 @@ use Zaptel::Utils;
use Zaptel::Xpp;
use Zaptel::Xpp::Line;
-my $proc_base = "/proc/xpp";
+my %file_warned; # Prevent duplicate warnings about same file.
-sub blink($$) {
- my $self = shift;
- my $on = shift;
- my $result;
+sub xpd_attr_path($@) {
+ my $self = shift || die;
+ my ($busnum, $unitnum, $subunitnum, @attr) = (
+ $self->xbus->num,
+ $self->unit,
+ $self->subunit,
+ @_);
+ foreach my $attr (@attr) {
+ my $file = sprintf "$Zaptel::Xpp::sysfs_xpds/%02d:%1d:%1d/$attr",
+ $busnum, $unitnum, $subunitnum;
+ unless(-f $file) {
+ my $procfile = sprintf "/proc/xpp/XBUS-%02d/XPD-%1d%1d/$attr",
+ $busnum, $unitnum, $subunitnum;
+ warn "$0: warning - OLD DRIVER: missing '$file'. Fall back to /proc\n"
+ unless $file_warned{$attr}++;
+ $file = $procfile;
+ }
+ next unless -f $file;
+ return $file;
+ }
+ return undef;
+}
- my $file = "$proc_base/" . $self->fqn . "/blink";
- die "$file is missing" unless -f $file;
- # First query
- open(F, "$file") or die "Failed to open $file for reading: $!";
- $result = <F>;
- chomp $result;
+# Backward compat plug for old /proc interface...
+sub xpd_old_gettype($) {
+ my $xpd = shift || die;
+ my $summary = "/proc/xpp/" . $xpd->fqn . "/summary";
+ open(F, $summary) or die "Failed to open '$summary': $!";
+ my $head = <F>;
close F;
- if(defined($on) and $on ne $result) { # Now change
- open(F, ">$file") or die "Failed to open $file for writing: $!";
- print F ($on)?"0xFFFF":"0";
- if(!close(F)) {
- if($! == 17) { # EEXISTS
- # good
- } else {
- undef $result;
- }
+ chomp $head;
+ $head =~ s/^XPD-\d+\s+\(//;
+ $head =~ s/,.*//;
+ return $head;
+}
+
+sub xpd_old_getspan($) {
+ my $xpd = shift || die;
+ my $zt_registration = "/proc/xpp/" . $xpd->fqn . "/zt_registration";
+ open(F, $zt_registration) or die "Failed to open '$zt_registration': $!";
+ my $head = <F>;
+ close F;
+ chomp $head;
+ return $head;
+}
+
+sub xpd_old_getoffhook($) {
+ my $xpd = shift || die;
+ my $summary = "/proc/xpp/" . $xpd->fqn . "/summary";
+ my $channels;
+
+ local $/ = "\n";
+ open(F, "$summary") || die "Failed opening $summary: $!\n";
+ my $head = <F>;
+ chomp $head; # "XPD-00 (BRI_TE ,card present, span 3)"
+ my $offhook;
+ while(<F>) {
+ chomp;
+ if(s/^\s*offhook\s*:\s*//) {
+ s/\s*$//;
+ $offhook = $_;
+ $offhook || die "No channels in '$summary'";
+ last;
}
}
+ close F;
+ return $offhook;
+}
+
+my %attr_missing_warned; # Prevent duplicate warnings
+
+sub xpd_getattr($$) {
+ my $xpd = shift || die;
+ my $attr = shift || die;
+ $attr = lc($attr);
+ my $file = $xpd->xpd_attr_path(lc($attr));
+
+ # Handle special cases for backward compat
+ return xpd_old_gettype($xpd) if $attr eq 'type' and !defined $file;
+ return xpd_old_getspan($xpd) if $attr eq 'span' and !defined $file;
+ return xpd_old_getoffhook($xpd) if $attr eq 'offhook' and !defined $file;
+ if(!defined($file)) {
+ warn "$0: xpd_getattr($attr) -- Missing attribute.\n" if
+ $attr_missing_warned{$attr};
+ return undef;
+ }
+ open(F, $file) || return undef;
+ my $val = <F>;
+ close F;
+ chomp $val;
+ return $val;
+}
+
+sub xpd_setattr($$$) {
+ my $xpd = shift || die;
+ my $attr = shift || die;
+ my $val = shift;
+ $attr = lc($attr);
+ my $file = xpd_attr_path($xpd, $attr);
+ my $oldval = $xpd->xpd_getattr($attr);
+ open(F, ">$file") or die "Failed to open $file for writing: $!";
+ print F "$val";
+ if(!close(F)) {
+ if($! == 17) { # EEXISTS
+ # good
+ } else {
+ return undef;
+ }
+ }
+ return $oldval;
+}
+
+sub blink($$) {
+ my $self = shift;
+ my $on = shift;
+ my $result = $self->xpd_getattr("blink");
+ if(defined($on)) { # Now change
+ $self->xpd_setattr("blink", ($on)?"0xFFFF":"0");
+ }
return $result;
}
@@ -44,8 +140,7 @@ sub zt_registration($$) {
my $self = shift;
my $on = shift;
my $result;
-
- my $file = "$proc_base/" . $self->fqn . "/zt_registration";
+ my $file = $self->xpd_attr_path("span", "zt_registration");
die "$file is missing" unless -f $file;
# First query
open(F, "$file") or die "Failed to open $file for reading: $!";
@@ -77,47 +172,86 @@ sub xpds_by_spanno() {
return @idx;
}
-sub new($$) {
+sub new($$$$$) {
my $pack = shift or die "Wasn't called as a class method\n";
my $xbus = shift || die;
+ my $unit = shift; # May be zero
+ my $subunit = shift; # May be zero
my $procdir = shift || die;
- my $self = {};
+ my $sysfsdir = shift || die;
+ my $self = {
+ XBUS => $xbus,
+ ID => "$unit$subunit",
+ FQN => $xbus->name . "/" . "XPD-$unit$subunit",
+ UNIT => $unit,
+ SUBUNIT => $subunit,
+ DIR => $procdir,
+ SYSFS_DIR => $sysfsdir,
+ };
bless $self, $pack;
- $self->{XBUS} = $xbus;
- $self->{DIR} = $procdir;
- local $/ = "\n";
- open(F, "$procdir/summary") || die "Missing summary file in $procdir";
- my $head = <F>;
- chomp $head; # "XPD-00 (BRI_TE ,card present, span 3)"
- # The driver does not export the number of channels...
- # Let's find it indirectly
- while(<F>) {
- chomp;
- if(s/^\s*offhook\s*:\s*//) {
- my @offhook = split;
- @offhook || die "No channels in '$procdir/summary'";
- $self->{CHANNELS} = @offhook;
- last;
- }
- }
- close F;
- $head =~ s/^(XPD-(\d\d))\s+// || die;
- $self->{ID} = $2;
- $self->{FQN} = $xbus->name . "/" . $1;
- $head =~ s/^.*\(// || die;
- $head =~ s/\) */, / || die;
- $head =~ s/\s*,\s*/,/g || die;
- my ($type,$present,$span,$rest) = split(/,/, $head);
- #warn "Garbage in '$procdir/summary': rest='$rest'\n" if $rest;
- if($span =~ s/span\s+(\d+)//) { # since changeset:5119
- $self->{SPANNO} = $1;
- }
+ my @offhook = split / /, ($self->xpd_getattr('offhook'));
+ $self->{CHANNELS} = @offhook;
+ my $type = $self->xpd_getattr('type');
+ my $span = $self->xpd_getattr('span');
+ $self->{SPANNO} = $span;
$self->{TYPE} = $type;
- $self->{IS_BRI} = ($type =~ /BRI_(NT|TE)/);
- $self->{IS_PRI} = ($type =~ /[ETJ]1_(NT|TE)/);
+ if($type =~ /BRI_(NT|TE)/) {
+ $self->{IS_BRI} = 1;
+ $self->{TERMTYPE} = $1;
+ }
+ $self->{IS_PRI} = ($type =~ /[ETJ]1/);
$self->{IS_DIGITAL} = ( $self->{IS_BRI} || $self->{IS_PRI} );
Zaptel::Xpp::Line->create_all($self, $procdir);
return $self;
}
+#------------------------------------
+# static xpd related helper functions
+#------------------------------------
+
+sub sync_priority_rank($) {
+ my $xpd = shift || die;
+ # The @rank array is ordered by priority of sync (good to bad)
+ my @rank = (
+ ($xpd->is_pri and defined($xpd->termtype) and $xpd->termtype eq 'TE'),
+ ($xpd->is_bri and defined($xpd->termtype) and $xpd->termtype eq 'TE'),
+ ($xpd->is_pri),
+ ($xpd->type eq 'FXO'),
+ ($xpd->is_bri),
+ ($xpd->type eq 'FXS'),
+ );
+ for(my $i = 0; $i < @rank; $i++) {
+ return $i if $rank[$i];
+ }
+ return @rank + 1;
+}
+
+# An XPD sync priority comparator for sort()
+sub sync_priority_compare() {
+ my $rank_a = sync_priority_rank($a);
+ my $rank_b = sync_priority_rank($b);
+ #print STDERR "DEBUG: $rank_a (", $a->fqn, ") $rank_b (", $b->fqn, ")\n";
+ return $a->fqn cmp $b->fqn if $rank_a == $rank_b;
+ return $rank_a <=> $rank_b;
+}
+
+# For debugging: show a list of XPD's with relevant sync info.
+sub show_xpd_rank(@) {
+ print STDERR "XPD's by rank\n";
+ foreach my $xpd (@_) {
+ my $type = $xpd->type;
+ my $rank = sync_priority_rank($xpd);
+ if($xpd->is_digital) {
+ $type .= " (TERMTYPE " . ($xpd->termtype || "UNKNOWN") . ")";
+ }
+ printf STDERR "%3d %-15s %s\n", $rank, $xpd->fqn, $type;
+ }
+}
+
+sub xpds_by_rank(@) {
+ my @xpd_prio = sort sync_priority_compare @_;
+ #show_xpd_rank(@xpd_prio);
+ return @xpd_prio;
+}
+
1;
diff --git a/kernel/xpp/utils/zt_registration b/kernel/xpp/utils/zt_registration
index 3bdc642..4ae5a66 100755
--- a/kernel/xpp/utils/zt_registration
+++ b/kernel/xpp/utils/zt_registration
@@ -15,11 +15,26 @@ use Zaptel;
use Zaptel::Span;
use Zaptel::Xpp;
use Zaptel::Xpp::Xbus;
+use Getopt::Std;
sub usage {
die "Usage: $0 [on|off|1|0]\n";
}
+my %opts;
+getopts('s:', \%opts);
+
+my $sort_order = $opts{s} || $ENV{XBUS_SORT} || 'SORT_CONNECTOR';
+my $sorter = Zaptel::Xpp::sorters($sort_order);
+
+if(!defined $sorter) {
+ my @sorter_names = Zaptel::Xpp::sorters;
+ print STDERR "Unknown sort order $sort_order. Select from:\n\t";
+ print STDERR join("\n\t", @sorter_names);
+ print STDERR "\n";
+ exit 1;
+}
+
@ARGV == 0 or @ARGV == 1 or usage;
my $on = shift;
my $verbose = 0;
@@ -42,7 +57,7 @@ sub myprintf {
my @spans = Zaptel::spans;
-foreach my $xbus (Zaptel::Xpp::xbuses('SORT_CONNECTOR')) {
+foreach my $xbus (Zaptel::Xpp::xbuses($sorter)) {
myprintf "%-10s\t%s\t%s\n", $xbus->name, $xbus->label, $xbus->connector;
next unless $xbus->status eq 'CONNECTED';
foreach my $xpd ($xbus->xpds()) {
@@ -61,6 +76,7 @@ foreach my $xbus (Zaptel::Xpp::xbuses('SORT_CONNECTOR')) {
myprintf "%3s ==> %3s\n", state2str($prev), state2str($on);
}
}
+myprintf "# Sorted: $sort_order\n";
__END__
@@ -70,7 +86,7 @@ zt_registration - Handle registration of Xorcom XPD modules in zaptel.
=head1 SYNOPSIS
-zt_registration [on|off]
+zt_registration [-s sortorder] [on|off]
=head1 DESCRIPTION
@@ -90,25 +106,46 @@ off -- deregisters all XPD's from zaptel.
on -- registers all XPD's to zaptel.
+=head2 Options
+
+=over
+
+=item -s I<sort_order>
+
+The sort order to use.
+
+=back
+
+If the option is not used, the sort order is taken from the environment
+variable XBUS_SORT and failing that: the hard-coded default of
+SORT_CONNECTOR.
+
+The available sorting orders are documented in Zaptel::Xpp manual.
+
+
+
=head2 Sample Output
An example of the output of zt_registration for some registered
Astribanks:
- $ zt_registration
- XBUS-02 [] usb-0000:00:1d.7-4
- XBUS-00/XPD-00: on Span 1
- XBUS-00/XPD-10: on Span 2
- XBUS-00 [usb:00000126] usb-0000:00:1d.7-2
- XBUS-02/XPD-00: on Span 3
- XBUS-02/XPD-10: on Span 4
- XBUS-02/XPD-20: on Span 5
- XBUS-02/XPD-30: on Span 6
- XBUS-01 [usb:00000128] usb-0000:00:1d.7-1
- XBUS-01/XPD-00: on Span 7
- XBUS-01/XPD-10: on Span 8
- XBUS-01/XPD-20: on Span 9
- XBUS-01/XPD-30: on Span 10
+ $ zt_registration -s type
+ XBUS-01 usb:0000153 usb-0000:00:10.4-2
+ XBUS-01/XPD-00: on Span 1
+ XBUS-01/XPD-01: on Span 2
+ XBUS-00 usb:0000157 usb-0000:00:10.4-4
+ XBUS-00/XPD-00: on Span 3
+ XBUS-00/XPD-01: on Span 4
+ XBUS-00/XPD-02: on Span 5
+ XBUS-00/XPD-03: on Span 6
+ XBUS-00/XPD-04: on Span 7
+ XBUS-00/XPD-05: on Span 8
+ XBUS-00/XPD-06: on Span 9
+ XBUS-00/XPD-07: on Span 10
+ XBUS-02 usb-0000:00:10.4-1
+ XBUS-02/XPD-00: on Span 11
+ XBUS-02/XPD-10: on Span 12
+ # Sorted: type
=head1 FILES