#! /usr/bin/perl -w use strict; # Make warnings fatal local $SIG{__WARN__} = sub { die @_ }; # # Written by Oron Peled # 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() { 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() { 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 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