summaryrefslogtreecommitdiff
path: root/xpp/utils
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/utils')
-rw-r--r--xpp/utils/Makefile16
-rw-r--r--xpp/utils/fpga_load.c18
-rwxr-xr-xxpp/utils/genzaptelconf152
-rwxr-xr-xxpp/utils/lszaptel70
-rw-r--r--xpp/utils/xpp.rules2
-rwxr-xr-xxpp/utils/xpp_blink8
-rwxr-xr-xxpp/utils/xpp_sync86
-rwxr-xr-xxpp/utils/zapconf275
-rwxr-xr-xxpp/utils/zaptel_hardware12
-rw-r--r--xpp/utils/zconf/Zaptel/Chans.pm15
-rw-r--r--xpp/utils/zconf/Zaptel/Config/Defaults.pm29
-rw-r--r--xpp/utils/zconf/Zaptel/Hardware.pm8
-rw-r--r--xpp/utils/zconf/Zaptel/Hardware/PCI.pm1
-rw-r--r--xpp/utils/zconf/Zaptel/Span.pm34
-rwxr-xr-xxpp/utils/zt_registration41
15 files changed, 552 insertions, 215 deletions
diff --git a/xpp/utils/Makefile b/xpp/utils/Makefile
index f9d034a..72ba74d 100644
--- a/xpp/utils/Makefile
+++ b/xpp/utils/Makefile
@@ -31,6 +31,7 @@ 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_?_*) ../calibrate_slics xpp_fxloader
+XPD_INIT_PERL = ../init_card_6_26 ../init_card_7_26
# Variables that should be defined above, but need sane defaults:
# FIXME: Are those values really sane?
@@ -48,7 +49,15 @@ CFLAGS = -g -Wall $(EXTRA_CFLAGS)
%.8: %
pod2man --section 8 $^ > $@ || $(RM) $@
-PERL_SCRIPTS = zt_registration xpp_sync lszaptel xpp_blink
+PERL_SCRIPTS = \
+ zt_registration \
+ xpp_sync \
+ lszaptel \
+ xpp_blink \
+ zapconf \
+ zaptel_hardware \
+ #
+
PERL_MANS = $(PERL_SCRIPTS:%=%.8)
TARGETS = init_fxo_modes print_modes
@@ -63,7 +72,7 @@ PROG_INSTALL += $(PERL_SCRIPTS)
TARGETS += $(PERL_MANS)
endif
-all: $(TARGETS)
+all: perlcheck $(TARGETS)
docs: $(PERL_MANS)
@@ -120,5 +129,8 @@ wctdm_fxomodes.h: $(WCTDM)
init_fxo_modes: print_modes
./$< >$@
+perlcheck: $(PERL_SCRIPTS) $(XPD_INIT_PERL)
+ for i in $^; do perl -I./zconf -c $$i || exit 1; done
+
clean:
$(RM) *.o $(TARGETS)
diff --git a/xpp/utils/fpga_load.c b/xpp/utils/fpga_load.c
index 1cbd749..cc9cf81 100644
--- a/xpp/utils/fpga_load.c
+++ b/xpp/utils/fpga_load.c
@@ -107,6 +107,18 @@ const char *load_status2str(enum fpga_load_status s)
}
}
+/* return 1 if:
+ * - str has a number
+ * - It is larger than 0
+ * - It equals num
+ */
+int num_matches(int num, const char* str) {
+ int str_val = atoi(str);
+ if (str_val <= 0)
+ return 0;
+ return (str_val == num);
+}
+
struct usb_device *dev_of_path(const char *path)
{
struct usb_bus *bus;
@@ -149,10 +161,12 @@ struct usb_device *dev_of_path(const char *path)
sprintf(dirname, "%03d", bnum);
sprintf(filename, "%03d", dnum);
for (bus = usb_busses; bus; bus = bus->next) {
- if(strcmp(bus->dirname, dirname) != 0)
+ if (! num_matches(bnum, bus->dirname))
+ //if(strcmp(bus->dirname, dirname) != 0)
continue;
for (dev = bus->devices; dev; dev = dev->next) {
- if(strcmp(dev->filename, filename) == 0)
+ //if(strcmp(dev->filename, filename) == 0)
+ if (num_matches(dnum, dev->filename))
return dev;
}
}
diff --git a/xpp/utils/genzaptelconf b/xpp/utils/genzaptelconf
index daccee8..cf32fcd 100755
--- a/xpp/utils/genzaptelconf
+++ b/xpp/utils/genzaptelconf
@@ -516,9 +516,8 @@ unload_module() {
set -- $line
# $1: the original module, $2: size, $3: refcount, $4: deps list
mods=`echo $4 | tr , ' '`
- # old versions of xpd_fxs actually depend on xpp, but forget to tell it.
- # bug has already been fixed but the code will remain here for a while
- # just in case
+ # xpp_usb keeps the xpds below busy, and hence must be removed
+ # before them:
case "$module" in xpd_*) mods="xpp_usb $mods";; esac
for mod in $mods; do
# run in a subshell, so it won't step over our vars:
@@ -583,7 +582,9 @@ temporary_zapconf() {
save)
say "Temporarily moving zaptel.conf aside to work around broken modprobe.conf"
ZAPCONF_FILE_TMP=`mktemp /tmp/genzaptelconf-zaptel.conf-XXXXXX` || die "Error creating temporary zaptel.conf"
- cp -a $ZAPCONF_FILE_SYSTEM $ZAPCONF_FILE_TMP
+ if [ -f $ZAPCONF_FILE_SYSTEM ]; then
+ cp -a $ZAPCONF_FILE_SYSTEM $ZAPCONF_FILE_TMP
+ fi
echo -n >$ZAPCONF_FILE_SYSTEM
;;
restore)
@@ -643,6 +644,8 @@ gen_tmp_conf() {
# Extract information from one digital channel (one line in a /proc/zaptel
# file). Information is saved to $tmp_dir/span_foo variables.
+# FIXME: detection should move to when we know the number of channels
+# and hence can tell between an E1 and a T1.
detect_digital_channel() {
line="$1"
chan_num="$2"
@@ -653,70 +656,78 @@ detect_digital_channel() {
# them by the channel names. This is shorter.
# This also allows us to count the channel numbers and check if
# we have a E1 span, a T1 span or a BRI span.
- if [ "`cat $tmp_dir/span_begin`" = "-1" ]
+
+ # span_lastd is always the one before last
+ # channel. span_bchan is the last:
+ echo $chan_num >$tmp_dir/span_end
+
+ if [ "`cat $tmp_dir/span_begin`" != "-1" ]
then
- echo $chan_num >$tmp_dir/span_begin
- echo $span_num >$tmp_dir/span_num
- # The Astribank channels provide the information of TE/NT in the channel name. So
- # why not use it?
- case "$line" in
- *XPP_BRI_TE/*) echo 'te' >$tmp_dir/span_termtype;;
- *XPP_BRI_NT/*) echo 'nt' >$tmp_dir/span_termtype;;
- esac
- case "$line" in
- *ZTHFC*/*|*ztqoz*/*|*XPP_BRI_*/*)
- # BRI channel
- echo 'ccs' >$tmp_dir/span_framing
- echo 'euroisdn' >$tmp_dir/span_switchtype
- if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ]
- then
- echo $ZAPBRI_NET >$tmp_dir/span_signalling
- else
- echo $ZAPBRI_CPE >$tmp_dir/span_signalling
- fi
+ return #we already configured this span.
+ fi
+
+ # Now we need to give initial configuration to the span
+ echo $chan_num >$tmp_dir/span_begin
+ echo $span_num >$tmp_dir/span_num
+
+ case "$line" in
+ *ZTHFC*/*|*ztqoz*/*|*XPP_BRI_*/*)
+ # BRI channel
+ echo 'ccs' >$tmp_dir/span_framing
+ echo 'euroisdn' >$tmp_dir/span_switchtype
+ if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ]
+ then
+ echo $ZAPBRI_NET >$tmp_dir/span_signalling
+ else
+ echo $ZAPBRI_CPE >$tmp_dir/span_signalling
+ fi
+ ;;
+ *ztgsm*/*)
+ # Junghanns's GSM cards.
+ echo 'ccs' >$tmp_dir/span_framing
+ #Does this mean anything?
+ echo 'gsm' >$tmp_dir/span_signalling
+ ;;
+ *TE[24]/*|*WCT1/*|*Tor2/*|*TorISA/*|*WP[TE]1/*)
+ # FIXME: handle cwain around here.
+ # name: *cwain[12]/* . Always E1.
+
+ # PRI span (E1/T1)
+ echo 'esf' >$tmp_dir/span_framing
+ echo 'b8zs' >$tmp_dir/span_coding
+ echo 'national' >$tmp_dir/span_switchtype
+ if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ]
+ then
+ echo pri_net >$tmp_dir/span_signalling
+ else
+ echo pri_cpe >$tmp_dir/span_signalling
+ fi
+ # an example of country-specific setup. This is probably not accurate
+ # Contributions are welcome
+ case "$lc_country" in
+ nl)
+ # (Just an example for per-country info)
+ echo 'ccs' >$tmp_dir/span_framing
+ echo 'ami' >$tmp_dir/span_coding
+ #echo 'crc4' >$tmp_dir/span_yellow
+ #echo 'euroisdn' >$tmp_dir/span_switchtype
+ #echo 'pri_cpe' >$tmp_dir/span_signalling
;;
- *ztgsm*/*)
- # Junghanns's GSM cards.
- echo 'ccs' >$tmp_dir/span_framing
- #Does this mean anything?
- echo 'gsm' >$tmp_dir/span_signalling
+ il|de|au)
+ echo 'ccs' >$tmp_dir/span_framing
+ echo 'hdb3' >$tmp_dir/span_coding
+ echo 'crc4' >$tmp_dir/span_yellow
+ echo 'euroisdn' >$tmp_dir/span_switchtype
;;
- *TE[24]/*|*WCT1/*|*Tor2/*|*TorISA/*|*WP[TE]1/*)
- # PRI span (E1/T1)
- echo 'esf' >$tmp_dir/span_framing
- echo 'b8zs' >$tmp_dir/span_coding
+ cl)
+ echo 'ccs' >$tmp_dir/span_framing
+ echo 'hdb3' >$tmp_dir/span_coding
+ #echo 'crc4' >$tmp_dir/span_yellow
echo 'national' >$tmp_dir/span_switchtype
- echo 'pri_cpe' >$tmp_dir/span_signalling
- # an example of country-specific setup. This is probably not accurate
- # Contributions are welcome
- case "$lc_country" in
- nl)
- # (Just an example for per-country info)
- echo 'ccs' >$tmp_dir/span_framing
- echo 'ami' >$tmp_dir/span_coding
- #echo 'crc4' >$tmp_dir/span_yellow
- #echo 'euroisdn' >$tmp_dir/span_switchtype
- #echo 'pri_cpe' >$tmp_dir/span_signalling
- ;;
- il|de|au)
- echo 'ccs' >$tmp_dir/span_framing
- echo 'hdb3' >$tmp_dir/span_coding
- echo 'crc4' >$tmp_dir/span_yellow
- echo 'euroisdn' >$tmp_dir/span_switchtype
- ;;
- cl)
- echo 'ccs' >$tmp_dir/span_framing
- echo 'hdb3' >$tmp_dir/span_coding
- #echo 'crc4' >$tmp_dir/span_yellow
- echo 'national' >$tmp_dir/span_switchtype
- ;;
- esac
- ;;
+ ;;
esac
- fi
- # span_lastd is always the one before last
- # channel. span_bchan is the last:
- echo $chan_num >$tmp_dir/span_end
+ ;;
+ esac
}
# read information from the $tmp_dir/span_foo files and generate
@@ -744,7 +755,7 @@ write_digital_config() {
31) #E1
dchan="$(($span_begin+15))"
bchans="$span_begin-$(($span_begin+14)),$(($span_begin+16))-$span_end"
- if [ "$span_switchtype" = 'national' ]; then
+ if [ "$span_framing" = 'esf' ]; then
# don't leave an E1 span with defective defaults:
span_framing=ccs
span_coding=hdb3
@@ -922,15 +933,14 @@ EOF
fi
# Check if ZapBRI cards are in TE or NT mode
- if echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[NT\]\ |octoBRI \[NT\] |HFC-S PCI A ISDN.* \[NT\] )'
+ if echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[NT\]\ |octoBRI \[NT\] |HFC-S PCI A ISDN.* \[NT\] |Xorcom .* BRI_NT)'
then
echo 'nt' >$tmp_dir/span_termtype
- else
- if echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[TE\]\ |octoBRI \[TE\] |HFC-S PCI A ISDN.* \[TE\] )'
- then
- echo 'te' >$tmp_dir/span_termtype
- fi
+ elif echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[TE\]\ |octoBRI \[TE\] |HFC-S PCI A ISDN.* \[TE\] |Xorcom .* BRI_TE)'
+ then
+ echo 'te' >$tmp_dir/span_termtype
fi
+
# The rest of the lines are per-channel lines
sed -e 1,2d $procfile | \
while read line
@@ -982,7 +992,7 @@ EOF
# Astribank FXS span (input port)
print_pattern -a input $chan_num fxo $mode
;;
- *ZTHFC*/*|*ztqoz*/*|*ztgsm/*|*TE[24]/*|*WCT1/*|*Tor2/*|*TorISA/*|*XPP_BRI_*/*|*WP[TE]1/*)
+ *ZTHFC*/*|*ztqoz*/*|*ztgsm/*|*TE[24]/*|*WCT1/*|*Tor2/*|*TorISA/*|*XPP_BRI_*/*|*WP[TE]1/*|*XPP_BRI*)
detect_digital_channel "$line" "$chan_num" "$span_num"
;;
'') ;; # Empty line (after span header)
diff --git a/xpp/utils/lszaptel b/xpp/utils/lszaptel
index ecb8ced..3126c8a 100755
--- a/xpp/utils/lszaptel
+++ b/xpp/utils/lszaptel
@@ -8,7 +8,8 @@
# $Id$
#
use strict;
-BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); }
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
use Zaptel;
use Zaptel::Span;
@@ -20,7 +21,7 @@ foreach my $span (Zaptel::spans()) {
OUT => 'Output',
IN => 'Input'
);
- my ($type) = map { $type_map{$_} or $_ } $chan->type;
+ my ($type) = map { $type_map{$_} or $_ } $chan->type || ("unknown");
printf "%3d %-10s %-10s %s\n", $chan->num, $type, $chan->signalling, $chan->info;
}
}
@@ -39,18 +40,53 @@ lszaptel
Example output:
- ### Span 1: XBUS-03/XPD-00 "Xorcom XPD #3/0: FXS"
- 1 FXS
- 2 FXS
- 3 FXS
- 4 FXS
- 5 FXS
- 6 FXS
- 7 FXS
- 8 FXS
- 9 Output
- 10 Output
- 11 Input
- 12 Input
- 13 Input
- 14 Input
+ ### Span 1: WCTDM/0 "Wildcard TDM400P REV E/F Board 1"
+ 1 FXO FXOLS (In use)
+ 2 FXS FXSKS
+ 3 FXS FXSKS
+ 4 FXS FXSKS
+ ### Span 2: XBUS-00/XPD-00 "Xorcom XPD #00/00: FXO"
+ 5 FXO FXSKS (In use)
+ 6 FXO FXSKS (In use) (no pcm)
+ 7 FXO FXSKS (In use) (no pcm)
+ 8 FXO FXSKS (In use) (no pcm)
+ 9 FXO FXSKS (In use) (no pcm)
+ 10 FXO FXSKS (In use) (no pcm)
+ 11 FXO FXSKS (In use) (no pcm)
+ 12 FXO FXSKS (In use) (no pcm)
+ ### Span 3: XBUS-00/XPD-10 "Xorcom XPD #00/10: FXO"
+ 13 FXO FXSKS (In use) (no pcm)
+ 14 FXO FXSKS (In use) (no pcm)
+ 15 FXO FXSKS (In use) (no pcm)
+ 16 FXO FXSKS (In use) (no pcm)
+ 17 FXO FXSKS (In use) (no pcm)
+ 18 FXO FXSKS (In use) (no pcm)
+ 19 FXO FXSKS (In use) (no pcm)
+ 20 FXO FXSKS (In use) (no pcm)
+
+ ...
+
+ ### Span 6: XBUS-01/XPD-00 "Xorcom XPD #01/00: FXS"
+ 37 FXS FXOLS (In use)
+ 38 FXS FXOLS (In use) (no pcm)
+ 39 FXS FXOLS (In use) (no pcm)
+ 40 FXS FXOLS (In use) (no pcm)
+ 41 FXS FXOLS (In use) (no pcm)
+ 42 FXS FXOLS (In use) (no pcm)
+ 43 FXS FXOLS (In use) (no pcm)
+ 44 FXS FXOLS (In use) (no pcm)
+ 45 Output FXOLS (In use) (no pcm)
+ 46 Output FXOLS (In use) (no pcm)
+ 47 Input FXOLS (In use) (no pcm)
+ 48 Input FXOLS (In use) (no pcm)
+ 49 Input FXOLS (In use) (no pcm)
+ 50 Input FXOLS (In use) (no pcm)
+
+The first column is the type of the channel (port, for an analog device)
+and the second one is the signalling (if set).
+
+=head1 FILES
+
+lszaptel is a somewhat glorified 'cat /proc/zaptel/*' . Unlike that
+command, it sorts the spans with the proper order. It also formats the
+output slightly differently.
diff --git a/xpp/utils/xpp.rules b/xpp/utils/xpp.rules
index 10e4c1a..a20acff 100644
--- a/xpp/utils/xpp.rules
+++ b/xpp/utils/xpp.rules
@@ -1,4 +1,6 @@
BUS!="usb", ACTION!="add", GOTO="xpp_usb_add_end"
+KERNEL=="*_ep*", GOTO="xpp_usb_add_end"
+KERNEL=="[0-9]*", GOTO="xpp_usb_add_end"
# Load firmware into the Xorcom Astribank device:
SYSFS{idVendor}=="e4e4", SYSFS{idProduct}=="11[345][01]", \
diff --git a/xpp/utils/xpp_blink b/xpp/utils/xpp_blink
index 1993a81..65be247 100755
--- a/xpp/utils/xpp_blink
+++ b/xpp/utils/xpp_blink
@@ -8,7 +8,8 @@
# $Id$
#
use strict;
-BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); }
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
use Zaptel;
use Zaptel::Span;
@@ -100,15 +101,18 @@ Blink all the leds of an XPD.
=over 16
=item span Select by span number. This only work for XPD registered to zaptel.
+ will also print the zaptel channels of the span and the
+ xbus/xpd this span represents.
=item xpd Select by xbus + xpd numbers. If only xbus number is given, all the
- XPDs of the selected xbus are blinked.
+ XPDs of the selected xbus (Astribank) are blinked.
=back
=head1 EXAMPLES
$ xpp_blink bzzt span 2
+ Using XBUS-04/XPD-10 (connected via usb-0000:00:1d.7-1): channels 15 16 17 18 19 20 21 22
$ xpp_blink xpd 0 1
diff --git a/xpp/utils/xpp_sync b/xpp/utils/xpp_sync
index d03c0a4..67825f8 100755
--- a/xpp/utils/xpp_sync
+++ b/xpp/utils/xpp_sync
@@ -8,7 +8,8 @@
# $Id$
#
use strict;
-BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); }
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
use Zaptel::Xpp;
use Zaptel::Xpp::Xbus;
@@ -38,10 +39,17 @@ sub get_sorted_xpds() {
}
}
- my @bri_xpds = grep { $_->type =~ /BRI/; } @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;
- return (@bri_xpds, @fxo_xpds, @fxs_xpds);
+
+ # Sync Priority
+ return
+ @bri_nt_xpds,
+ @fxo_xpds,
+ @bri_te_xpds,
+ @fxs_xpds;
}
sub do_select(@) {
@@ -88,13 +96,30 @@ sub show_sync() {
my @xpds = $xbus->xpds;
my @types = map { $_->type } @xpds;
my $mark = ($curr_sync =~ /\d+/ and $xbus->num == $curr_sync)?"+":"";
- printf "\t%1s %s [ ", $mark, $xbus->name;
- foreach my $x (sort { $a->num <=> $b->num } @xpds) {
- printf "%-3s ", $x->type;
+ my $xpdstr = '';
+ my @xpd_types = map { $_->type } sort { $a->num <=> $b->num } @xpds;
+ my $last_type = '';
+ my $mult = 0;
+ foreach my $curr (@xpd_types) {
+ if(!$last_type || ($curr eq $last_type)) {
+ $mult++;
+ } else {
+ if($mult == 1) {
+ $xpdstr .= "$last_type ";
+ } elsif($mult) {
+ $xpdstr .= "$last_type*$mult ";
+ }
+ $mult = 1;
+ }
+ $last_type = $curr;
}
- print "]";
- my $padding = ' ' x (4 * (8 - @xpds));
- printf "%s (%s)\n", $padding, $xbus->connector;
+ if($mult == 1) {
+ $xpdstr .= "$last_type ";
+ } elsif($mult) {
+ $xpdstr .= "$last_type*$mult ";
+ }
+ my $padding = ' ' x (40 - length $xpdstr);
+ printf " %1s %s [ %s]%s (%s)\n", $mark, $xbus->name, $xpdstr, $padding, $xbus->connector;
}
}
@@ -135,7 +160,7 @@ __END__
=head1 NAME
-xpp_sync - Handle sync selection of Xorcom XPD's.
+xpp_sync - Handle sync selection of Xorcom Astribanks.
=head1 SYNOPSIS
@@ -143,8 +168,15 @@ xpp_sync [auto|host|nn]
=head1 DESCRIPTION
-Without parameters, the current syncer. Either HOST or the XBUS number.
-Then a list of the 3 best XPD's for syncing.
+On a normal operation one Astribank device provides timing for all the
+other Astribank devices.
+
+When run without parameters, xpp_sync will display a list of Astribanks
+(xbuses) that are connected and registered as Zaptel spans. The current
+xpp sync master will be marked (if it is not HOST).
+
+If you this an Astribank is connected and yet it does not appear on the
+output of xpp_sync, it may be unregistered. Try running zt_registration .
=head2 Parameters
@@ -152,7 +184,7 @@ Then a list of the 3 best XPD's for syncing.
=item auto
-Automatically selects the best XPD for syncing (with HOST fallback).
+Automatically selects the best Astribank for syncing (with HOST fallback).
=item host
@@ -166,9 +198,27 @@ Set XBUS number nn as sync source.
=head2 Example output:
- Current sync: 03
+ Current sync: 02
Best Available Syncers:
- XBUS-00: FXS FXO (USB-0000:00:10.4-4)
- + XBUS-03: FXS FXS FXS FXS (USB-0000:00:10.4-1)
- XBUS-02: FXS FXS FXS FXS (USB-0000:00:10.4-2)
- XBUS-01: FXS FXS FXS FXS (USB-0000:00:10.4-3)
+ + XBUS-02 [ FXS*3 FXO ] (usb-0000:00:1d.7-3)
+ XBUS-04 [ FXS*4 ] (usb-0000:00:1d.7-1)
+ XBUS-03 [ FXS*4 ] (usb-0000:00:1d.7-2)
+ XBUS-01 [ FXS*4 ] (usb-0000:00:1d.7-4)
+ XBUS-00 [ FXS*4 ] (usb-0000:00:1d.7-5)
+ XBUS-05 [ FXS*4 ] (usb-0000:00:1d.7-6)
+
+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.
+
+=head1 FILES
+
+=over
+
+=item /proc/xpp/sync
+
+xpp_sync is essentially a nicer interface to /proc/xpp/sync . That file
+shows the current xpp sync master (and in what format you need to write
+to it to set the master).
+
+=back
diff --git a/xpp/utils/zapconf b/xpp/utils/zapconf
index 8bcca13..e1a6537 100755
--- a/xpp/utils/zapconf
+++ b/xpp/utils/zapconf
@@ -5,60 +5,103 @@
# This program is free software; you can redistribute and/or
# modify it under the same terms as Perl itself.
#
-# $Id:$
+# $Id$
#
use strict;
-BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); }
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
use Zaptel;
use Zaptel::Xpp;
+use Zaptel::Config::Defaults;
my %default_context = (
FXO => 'from-pstn',
FXS => 'from-internal',
IN => 'astbank-input',
- OUT => 'astbank-output'
+ OUT => 'astbank-output',
+ BRI_TE => 'from-pstn',
+ BRI_NT => 'from-internal',
+ PRI_TE => 'from-pstn',
+ PRI_NT => 'from-internal',
);
my %default_group = (
- FXO => '0',
- FXS => '5',
- IN => '5',
- OUT => '5'
+ FXO => 0,
+ FXS => 5,
+ IN => 5, # FIXME: no need for group?
+ OUT => 5, # FIXME: no need for group?
+ BRI_TE => 0,
+ BRI_NT => 5,
+ PRI_TE => 0,
+ PRI_NT => 5,
);
-my @zaptel_default_vars = qw(
- base_exten
- lc_country
- context_lines
- context_phones
- context_input
- context_output
- group_lines
- group_phones
+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 $fxs_default_start;
my $lc_country = 'us';
-my $loadzone;
-my $defaultzone;
+my $loadzone = $lc_country;
+my $defaultzone = $lc_country;
+my $bri_sig_style = 'bri_ptmp';
+
+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,
+ );
sub map_zaptel_defaults {
my %defaults = @_;
-
- $default_group{FXO} = $defaults{group_lines}
- if defined $defaults{group_lines};
- $default_group{FXS} = $default_group{IN} = $default_group{OUT} = $defaults{group_phones}
- if defined $defaults{group_phones};
- $default_context{FXO} ||= $defaults{context_lines};
- $default_context{FXS} ||= $defaults{context_phones};
- $default_context{IN} ||= $defaults{context_input};
- $default_context{OUT} ||= $defaults{context_output};
- $fxs_immediate ||= $defaults{fxs_immediate};
- $fxs_default_start ||= $defaults{fxs_default_start} || 'ls';
- $lc_country ||= $defaults{lc_country};
- $loadzone = $defaultzone = $lc_country;
+ 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;
+ }
+ }
}
@@ -71,12 +114,25 @@ sub bchan_range($) {
my $span = shift || die;
my $first_chan = ($span->chans())[0];
my $first_num = $first_chan->num();
- my $range;
-
- if($span->is_bri()) {
- $range = sprintf "%d-%d", $first_num, $first_num + 1;
+ 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;
}
- return $range;
+ if($prev >= $first_num) {
+ push(@range, sprintf("%d-%d", $range_start, $prev));
+ }
+ return join(',', @range);
}
sub gen_zaptel_signalling($) {
@@ -84,31 +140,26 @@ sub gen_zaptel_signalling($) {
my $type = $chan->type;
my $num = $chan->num;
- if($type eq 'FXO') {
- printf "fxsks=%d\n", $num;
- } elsif($type eq 'FXS') {
- printf "fxo%s=%d\n", $fxs_default_start, $num;
- } elsif ($type eq 'IN') {
+ die "channel $num type $type is not an analog channel\n" if $chan->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 $chan type $type";
+ if ($type eq 'IN') {
printf "# astbanktype: input\n";
- printf "fxo%s=%d\n", $fxs_default_start, $num;
} elsif ($type eq 'OUT') {
printf "# astbanktype: output\n";
- printf "fxo%s=%d\n", $fxs_default_start, $num;
- } elsif ($type eq 'BRI_TE') {
- printf "# termtype: te\n";
- } elsif ($type eq 'BRI_NT') {
- printf "# termtype: nt\n";
- } elsif($type eq 'EMPTY') {
- printf "# channel %d, %s, no module.\n", $num, $chan->fqn;
- return;
}
+ printf "$sig=$num\n";
}
my $bri_te_last_timing = 1;
sub gen_zaptel_digital($) {
my $span = shift || die;
- my $num = $span->num();
+ 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 = 1;
@@ -133,7 +184,7 @@ sub gen_zaptel_digital($) {
sub gen_zaptelconf($) {
my $file = shift || die;
rename "$file", "$file.bak"
- or $!{ENOENT}
+ 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;
@@ -146,7 +197,7 @@ sub gen_zaptelconf($) {
HEAD
foreach my $span (@spans) {
printf "# Span %d: %s %s\n", $span->num, $span->name, $span->description;
- if($span->is_bri()) {
+ if($span->is_digital()) {
gen_zaptel_digital($span);
} else {
foreach my $chan ($span->chans()) {
@@ -172,38 +223,65 @@ TAIL
select $old;
}
+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"};
+
+ 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($bri_sig_style eq 'bri_ptmp') {
+ $sig .= '_ptmp';
+ }
+ $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);
+ printf "group=\ncontext=default\n";
+}
+
sub gen_zapata_channel($) {
my $chan = shift || die;
my $type = $chan->type;
my $num = $chan->num;
- my $sig;
- my $immediate;
- my $callerid = sprintf "\"Channel %d\" <4%03d>", $num, $num;
+ die "channel $num type $type is not an analog channel\n" if $chan->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;
- if ($type eq 'FXO') {
- $sig = "fxs_ks";
- $callerid = 'asreceived';
- } elsif($type eq 'FXS') {
- $sig = "fxo_" . $fxs_default_start;
- $immediate = 'yes' if $fxs_immediate eq 'yes';
- } elsif($type eq 'IN') {
- $sig = "fxo_" . $fxs_default_start;
+ 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';
- } elsif($type eq 'OUT') {
- $sig = "fxo_" . $fxs_default_start;
- } elsif($type eq 'EMPTY') {
- return;
}
- die "Unknown signalling for channel $num type $type\n"
- unless defined $sig;
- printf ";;; line=\"%d %s\"\n", $num, $chan->fqn;
+ # 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=4%03d\n", $num unless $type eq 'FXO';
+ printf "mailbox=%04d\n", $exten unless $type eq 'FXO';
if(defined $group) {
- printf "group=%d\n", $group;
+ printf "group=$group\n";
}
printf "context=$context\n";
printf "immediate=$immediate\n" if defined $immediate;
@@ -222,11 +300,11 @@ sub gen_zapata_channel($) {
sub gen_zapataconf($) {
my $file = shift || die;
rename "$file", "$file.bak"
- or $!{ENOENT}
+ 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);
+ printf "; Autogenerated by %s on %s -- do not hand edit\n", $0, scalar(localtime);
print <<"HEAD";
; Zaptel Channels Configurations (zapata.conf)
;
@@ -237,8 +315,12 @@ sub gen_zapataconf($) {
HEAD
foreach my $span (@spans) {
printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
- foreach my $chan ($span->chans()) {
- gen_zapata_channel($chan);
+ if($span->is_digital()) {
+ gen_zapata_digital($span);
+ } else {
+ foreach my $chan ($span->chans()) {
+ gen_zapata_channel($chan);
+ }
}
print "\n";
}
@@ -246,23 +328,6 @@ HEAD
select $old;
}
-# Use the shell to source a file and expand a given list
-# of variables.
-sub do_source($@) {
- my $file = shift;
- my @vars = @_;
- my @output = `env -i sh -e -c '. $file; export @vars; env'`;
- die "$0: Sourcing '$file' exited with $?" if $?;
- my %vars;
-
- foreach my $line (@output) {
- chomp $line;
- my ($k, $v) = split(/=/, $line, 2);
- $vars{$k} = $v if grep /^$k$/, @vars;
- }
- return %vars;
-}
-
sub set_defaults {
my $zaptel_boot_debian = $ENV{ZAPTEL_BOOT_DEBIAN} || "/etc/default/zaptel";
my $zaptel_boot_fedora = $ENV{ZAPTEL_BOOT_FEDORA} || "/etc/sysconfig/zaptel";
@@ -270,7 +335,9 @@ sub set_defaults {
# Source default files
my %source_defaults;
foreach my $defaults ($zaptel_boot_debian, $zaptel_boot_fedora) {
- %source_defaults = do_source($defaults, @zaptel_default_vars) if -r $defaults;
+ %source_defaults = Zaptel::Config::Defaults::do_source(
+ $defaults, keys(%zaptel_default_vars))
+ if -r $defaults;
}
map_zaptel_defaults(%source_defaults);
$zapconf_file = $ENV{ZAPCONF_FILE} || "/etc/zaptel.conf";
@@ -293,3 +360,19 @@ zapconf
=head1 DESCRIPTION
+This script generate configuration files for Zaptel hardware.
+Currently it generate two files:
+
+=over 4
+
+=item /etc/zaptel.conf
+
+Configuration for ztcfg(1). It's location may be overriden by the
+environment variable ZAPCONF_FILE.
+
+=item /etc/asterisk/zapata-channels.conf
+
+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.
+
+=back
diff --git a/xpp/utils/zaptel_hardware b/xpp/utils/zaptel_hardware
index 26aa839..afd3a06 100755
--- a/xpp/utils/zaptel_hardware
+++ b/xpp/utils/zaptel_hardware
@@ -5,10 +5,11 @@
# This program is free software; you can redistribute and/or
# modify it under the same terms as Perl itself.
#
-# $Id:$
+# $Id$
#
use strict;
-BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); }
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
use Zaptel;
use Zaptel::Span;
@@ -22,6 +23,8 @@ sub usage {
@ARGV == 0 or usage;
+Zaptel::Hardware->scan_hardware;
+
my @hardware = Zaptel::Hardware->devices;
my @spans = Zaptel::spans;
@@ -89,3 +92,8 @@ zaptel_hardware
Show all zaptel hardware devices, both used and unused.
+=head1 BUGS
+
+Assumes a bit too much about the output of lspci and sysfs. Currently
+the PCI scanning will not work on e.g. CentOS 4. This should be fixed in
+Zaptel::Hardware::PCI.pm
diff --git a/xpp/utils/zconf/Zaptel/Chans.pm b/xpp/utils/zconf/Zaptel/Chans.pm
index eef922f..f50d212 100644
--- a/xpp/utils/zconf/Zaptel/Chans.pm
+++ b/xpp/utils/zconf/Zaptel/Chans.pm
@@ -39,6 +39,21 @@ sub new($$$$$$) {
my $type;
if($fqn =~ m|\bXPP_(\w+)/.*$|) {
$type = $1; # One of our AB
+ } elsif ($fqn =~ m{\b(TE[24]|WCT1|Tor2|TorISA|WP[TE]1|cwain[12])/.*}) {
+ # TE[24]: Digium wct4xxp
+ # WCT1: Digium single span card drivers?
+ # Tor2: Tor PCI cards
+ # TorISA: ISA ones (still used?)
+ # 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*)/.*}) {
+ # 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) {
$type = 'FXS' if $signalling =~ /^FXS/;
$type = 'FXO' if $signalling =~ /^FXO/;
diff --git a/xpp/utils/zconf/Zaptel/Config/Defaults.pm b/xpp/utils/zconf/Zaptel/Config/Defaults.pm
new file mode 100644
index 0000000..90b49ab
--- /dev/null
+++ b/xpp/utils/zconf/Zaptel/Config/Defaults.pm
@@ -0,0 +1,29 @@
+package Zaptel::Config::Defaults;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+
+# Use the shell to source a file and expand a given list
+# of variables.
+sub do_source($@) {
+ my $file = shift;
+ my @vars = @_;
+ my @output = `env -i sh -ec '. $file; export @vars; env'`;
+ die "$0: Sourcing '$file' exited with $?" if $?;
+ my %vars;
+
+ foreach my $line (@output) {
+ chomp $line;
+ my ($k, $v) = split(/=/, $line, 2);
+ $vars{$k} = $v if grep /^$k$/, @vars;
+ }
+ return %vars;
+}
+
+1;
diff --git a/xpp/utils/zconf/Zaptel/Hardware.pm b/xpp/utils/zconf/Zaptel/Hardware.pm
index 321292a..39305fb 100644
--- a/xpp/utils/zconf/Zaptel/Hardware.pm
+++ b/xpp/utils/zconf/Zaptel/Hardware.pm
@@ -34,7 +34,11 @@ sub devices($) {
return @zaptel_devices;
}
-Zaptel::Hardware::USB->scan_devices;
-Zaptel::Hardware::PCI->scan_devices;
+sub scan_hardware($) {
+ my $pack = shift || die;
+
+ Zaptel::Hardware::USB->scan_devices;
+ Zaptel::Hardware::PCI->scan_devices;
+}
1;
diff --git a/xpp/utils/zconf/Zaptel/Hardware/PCI.pm b/xpp/utils/zconf/Zaptel/Hardware/PCI.pm
index c6731dc..48fa810 100644
--- a/xpp/utils/zconf/Zaptel/Hardware/PCI.pm
+++ b/xpp/utils/zconf/Zaptel/Hardware/PCI.pm
@@ -11,6 +11,7 @@ use strict;
use Zaptel::Hardware;
my @idlist = qw(
+ 0B0B:0206
1397:16B8
1397:08B4
1057:5608
diff --git a/xpp/utils/zconf/Zaptel/Span.pm b/xpp/utils/zconf/Zaptel/Span.pm
index 8496910..47a5a56 100644
--- a/xpp/utils/zconf/Zaptel/Span.pm
+++ b/xpp/utils/zconf/Zaptel/Span.pm
@@ -46,28 +46,51 @@ my @bri_strings = (
'HFC-S PCI A ISDN.* \[(NT|TE)\] '
);
+my @pri_strings = (
+ 'PRI_(NT|TE)'
+ );
+
our $ZAPBRI_NET = 'bri_net';
our $ZAPBRI_CPE = 'bri_cpe';
+our $ZAPPRI_NET = 'pri_net';
+our $ZAPPRI_CPE = 'pri_cpe';
+
sub new($$) {
my $pack = shift or die "Wasn't called as a class method\n";
my $num = shift or die "Missing a span number parameter\n";
my $self = { NUM => $num };
bless $self, $pack;
+ $self->{TYPE} = "UNKNOWN";
open(F, "$proc_base/$num") or die "Failed to open '$proc_base/$num\n";
my $head = <F>;
chomp $head;
foreach my $cardtype (@bri_strings) {
if($head =~ m/$cardtype/) {
+ $self->{IS_DIGITAL} = 1;
$self->{IS_BRI} = 1;
$self->{TERMTYPE} = $1;
+ $self->{TYPE} = "BRI_$1";
$self->{DCHAN_IDX} = 2;
$self->{BCHAN_LIST} = [ 0, 1 ];
last;
}
}
+ foreach my $cardtype (@pri_strings) {
+ if($head =~ m/$cardtype/) {
+ $self->{IS_DIGITAL} = 1;
+ $self->{IS_PRI} = 1;
+ $self->{TERMTYPE} = $1;
+ $self->{TYPE} = "PRI_$1";
+ {
+ $self->{DCHAN_IDX} = 15; # Depends on E1/T1/J1
+ $self->{BCHAN_LIST} = [ 0 .. 14, 16 .. 30 ];
+ }
+ last;
+ }
+ }
die "$0: Unkown TERMTYPE [NT/TE]\n"
- if $self->is_bri and !defined $self->{TERMTYPE};
+ 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;
@@ -99,6 +122,15 @@ sub new($$) {
$self->{SIGNALLING} = 'gsm';
}
}
+ if($self->is_pri()) {
+ $self->{DCHAN} = ($self->chans())[$self->{DCHAN_IDX}];
+ $self->{BCHANS} = [ ($self->chans())[@{$self->{BCHAN_LIST}}] ];
+ $self->{CODING} = 'hdb3';
+ $self->{YELLOW} = undef;
+ $self->{FRAMING} = 'ccs';
+ $self->{SIGNALLING} = ($self->{TERMTYPE} eq 'NT') ? $ZAPPRI_NET : $ZAPPRI_CPE ;
+ $self->{SWITCHTYPE} = 'euroisdn';
+ }
return $self;
}
diff --git a/xpp/utils/zt_registration b/xpp/utils/zt_registration
index d6d0278..9a8323f 100755
--- a/xpp/utils/zt_registration
+++ b/xpp/utils/zt_registration
@@ -8,7 +8,8 @@
# $Id$
#
use strict;
-BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); }
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
use Zaptel;
use Zaptel::Span;
@@ -73,7 +74,7 @@ zt_registration [on|off]
=head1 DESCRIPTION
-Without parameters, show all connected XPD's sorted by physical connector order.
+Without parameters, show all connected XPDs sorted by physical connector order.
Each one is show to be unregistered (off), or registered to a specific zaptel span
(the span number is shown).
@@ -84,3 +85,39 @@ All registerations/deregisterations are sorted by physical connector string.
off -- deregisters all XPD's from zaptel.
on -- registers all XPD's to zaptel.
+
+=head2 Sample Output
+
+ $ zt_registration
+ XBUS-02 usb-0000:00:1d.7-3
+ XBUS-02/XPD-00: on Span 9
+ XBUS-02/XPD-10: on Span 10
+ XBUS-02/XPD-20: on Span 11
+ XBUS-02/XPD-30: on Span 12
+ XBUS-01 usb-0000:00:1d.7-4
+ XBUS-01/XPD-00: on Span 13
+ XBUS-01/XPD-10: on Span 14
+ XBUS-01/XPD-20: on Span 15
+ XBUS-01/XPD-30: on Span 16
+ XBUS-00 usb-0000:00:1d.7-5
+ XBUS-00/XPD-00: on Span 17
+ XBUS-00/XPD-10: on Span 18
+ XBUS-00/XPD-20: on Span 19
+ XBUS-00/XPD-30: on Span 20
+
+=head1 FILES
+
+=over
+
+=item /proc/xpp/XBUS-nn/XPD-mm/zt_registration
+
+Reading from this file shows if if the if the specific XPD is
+registered. Writing to it 0 or 1 registers / unregisters the device.
+
+This should allow you to register / unregister a specific XPD rather
+than all of them.
+
+Unregistering an XPD will fail if the span is in use (has some channels
+that are in use by e.g. Asterisk).
+
+=back