summaryrefslogtreecommitdiff
path: root/kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm')
-rw-r--r--kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm244
1 files changed, 189 insertions, 55 deletions
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;