summaryrefslogtreecommitdiff
path: root/xpp
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-09-04 23:53:30 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-09-04 23:53:30 +0000
commitd1dca1a4fed07a51f4a2b013902eca069ae1734c (patch)
treedaeb458935244fae1a2293068a46140e694fafc0 /xpp
parentee5282ac097e112e9baf1c760211e6ee0f2a4fe8 (diff)
* Re-add calibrate_slics to the FXS initialization process
* xpp/utils: Build and install init_fxo_modes . Data is based on data from wctdm.c . TODO: a separate daa.h? * Fail the script if automatic calibration has failed. git-svn-id: http://svn.digium.com/svn/zaptel/trunk@1394 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp')
-rwxr-xr-xxpp/calibrate_slics314
-rwxr-xr-xxpp/initialize_registers54
-rw-r--r--xpp/utils/Makefile16
-rw-r--r--xpp/utils/print_modes.c44
-rw-r--r--xpp/xbus-core.c88
5 files changed, 505 insertions, 11 deletions
diff --git a/xpp/calibrate_slics b/xpp/calibrate_slics
new file mode 100755
index 0000000..f5b45f3
--- /dev/null
+++ b/xpp/calibrate_slics
@@ -0,0 +1,314 @@
+#!/usr/bin/perl -w
+
+#
+# $Id:$
+#
+
+use strict;
+use Time::HiRes qw (time alarm sleep);
+
+my $SlicsFile = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/$ENV{XPD_NAME}/slics";
+
+my @SlicNums = (0 .. 7);
+
+if ( ! -f $SlicsFile ) {
+ exit 1
+}
+
+sub logger($) {
+ print STDERR "LOG: @_\n";
+ system("logger @_");
+}
+
+sub write_to_slic_file($) {
+ my $write_str = shift;
+ #print STDERR "[Writing string]\n".$write_str."[End String]\n";
+
+ open(SLICS,">$SlicsFile") or
+ die("Failed writing to slics file $SlicsFile");
+ print SLICS $write_str;
+ close(SLICS);
+ sleep(0.001);
+
+}
+
+sub read_reg($$$) {
+ my $read_slic = shift;
+ my $read_reg = shift;
+ my $direct = shift;
+
+ write_to_slic_file(
+ sprintf("%02x 00 00 00 R%s %02X",
+ 1<<$read_slic, $direct, $read_reg));
+ sleep(0.001);
+ open(SLICS,$SlicsFile) or
+ die("Failed reading from slics file $SlicsFile");
+ my @reply = ();
+ while(<SLICS>){
+ #if (/^[^#]/) {
+ # print STDERR "answer line: $_";
+ #}
+ if (/^SLIC_REPLY:\s+[DI]\s+reg_num=0x[[:xdigit:]]+,\s+dataH=0x([[:xdigit:]]+)\s+dataL=0x([[:xdigit:]]+)/){
+ @reply = (hex($1), hex($2));
+ #print STDERR "got [@reply]\n";
+ last;
+ }
+ }
+ close(SLICS);
+ if ($direct eq 'I') {
+ return @reply;
+ } else {
+ return $reply[1];
+ }
+}
+
+# TODO: rearange arguments
+sub write_reg{#($$$$$) {
+ my $read_slic = shift;
+ my $read_reg = shift;
+ my $direct = shift;
+ my $reg_val_low = shift;
+ my $reg_val_hi = shift;
+
+ my $str = sprintf "%02x 00 00 00 W%s %02X %02X",
+ 1<<$read_slic, $direct, $read_reg, $reg_val_low;
+ if ($direct eq 'I') {
+ $str .= sprintf " %02X", $reg_val_hi;
+ }
+ #printf STDERR "Writing: $str\n";
+ write_to_slic_file($str);
+}
+
+# TODO: rearange arguments
+sub write_reg_all_slics{#($$$$) {
+ my $read_reg = shift;
+ my $direct = shift;
+ my $reg_val_low = shift;
+ my $reg_val_hi = shift;
+
+ my $str = sprintf "FF FF 00 00 W%s %02X %02X",
+ $direct, $read_reg, $reg_val_low;
+ if ($direct eq 'I') {
+ $str .= sprintf " %02X", $reg_val_hi;
+ }
+ printf STDERR "Writing: $str\n";
+ write_to_slic_file($str);
+}
+
+sub log_calib_params() {
+ for my $i (100 .. 107) {
+ my $line="Calib Reg $i: ";
+ for my $slic (@SlicNums) {
+ $line .= " ".read_reg($slic, $i, 'D');
+ }
+ logger($line);
+ }
+}
+
+sub init_indirect_registers() {
+ return write_to_slic_file("#
+FF FF 00 00 WI 00 C2 55
+FF FF 00 00 WI 01 E6 51
+FF FF 00 00 WI 02 85 4B
+FF FF 00 00 WI 03 37 49
+
+FF FF 00 00 WI 04 33 33
+FF FF 00 00 WI 05 02 02
+FF FF 00 00 WI 06 02 02
+FF FF 00 00 WI 07 98 01
+
+FF FF 00 00 WI 08 98 01
+FF FF 00 00 WI 09 11 06
+FF FF 00 00 WI 0A 02 02
+FF FF 00 00 WI 0B E5 00
+
+FF FF 00 00 WI 0C 1C 0A
+FF FF 00 00 WI 0D 30 7B
+FF FF 00 00 WI 0E 63 00
+FF FF 00 00 WI 0F 00 00
+
+FF FF 00 00 WI 10 70 78
+FF FF 00 00 WI 11 7D 00
+FF FF 00 00 WI 12 00 00
+FF FF 00 00 WI 13 00 00
+
+FF FF 00 00 WI 14 F0 7E
+FF FF 00 00 WI 15 60 01
+FF FF 00 00 WI 16 00 00
+FF FF 00 00 WI 17 00 20
+
+FF FF 00 00 WI 18 00 20
+FF FF 00 00 WI 19 00 00
+FF FF 00 00 WI 1A 00 20
+FF FF 00 00 WI 1B 00 40
+
+FF FF 00 00 WI 1C 00 10
+FF FF 00 00 WI 1D 00 36
+FF FF 00 00 WI 1E 00 10
+FF FF 00 00 WI 1F 00 02
+
+FF FF 00 00 WI 20 C0 07
+FF FF 00 00 WI 21 00 26
+FF FF 00 00 WI 22 F4 0F
+FF FF 00 00 WI 23 00 80
+
+#FF FF 00 00 WI 24 20 03
+#FF FF 00 00 WI 25 8C 08
+#FF FF 00 00 WI 26 00 01
+#FF FF 00 00 WI 27 10 00
+
+FF FF 00 00 WI 24 00 08
+FF FF 00 00 WI 25 00 08
+FF FF 00 00 WI 26 00 08
+FF FF 00 00 WI 27 00 08
+
+FF FF 00 00 WI 28 00 0C
+FF FF 00 00 WI 29 00 0C
+FF FF 00 00 WI 2B 00 01
+
+FF FF 00 00 WI 63 DA 00
+FF FF 00 00 WI 64 60 6B
+FF FF 00 00 WI 65 74 00
+FF FF 00 00 WI 66 C0 79
+
+FF FF 00 00 WI 67 20 11
+FF FF 00 00 WI 68 E0 3B
+#");
+}
+
+sub init_early_direct_regs() {
+ return write_to_slic_file("#
+FF FF 00 00 WD 08 00
+FF FF 00 00 WD 4A 34
+FF FF 00 00 WD 4B 10
+FF FF 00 00 WD 40 00
+#")
+}
+
+my @FilterParams = ();
+
+sub save_indirect_filter_params() {
+ for my $slic (@SlicNums) {
+ for my $reg (35 .. 39) {
+ $FilterParams[$slic][$reg] =
+ [read_reg($slic, $reg, 'I')];
+ write_reg($slic, $reg, 'I', 0, 0x80);
+ }
+ }
+
+}
+
+sub restore_indirect_filter_params() {
+ for my $slic (@SlicNums) {
+ for my $reg (35 .. 39) {
+ write_reg($slic, $reg, 'I',
+ @{$FilterParams[$slic][$reg]});
+ }
+ }
+}
+
+my $ManualCalibrationSleepTime = 0.04; # 40ms
+
+sub manual_calibrate_loop($$) {
+ my $write_reg = shift;
+ my $read_reg = shift;
+
+ # counters to count down to (at most) 0
+ my @slic_counters = ();
+ for my $i (0 .. $#SlicNums) {
+ $slic_counters[$i] = 0x1F;
+ }
+
+ # start calibration:
+ my $calibration_in_progress = 1;
+ write_reg_all_slics($write_reg, 'D', 0x1F);
+ sleep $ManualCalibrationSleepTime;
+
+ # wait until all slics have finished calibration, or for timeout
+ while ($calibration_in_progress) {
+ $calibration_in_progress = 0; # until proven otherwise
+ print STDERR "ManualCalib:: ";
+ for my $slic(@SlicNums) {
+ my $value = read_reg($slic, $read_reg, 'D');
+ print STDERR " [$slic_counters[$slic]:$value]";
+ if ($value != 0 && $slic_counters[$slic] >= 0) {
+ $calibration_in_progress = 1;
+ $slic_counters[$slic]--;
+ write_reg($slic,$write_reg,'D',$slic_counters[$slic]);
+ }
+ }
+ print STDERR "\n";
+ # TODO: unnecessary sleep in the last round:
+ sleep $ManualCalibrationSleepTime;
+ }
+}
+
+sub manual_calibrate() {
+ manual_calibrate_loop(98, 88);
+ manual_calibrate_loop(99, 89);
+}
+
+sub auto_calibrate($$) {
+ my $calib_96 = shift;
+ my $calib_97 = shift;
+
+ #log_calib_params();
+ # start calibration:
+ write_to_slic_file(
+ sprintf
+ "FF FF 00 00 WD 61 %02X\n".
+ "FF FF 00 00 WD 60 %02X\n".
+ "", $calib_97, $calib_96
+
+ );
+ # wait until all slics have finished calibration, or for timeout
+ my $end_time=time() + 2;
+ my $timeout=0;
+ CALIB_LOOP: for my $slic (@SlicNums) {
+ logger("checking slic $slic");
+ while(1) {
+ my $reply;
+ if (($reply=read_reg($slic, 96, 'D')) == 0) {
+ # move to next register
+ logger("slic $slic calibrated");
+ last;
+ }
+ print STDERR "reply: $reply\n";
+ my $time=time();
+ if ( $time > $end_time) {
+ $timeout=1;
+ logger("Exiting on timeout: $time is after timeout $end_time .");
+ exit 1;
+ #last CALIB_LOOP;
+ }
+ logger("auto_calibrate not done yet: slic #$slic\n");
+ sleep(0.1);
+ }
+ }
+ #log_calib_params();
+}
+
+###########################################################
+#
+# main
+#
+
+# TODO: for all slics check the following reads to check communication
+#read_reg($slic, 0x08, 'D'): 0x02
+#read_reg($slic, 0x0B, 'D'): 0x33
+#read_reg($slic, 0x40, 'D'): 0x00 (?)
+
+print STDERR "starting\n";
+
+init_indirect_registers();
+print STDERR "after init_indirect_registers\n";
+init_early_direct_regs();
+print STDERR "after init_early_direct_regs\n";
+auto_calibrate(0x47, 0x1E);
+print STDERR "after auto_calibrate\n";
+manual_calibrate();
+print STDERR "after manul_calibrate\n";
+auto_calibrate(0x40, 0x01);
+print STDERR "after auto_calibrate 2\n";
+
+
diff --git a/xpp/initialize_registers b/xpp/initialize_registers
index 35386ce..6c07e94 100755
--- a/xpp/initialize_registers
+++ b/xpp/initialize_registers
@@ -1,23 +1,59 @@
#! /bin/sh
-# XPD_BUS - bus name
-# XPD_NAME - xpd name
-# XPD_TYPE - xpd type number (from protocol reply):
+#
+# $Id$
+#
+# This script is run from the xpp kernel module upon detection
+# of a new XPD.
+#
+# Expects the following environment variables to be set:
+# XPD_BUS - bus name
+# XPD_NAME - xpd name
+# XPD_TYPE - xpd type number (from protocol reply):
# 3 - FXS
# 4 - FXO
-# XPD_REVISION - xpd revision number
+# XPD_REVISION - xpd revision number
set -e
LOGGER="logger -i -t `basename $0`"
-
+opermode='FCC'
INIT_DIR=`dirname $0`
-BASE=/proc/xpp
+XPP_BASE=/proc/xpp
+
+if [ -r /etc/default/zaptel ]
+then . /etc/default/zaptel
+fi
+
+export XPP_BASE
-SLICS="$BASE/$XPD_BUS/$XPD_NAME/slics"
+SLICS="$XPP_BASE/$XPD_BUS/$XPD_NAME/slics"
FILE="$INIT_DIR/init_data_${XPD_TYPE}_${XPD_REVISION}.cmd"
+set_daa_country_params() {
+ # based on fxo_modes from wctdm.c . TODO: more decent calculation?
+ reg16=00; reg26=00; reg30=00; reg31=A3; ring_osc=; ring_x=;
+ mode="$1"
+ # TODO: a saner fall-back in case of an unknown mode
+ if [ "$mode" = '' ]; then mode='FCC'; fi
+ if [ -r $INIT_DIR/init_fxo_modes ]; then
+ . $INIT_DIR/init_fxo_modes
+ fi
+ cat <<EOF >$SLICS
+FF FF 00 00 WD 10 $reg16
+FF FF 00 00 WD 1A $reg26
+FF FF 00 00 WD 1E $reg30
+FF FF 00 00 WD 1F $reg31
+EOF
+ # for the FXS:
+ #if [ "$ring_osc" != '' ]; then
+ # /bin/echo "31 WI __ $ring_osc" >$SLICS
+ #fi
+ #if [ "$ring_x" != '' ]; then
+ # /bin/echo "31 WI __ $ring_x" >$SLICS
+ #fi
+}
if [ ! -f "$SLICS" ]; then
- $LOGGER "missing slics file '$SLICS'"
+ $LOGGER "missing register file '$SLICS'"
exit 1
fi
@@ -28,7 +64,9 @@ fi
case "$XPD_TYPE" in
3|4)
+ if [ "$XPD_TYPE" = 3 ]; then "$INIT_DIR/calibrate_slics"; fi
cat "$FILE" > "$SLICS"
+ if [ "$XPD_TYPE" = 4 ]; then set_daa_country_params "$opermode"; fi
;;
*)
$LOGGER "Unknown type '$XPD_TYPE'"
diff --git a/xpp/utils/Makefile b/xpp/utils/Makefile
index d840333..7dc4fa2 100644
--- a/xpp/utils/Makefile
+++ b/xpp/utils/Makefile
@@ -10,11 +10,13 @@ DATADIR = /usr/share/zaptel
MANDIR = /usr/share/man/man8
HOTPLUG_USB_DIR = /etc/hotplug/usb
-DATA_FILES = $(wildcard ../init_data_*.cmd *.hex)
+DATA_FILES = $(wildcard ../init_data_*.cmd *.hex) init_fxo_modes
+
+WCTDM=../../wctdm.c
CFLAGS = -g -Wall $(EXTRA_CFLAGS)
-TARGETS = libhexfile.a fpga_load test_parse
+TARGETS = libhexfile.a fpga_load test_parse init_fxo_modes
all: $(TARGETS)
@@ -23,7 +25,7 @@ install: all
$(INSTALL) genzaptelconf fpga_load $(DESTDIR)$(BINDIR)/
$(INSTALL) -d $(DESTDIR)$(DATADIR)
$(INSTALL_DATA) $(DATA_FILES) $(DESTDIR)$(DATADIR)/
- $(INSTALL) ../initialize_registers $(DESTDIR)$(DATADIR)/
+ $(INSTALL) ../initialize_registers ../calibrate_slics $(DESTDIR)$(DATADIR)/
$(INSTALL) -d $(DESTDIR)$(MANDIR)
$(INSTALL_DATA) fpga_load.8 genzaptelconf.8 $(DESTDIR)$(MANDIR)/
$(INSTALL) -d $(DESTDIR)$(HOTPLUG_USB_DIR)
@@ -46,5 +48,13 @@ test_parse.o: test_parse.c hexfile.h
test_parse: test_parse.o libhexfile.a
$(CC) -L. -o $@ $@.o $(EXTRA_LIBS) -lhexfile -lusb
+print_modes.o: wctdm_fxomodes.h
+
+wctdm_fxomodes.h: $(WCTDM)
+ perl -n -e 'print if (/^static struct fxo_mode {$$/ .. /};$$/)' $(WCTDM) >$@
+
+init_fxo_modes: print_modes
+ ./$^ >$@
+
clean:
$(RM) *.o $(TARGETS)
diff --git a/xpp/utils/print_modes.c b/xpp/utils/print_modes.c
new file mode 100644
index 0000000..473bafb
--- /dev/null
+++ b/xpp/utils/print_modes.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+
+#include "wctdm_fxomodes.h"
+
+int main() {
+ size_t i;
+
+ printf("case \"$mode\" in\n");
+ for (i=0; i<(sizeof(fxo_modes)/sizeof(struct fxo_mode)); i++) {
+ if (fxo_modes[i].name == NULL) break;
+ int reg16=0, reg26=0, reg30=0, reg31=0x3a;
+ char ring_osc[BUFSIZ]="", ring_x[BUFSIZ] = "";
+
+ reg16 |= (fxo_modes[i].ohs << 6);
+ reg16 |= (fxo_modes[i].rz << 1);
+ reg16 |= (fxo_modes[i].rt);
+
+ reg26 |= (fxo_modes[i].dcv << 6);
+ reg26 |= (fxo_modes[i].mini << 4);
+ reg26 |= (fxo_modes[i].ilim << 1);
+
+ reg30 = (fxo_modes[i].acim);
+
+ reg31 |= (fxo_modes[i].ohs2 << 3);
+
+ if (fxo_modes[i].ring_osc !=0 ) {
+ snprintf(ring_osc, BUFSIZ, "; ring_osc=\"%02X %02X\"",
+ (fxo_modes[i].ring_osc)>>8,
+ (fxo_modes[i].ring_osc)&&0xFF
+ );
+ }
+ if (fxo_modes[i].ring_x !=0 ) {
+ snprintf(ring_x, BUFSIZ, "; ring_x=\"%02X %02X\"",
+ (fxo_modes[i].ring_x)>>8,
+ (fxo_modes[i].ring_x)&&0xFF
+ );
+ }
+
+ printf("%s)\treg16=%02X; reg26=%02X; reg30=%02X; reg31=%02X%s%s;;\n",
+ fxo_modes[i].name, reg16, reg26, reg30, reg31, ring_osc, ring_x);
+ }
+ printf("esac\n");
+ return 0;
+}
diff --git a/xpp/xbus-core.c b/xpp/xbus-core.c
index 5e96147..f7b0a70 100644
--- a/xpp/xbus-core.c
+++ b/xpp/xbus-core.c
@@ -29,6 +29,9 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
+#ifdef PROTOCOL_DEBUG
+#include <linux/ctype.h>
+#endif
#include <linux/device.h>
#include <linux/delay.h> /* for mdelay() to debug */
#include "xpd.h"
@@ -44,6 +47,11 @@ static const char rcsid[] = "$Id$";
#define PROC_XBUS_SUMMARY "summary"
#define PROC_XBUS_WAITFOR_XPDS "waitfor_xpds"
+#ifdef PROTOCOL_DEBUG
+#define PROC_XBUS_COMMAND "command"
+static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+#endif
+
/* Command line parameters */
extern int print_dbg;
extern int max_queue_len;
@@ -504,6 +512,13 @@ static void xbus_free(xbus_t *xbus)
remove_proc_entry(PROC_XBUS_WAITFOR_XPDS, xbus->proc_xbus_dir);
xbus->proc_xbus_waitfor_xpds = NULL;
}
+#ifdef PROTOCOL_DEBUG
+ if(xbus->proc_xbus_command) {
+ DBG("Removing proc '%s' for %s\n", PROC_XBUS_COMMAND, xbus->busname);
+ remove_proc_entry(PROC_XBUS_COMMAND, xbus->proc_xbus_dir);
+ xbus->proc_xbus_command = NULL;
+ }
+#endif
DBG("Removing proc directory %s\n", xbus->busname);
remove_proc_entry(xbus->busname, xpp_proc_toplevel);
xbus->proc_xbus_dir = NULL;
@@ -594,6 +609,17 @@ xbus_t *xbus_new(xbus_ops_t *ops)
goto nobus;
}
xbus->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
+#ifdef PROTOCOL_DEBUG
+ xbus->proc_xbus_command = create_proc_entry(PROC_XBUS_COMMAND, 0200, xbus->proc_xbus_dir);
+ if (!xbus->proc_xbus_command) {
+ ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_COMMAND, xbus->busname);
+ err = -EIO;
+ goto nobus;
+ }
+ xbus->proc_xbus_command->write_proc = proc_xbus_command_write;
+ xbus->proc_xbus_command->data = xbus;
+ xbus->proc_xbus_command->owner = THIS_MODULE;
+#endif
#endif
/* Sanity checks */
if(!ops->packet_send) {
@@ -733,6 +759,65 @@ out:
}
+#ifdef PROTOCOL_DEBUG
+static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ const int NUM_SIZE = 100;
+ char buf[NUM_SIZE];
+ xbus_t *xbus = data;
+ xpacket_t *pack;
+ char *p;
+ byte *pack_contents;
+ byte *q;
+
+ if(count >= NUM_SIZE) {
+ ERR("%s: line too long\n", __FUNCTION__);
+ return -EFBIG;
+ }
+ if(copy_from_user(buf, buffer, count))
+ return -EINVAL;
+ buf[count] = '\0';
+ pack = xbus->ops->packet_new(xbus, GFP_KERNEL);
+ if(!pack)
+ return -ENOMEM;
+ q = pack_contents = (byte *)&pack->content;
+ for(p = buf; *p;) {
+ int val;
+ char hexdigit[3];
+
+ while(*p && isspace(*p)) // skip whitespace
+ p++;
+ if(!(*p))
+ break;
+ if(!isxdigit(*p)) {
+ ERR("%s: %s: bad hex value ASCII='0x%X' at position %d\n",
+ __FUNCTION__, xbus->busname, *p, p - buf);
+ goto err;
+ }
+ hexdigit[0] = *p++;
+ hexdigit[1] = '\0';
+ hexdigit[2] = '\0';
+ if(isxdigit(*p))
+ hexdigit[1] = *p++;
+ if(sscanf(hexdigit, "%2X", &val) != 1) {
+ ERR("%s: %s: bad hex value '%s' at position %d\n",
+ __FUNCTION__, xbus->busname, hexdigit, p - buf);
+ goto err;
+ }
+ *q++ = val;
+ // DBG("%s: %s: '%s' val=%d\n", __FUNCTION__, xbus->busname, hexdigit, val);
+ }
+ pack->datalen = q - pack_contents -
+ sizeof(pack->content.opcode) - sizeof(pack->content.addr);
+ packet_send(xbus, pack);
+ return count;
+err:
+ xbus->ops->packet_free(xbus, pack);
+ return -EINVAL;
+}
+#endif
+
+
static int read_proc_xbuses(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
@@ -840,6 +925,9 @@ int __init xbus_core_init(void)
{
int ret;
+#ifdef PROTOCOL_DEBUG
+ INFO("FEATURE: %s with PROTOCOL_DEBUG\n", THIS_MODULE->name);
+#endif
packet_cache = kmem_cache_create("xpp_packets",
sizeof(xpacket_t),
0, 0,