summaryrefslogtreecommitdiff
path: root/kernel/xpp/utils/zconf/Zaptel/Xpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/xpp/utils/zconf/Zaptel/Xpp')
-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
3 files changed, 337 insertions, 123 deletions
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;