dahdi-linux/drivers/dahdi/xpp/init_card_2_30
Oron Peled 949aa4958f xpp: FXO: in-firmware polarity-reversal detection
PIC_TYPE_2 rev.11039 adds support for polarity reversal detection. Support
those messages.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
2013-03-28 21:06:34 +02:00

468 lines
12 KiB
Perl
Executable File

#! /usr/bin/perl -w
use strict;
# Make warnings fatal
local $SIG{__WARN__} = sub { die @_ };
#
# Written by Oron Peled <oron@actcom.co.il>
# Copyright (C) 2006, 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.
#
# See the file LICENSE in the top level of this tarball.
#
#
# $Id$
#
# Data format:
# - A comment start with ';' or '#' until the end of line
# - Blank lines are ignored
# - Fields are whitespace separated (spaces or tabs)
#
# The fields are (in command line order):
# 1. SLIC select in decimal (range 0-7).
# * is a special value which means ALL SLICS (only some registers
# accept settings for ALL SLICS).
# 2. Command word:
# - RD Read Direct register.
# - RS Read Sub-register.
# - WD Write Direct register.
# - WS Write Sub-register.
# 3. Register number in hexadecimal.
# 4. Low data byte in hexadecimal. (for WD and WS commands).
# 5. High data byte in hexadecimal. (for WS command only).
#
#
package main;
use File::Basename;
use Getopt::Std;
my $program = basename("$0");
my $init_dir = dirname("$0");
BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); }
use XppConfig $init_dir;
my $unit_id;
my %opts;
$Getopt::Std::STANDARD_HELP_VERSION = 1;
our $VERSION = '$Id$';
sub usage() {
print <<"EOF";
$0 [-L] [-v verify_file] [-o output_file]
-L: List all available opermodes and exit
-v: verify opermodes and exit
-o: simulate: output to file instead of astribank
EOF
exit 1;
}
sub HELP_MESSAGE() {
eval {usage};
return 0;
}
getopts('Lo:v:', \%opts) || usage;
my %settings;
$settings{debug} = 0;
my $chipregs;
sub logit {
print STDERR "$unit_id: @_\n";
}
sub debug {
logit @_ if $settings{debug};
}
# Arrange for error logging
if (-t STDERR || $opts{v}) {
$unit_id = 'Interactive';
debug "Interactive startup";
} else {
$unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
open (STDERR, "| logger -t $program -p kern.info") || die;
debug "Non Interactive startup";
foreach my $k (qw(
XBUS_NAME
XBUS_NUMBER
UNIT_NUMBER
UNIT_TYPE
UNIT_SUBUNITS
UNIT_SUBUNITS_DIR
XBUS_REVISION
XBUS_CONNECTOR
XBUS_LABEL)) {
unless(defined $ENV{$k}) {
logit "Missing ENV{$k}\n";
die;
}
}
$chipregs = sprintf "/sys/bus/xpds/devices/%02d:%1d:0/chipregs",
$ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER};
if(! -f $chipregs) {
my $xpd_name = sprintf("XPD-%1d0", $ENV{UNIT_NUMBER});
$chipregs = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs";
logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
if -f $chipregs;
}
}
sub set_output() {
my $output;
if($opts{o}) {
$output = $opts{o};
} else {
# No subunits in FXS (everything is subunit 0)
$output = $chipregs;
}
open(REG, ">$output") || die "Failed to open '$output': $!\n";
my $oldfh = select REG;
main::logit "# Setting output" if $opts{o};
return $oldfh;
}
package FXO;
sub gen {
my $fmt = shift;
$| = 1;
printf "$fmt\n", @_;
}
my $OPERMODE = 'FCC';
sub turn_off_leds() {
# Turning off red LEDs
# Warning: do not send WD 31 20 A0 !
foreach my $i (0..7) {
FXO::gen "$i WD 20 A0";
}
}
# This data is manually taken from utils/init_fxo_modes which is generated
# during build.
# Running this script with a single 'verify' argument, during build,
# compare this data to a (possibly updated) utils/init_fxo_modes file.
my $OPERMODE_DATA = "
FCC reg16=01 reg26=C0 reg30=00 reg31=20
TBR21 reg16=00 reg26=C2 reg30=02 reg31=20 ring_osc=7E6C ring_x=023A
ARGENTINA reg16=00 reg26=C0 reg30=00 reg31=20
AUSTRALIA reg16=40 reg26=30 reg30=03 reg31=20
AUSTRIA reg16=00 reg26=C2 reg30=03 reg31=28
BAHRAIN reg16=00 reg26=C2 reg30=02 reg31=20
BELGIUM reg16=00 reg26=C2 reg30=02 reg31=28
BRAZIL reg16=00 reg26=30 reg30=00 reg31=20
BULGARIA reg16=00 reg26=C2 reg30=03 reg31=20
CANADA reg16=00 reg26=C0 reg30=00 reg31=20
CHILE reg16=00 reg26=C0 reg30=00 reg31=20
CHINA reg16=00 reg26=30 reg30=0F reg31=20
COLOMBIA reg16=00 reg26=C0 reg30=00 reg31=20
CROATIA reg16=00 reg26=C2 reg30=02 reg31=20
CYPRUS reg16=00 reg26=C2 reg30=02 reg31=20
CZECH reg16=00 reg26=C2 reg30=02 reg31=20
DENMARK reg16=00 reg26=C2 reg30=02 reg31=28
ECUADOR reg16=00 reg26=C0 reg30=00 reg31=20
EGYPT reg16=00 reg26=30 reg30=00 reg31=20
ELSALVADOR reg16=00 reg26=C0 reg30=00 reg31=20
FINLAND reg16=00 reg26=C2 reg30=02 reg31=28
FRANCE reg16=00 reg26=C2 reg30=02 reg31=28
GERMANY reg16=00 reg26=C2 reg30=03 reg31=28
GREECE reg16=00 reg26=C2 reg30=02 reg31=28
GUAM reg16=00 reg26=C0 reg30=00 reg31=20
HONGKONG reg16=00 reg26=C0 reg30=00 reg31=20
HUNGARY reg16=00 reg26=C0 reg30=00 reg31=20
ICELAND reg16=00 reg26=C2 reg30=02 reg31=28
INDIA reg16=00 reg26=C0 reg30=04 reg31=20
INDONESIA reg16=00 reg26=C0 reg30=00 reg31=20
IRELAND reg16=00 reg26=C2 reg30=02 reg31=28
ISRAEL reg16=00 reg26=C2 reg30=02 reg31=20
ITALY reg16=00 reg26=C2 reg30=02 reg31=28
JAPAN reg16=00 reg26=30 reg30=00 reg31=20
JORDAN reg16=00 reg26=30 reg30=00 reg31=20
KAZAKHSTAN reg16=00 reg26=C0 reg30=00 reg31=20
KUWAIT reg16=00 reg26=C0 reg30=00 reg31=20
LATVIA reg16=00 reg26=C2 reg30=02 reg31=20
LEBANON reg16=00 reg26=C2 reg30=02 reg31=20
LUXEMBOURG reg16=00 reg26=C2 reg30=02 reg31=28
MACAO reg16=00 reg26=C0 reg30=00 reg31=20
MALAYSIA reg16=00 reg26=30 reg30=00 reg31=20
MALTA reg16=00 reg26=C2 reg30=02 reg31=20
MEXICO reg16=00 reg26=C0 reg30=00 reg31=20
MOROCCO reg16=00 reg26=C2 reg30=02 reg31=20
NETHERLANDS reg16=00 reg26=C2 reg30=02 reg31=28
NEWZEALAND reg16=00 reg26=C0 reg30=04 reg31=20
NIGERIA reg16=00 reg26=C2 reg30=02 reg31=20
NORWAY reg16=00 reg26=C2 reg30=02 reg31=28
OMAN reg16=00 reg26=30 reg30=00 reg31=20
PAKISTAN reg16=00 reg26=30 reg30=00 reg31=20
PERU reg16=00 reg26=C0 reg30=00 reg31=20
PHILIPPINES reg16=00 reg26=30 reg30=00 reg31=20
POLAND reg16=03 reg26=C0 reg30=00 reg31=20
PORTUGAL reg16=00 reg26=C2 reg30=02 reg31=28
ROMANIA reg16=00 reg26=C0 reg30=00 reg31=20
RUSSIA reg16=00 reg26=30 reg30=00 reg31=20
SAUDIARABIA reg16=00 reg26=C0 reg30=00 reg31=20
SINGAPORE reg16=00 reg26=C0 reg30=00 reg31=20
SLOVAKIA reg16=00 reg26=C0 reg30=03 reg31=20
SLOVENIA reg16=00 reg26=C0 reg30=02 reg31=20
SOUTHAFRICA reg16=42 reg26=C0 reg30=03 reg31=20
SOUTHKOREA reg16=00 reg26=C0 reg30=00 reg31=20
SPAIN reg16=00 reg26=C2 reg30=02 reg31=28
SWEDEN reg16=00 reg26=C2 reg30=02 reg31=28
SWITZERLAND reg16=00 reg26=C2 reg30=02 reg31=28
SYRIA reg16=00 reg26=30 reg30=00 reg31=20
TAIWAN reg16=00 reg26=30 reg30=00 reg31=20
THAILAND reg16=00 reg26=30 reg30=00 reg31=20
UAE reg16=00 reg26=C0 reg30=00 reg31=20
UK reg16=00 reg26=C2 reg30=05 reg31=28
USA reg16=00 reg26=C0 reg30=00 reg31=20
YEMEN reg16=00 reg26=C0 reg30=00 reg31=20
";
my %opermode_table;
sub opermode_setup() {
main::logit "Setting OPERMODE=$OPERMODE";
# Several countries (South Africa, UAE, anybody else)
# require a shorter delay:
if($OPERMODE eq 'SOUTHAFRICA' or $OPERMODE eq 'UAE') {
FXO::gen "* WD 17 2B";
}
# defaults, based on fxo_modes from wctdm.c .
# Decimal register numbers!
my %regs = (
16 => 0,
26 => 0,
30 => 0,
31 => 0x20,
);
my $mode = $opermode_table{$OPERMODE};
if(defined $mode) {
foreach my $k (keys %regs) {
my $fullkey = "reg$k";
$regs{$k} = $mode->{$fullkey};
}
}
foreach my $k (keys %regs) {
# Our values are HEXADECIMAL without a 0x prefix!!!
my $cmd = sprintf "* WD %02X %02X", $k, hex($regs{$k});
main::debug " regs: '$cmd'";
FXO::gen "$cmd";
}
main::debug "Finished Opermode";
}
sub parse_opermode_line($) {
my $line = shift or return();
chomp $line;
$line =~ s/#.*//;
my @params = split(/\s+/, $line);
my $location = shift @params;
my $entry = {};
foreach my $p (@params) {
my ($key, $val) = split(/=/, $p, 2);
$entry->{$key} = $val;
}
return ($location, $entry);
}
sub opermode_preprocess() {
undef %opermode_table;
foreach my $line (split(/\n/, $OPERMODE_DATA)) {
my ($location, $entry) = parse_opermode_line($line);
next unless defined $location;
#print "$location\t", ref($entry), "\n";
die "An entry for '$location' already exists\n"
if exists $opermode_table{$location};
$opermode_table{$location} = $entry;
}
}
sub opermode_to_string($) {
my $mode = shift or die;
my @params;
foreach my $k (sort keys %{$mode}) {
push(@params, "$k=$mode->{$k}");
}
return join(" ", @params);
}
sub opermode_list() {
my $l = join("\n", sort keys %opermode_table);
print "$l\n";
}
sub opermode_verify($) {
my $input = shift or die;
my %verification_table;
my %location_lines;
my $mismatches = 0;
open(F, $input) or die "$0: Failed opening '$input': $!\n";
while(<F>) {
chomp;
#print "$_\n";
s/#.*//;
my @params = split;
my $location = shift @params;
foreach my $p (@params) {
my ($key, $val) = split(/=/, $p, 2);
$verification_table{$location}{$key} = $val;
}
$location_lines{$location} = $.;
}
close F;
# First test: check for missing data in our program
foreach my $location (sort keys %verification_table) {
my $mode = $opermode_table{$location};
if(! defined $mode) {
printf STDERR "Missing from $0: '$location' at $input:$location_lines{$location}\n";
$mismatches++;
next;
}
my $verify_mode = $verification_table{$location};
my $str1 = opermode_to_string($mode);
my $str2 = opermode_to_string($verify_mode);
if($str1 ne $str2) {
print STDERR "DIFF: '$location' at $input:$location_lines{$location}\n";
printf STDERR "\t%-20s: %s\n", "program", $str1;
printf STDERR "\t%-20s: %s\n", "verify", $str2;
$mismatches++;
}
}
# Second test: check for extra data in our program
foreach my $location (sort keys %opermode_table) {
my $mode = $verification_table{$location};
if(! defined $mode) {
printf STDERR "Extra in $0 '$location'\n";
$mismatches++;
next;
}
}
print STDERR "Total $mismatches mismatches\n" if $mismatches;
return $mismatches;
}
sub read_defaults() {
if(XppConfig::read_config(\%settings)) {
main::logit "Defaults from $settings{xppconf}";
my $o = $settings{opermode};
if(defined($o)) {
# Verify
$o = uc($o); # Uppercase
my $mode = $opermode_table{$o};
if(! defined $mode) {
main::logit "Unknown opermode='$o'";
die;
}
$OPERMODE = $o;
main::logit "Set OPERMODE = $o";
}
} else {
main::logit "No defaults file, use hard-coded defaults.";
}
}
package main;
FXO::opermode_preprocess; # Must be first
if($opts{v}) {
my $verify_file = $opts{v};
usage unless $verify_file;
main::debug "$0: opermode verification (input='$verify_file')";
my $mismatches = FXO::opermode_verify($verify_file);
die "$0: Verification against $verify_file failed\n" if $mismatches != 0;
exit 0;
} elsif($opts{L}) {
FXO::opermode_list();
exit 0;
}
main::debug "Starting";
FXO::read_defaults;
die "OPERMODE is undefined" unless $OPERMODE;
set_output;
FXO::turn_off_leds;
while(<DATA>) {
chomp;
s/[#;].*$//; # remove comments
s/^\s+//; # trim whitespace
s/\s+$//; # trim whitespace
s/\t+/ /g; # replace tabs with spaces (for logs)
next unless /\S/; # Skip empty lines
main::debug "writing: '$_'";
FXO::gen "$_";
}
FXO::opermode_setup;
close REG;
main::debug "Ending '$0'";
close STDERR;
exit 0;
__DATA__
* WD 12 02 # Full wave rectified ring detection
* WD 03 01 # Polarity reversal detect mask
* WD 04 00 # Clear interrupt status
* WD 21 08 # Disable PCM transfers
* WD 18 99
* WD 06 00
# ----------- DAA PCM start offset ----------
* WD 23 00
* WD 25 00
0 WD 22 00
0 WD 24 00
0 WD 21 28 # Enable PCM transfers, when offsets are set
1 WD 22 08
1 WD 24 08
1 WD 21 28
2 WD 22 10
2 WD 24 10
2 WD 21 28
3 WD 22 18
3 WD 24 18
3 WD 21 28
4 WD 22 20
4 WD 24 20
4 WD 21 28
5 WD 22 28
5 WD 24 28
5 WD 21 28
6 WD 22 30
6 WD 24 30
6 WD 21 28
7 WD 22 38
7 WD 24 38
7 WD 21 28
# ----------- DAA ONHOOK --------------------
* WD 05 00
# Set tip to ring voltage to 3.5 volts while off-hook
# instead of default of 3.1
* WD 1A C0