diff options
Diffstat (limited to 'xpp')
-rwxr-xr-x | xpp/calibrate_slics | 314 | ||||
-rwxr-xr-x | xpp/initialize_registers | 54 | ||||
-rw-r--r-- | xpp/utils/Makefile | 16 | ||||
-rw-r--r-- | xpp/utils/print_modes.c | 44 | ||||
-rw-r--r-- | xpp/xbus-core.c | 88 |
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, |