dahdi-tools-3.0.0/0000755000000000000000000000000013373276276012437 5ustar rootrootdahdi-tools-3.0.0/install-sh0000755000000000000000000002202113373276276014440 0ustar rootroot#!/bin/sh # install - install a program, script, or datafile scriptversion=2005-05-14.22 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" chmodcmd="$chmodprog 0755" chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: -c (ignored) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test -n "$1"; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit $?;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --version) echo "$0 $scriptversion"; exit $?;; *) # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. test -n "$dir_arg$dstarg" && break # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done break;; esac done if test -z "$1"; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src src= if test -d "$dst"; then mkdircmd=: chmodcmd= else mkdircmd=$mkdirprog fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dstarg: Is a directory" >&2 exit 1 fi dst=$dst/`basename "$src"` fi fi # This sed command emulates the dirname command. dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` # Make sure that the destination directory exists. # Skip lots of stat calls in the usual case. if test ! -d "$dstdir"; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` shift IFS=$oIFS pathcomp= while test $# -ne 0 ; do pathcomp=$pathcomp$1 shift if test ! -d "$pathcomp"; then $mkdirprog "$pathcomp" # mkdir can fail with a `File exist' error in case several # install-sh are creating the directory concurrently. This # is OK. test -d "$pathcomp" || exit fi pathcomp=$pathcomp/ done fi if test -n "$dir_arg"; then $doit $mkdircmd "$dst" \ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } else dstfile=`basename "$dst"` # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 trap '(exit $?); exit' 1 2 13 15 # Copy the file name to the temp name. $doit $cpprog "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ || { # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dstdir/$dstfile"; then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit 1 } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" } } fi || { (exit 1); exit 1; } done # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit 0 } # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: dahdi-tools-3.0.0/fxotune.c0000644000000000000000000011327513373276276014304 0ustar rootroot/* * fxotune.c -- A utility for tuning the various settings on the fxo * modules for the TDM400 cards. * * by Matthew Fredrickson * * (C) 2004-2008 Digium, Inc. */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dahdi_tools_version.h" #include "fxotune.h" #define TEST_DURATION 2000 #define BUFFER_LENGTH (2 * TEST_DURATION) #define SKIP_SAMPLES 800 #define SINE_SAMPLES 8000 static float sintable[SINE_SAMPLES]; static const float amplitude = 16384.0; static char *configfile = "/etc/fxotune.conf"; static int audio_dump_fd = -1; static int printbest = 0; #define MAX_RESULTS (5) struct result_catalog { int idx; float echo; float freqres; struct wctdm_echo_coefs settings; }; struct { struct result_catalog results[MAX_RESULTS]; int numactive; } topresults; static char *usage = "Usage: fxotune [-v[vv] (-s | -i | -d )\n" "\n" " -s : set previously calibrated echo settings\n" " -i : calibrate echo settings\n" " options : [] [-t ]\n" " [-b ][-e ]\n" " [-n ][-l ][-m ]\n" " -d : dump input and output waveforms to ./fxotune_dump.vals\n" " options : [-b ][-w ]\n" " [-n ][-l ][-m ]\n" " -v : more output (-vv, -vvv also)\n" " -p : print the 5 best candidates for acim and coefficients settings\n" " -x : Perform sin/cos functions using table lookup\n" " -o : Write the received raw 16-bit signed linear audio that is\n" " used in processing to the file specified by \n" " -c \n" "\n" " - type of calibration\n" " (default 2, old method 1)\n" " \n" " - defines a range of devices to test\n" " (default: 1-252)\n" " - string to dial to clear the line\n" " (default 5)\n" " - seconds to wait for line to clear (default 0)\n" " - seconds before line will no longer be clear\n" " (default 18)\n" " - the device to perform waveform dump on\n" " (default 1)\n" " - -1 for multitone waveform, or frequency of\n" " single tone (default -1)\n" " - Alternative file to set from / calibrate to.\n" " (Default: /etc/fxotune.conf)\n" ; #define OUT_OF_BOUNDS(x) ((x) < 0 || (x) > 255) struct silence_info{ char *dialstr; /** fd of device we are working with */ int device; /** seconds we should wait after dialing the dialstring before we know for sure we'll have silence */ int initial_delay; /** seconds after which a reset should occur */ int reset_after; /** time of last reset */ struct timeval last_reset; }; static short outbuf[TEST_DURATION]; static int debug = 0; static FILE *debugoutfile = NULL; static int use_table = 0; static int fxotune_read(int fd, void *buffer, int len) { int res; res = read(fd, buffer, len); if ((res > 0) && (audio_dump_fd != -1)) { res = write(audio_dump_fd, buffer, len); } return res; } /** * Makes sure that the line is clear. * Right now, we do this by relying on the user to specify how long after dialing the * dialstring we can rely on the line being silent (before the telco complains about * the user not hitting the next digit). * * A more robust way to do this would be to actually measure the sound levels on the line, * but that's a lot more complicated, and this should work. * * @return 0 if succesful (no errors), 1 if unsuccesful */ static int ensure_silence(struct silence_info *info) { struct timeval tv; long int elapsedms; int x = DAHDI_ONHOOK; struct dahdi_dialoperation dop; gettimeofday(&tv, NULL); if (info->last_reset.tv_sec == 0) { /* this is the first request, we will force it to run */ elapsedms = -1; } else { /* this is not the first request, we will compute elapsed time */ elapsedms = ((tv.tv_sec - info->last_reset.tv_sec) * 1000L + (tv.tv_usec - info->last_reset.tv_usec) / 1000L); } if (debug > 4) { fprintf(stdout, "Reset line request received - elapsed ms = %li / reset after = %ld\n", elapsedms, info->reset_after * 1000L); } if (elapsedms > 0 && elapsedms < info->reset_after * 1000L) return 0; if (debug > 1){ fprintf(stdout, "Resetting line\n"); } /* do a line reset */ /* prepare line for silence */ /* Do line hookstate reset */ if (ioctl(info->device, DAHDI_HOOK, &x)) { fprintf(stderr, "Unable to hang up fd %d\n", info->device); return -1; } sleep(2); x = DAHDI_OFFHOOK; if (ioctl(info->device, DAHDI_HOOK, &x)) { fprintf(stderr, "Cannot bring fd %d off hook\n", info->device); return -1; } sleep(2); /* Added to ensure that dial can actually takes place */ memset(&dop, 0, sizeof(dop)); dop.op = DAHDI_DIAL_OP_REPLACE; dop.dialstr[0] = 'T'; dahdi_copy_string(dop.dialstr + 1, info->dialstr, sizeof(dop.dialstr)); if (ioctl(info->device, DAHDI_DIAL, &dop)) { fprintf(stderr, "Unable to dial!\n"); return -1; } sleep(1); sleep(info->initial_delay); gettimeofday(&info->last_reset, NULL); return 0; } /** * Generates a tone of specified frequency. * * @param hz the frequency of the tone to be generated * @param idx the current sample * to begenerated. For a normal waveform you need to increment * this every time you execute the function. * * @return 16bit slinear sample for the specified index */ static short inline gentone(int hz, int idx) { return amplitude * sin((idx * 2.0 * M_PI * hz)/8000); } /* Using DTMF tones for now since they provide good mid band testing * while not being harmonics of each other */ static int freqs[] = {697, 770, 941, 1209, 1336, 1633}; static int freqcount = 6; /** * Generates a waveform of several frequencies. * * @param idx the current sample * to begenerated. For a normal waveform you need to increment * this every time you execute the function. * * @return 16bit slinear sample for the specified index */ static short inline genwaveform(int idx) { int i = 0; float response = (float)0; for (i = 0; i < freqcount; i++){ response += sin((idx * 2.0 * M_PI * freqs[i])/8000); } return amplitude * response / freqcount; } /** * Calculates the RMS of the waveform buffer of samples in 16bit slinear format. * prebuf the buffer of either shorts or floats * bufsize the number of elements in the prebuf buffer (not the number of bytes!) * short_format 1 if prebuf points to an array of shorts, 0 if it points to an array of floats * * Formula for RMS (http://en.wikipedia.org/wiki/Root_mean_square): * * Xrms = sqrt(1/N Sum(x1^2, x2^2, ..., xn^2)) * * Note: this isn't really a power calculation - but it gives a good measure of the level of the response * * @param prebuf the buffer containing the values to compute * @param bufsize the size of the buffer * @param short_format 1 if prebuf contains short values, 0 if it contains float values */ static float power_of(void *prebuf, int bufsize, int short_format) { float sum_of_squares = 0; int numsamples = 0; float finalanswer = 0; short *sbuf = (short*)prebuf; float *fbuf = (float*)prebuf; int i = 0; if (short_format) { /* idiot proof checks */ if (bufsize <= 0) return -1; numsamples = bufsize; /* Got rid of divide by 2 - the bufsize parameter should give the number of samples (that's what it does for the float computation, and it should do it here as well) */ for (i = 0; i < numsamples; i++) { sum_of_squares += ((float)sbuf[i] * (float)sbuf[i]); } } else { /* Version for float inputs */ for (i = 0; i < bufsize; i++) { sum_of_squares += (fbuf[i] * fbuf[i]); } } finalanswer = sum_of_squares/(float)bufsize; /* need to divide by the number of elements in the sample for RMS calc */ if (finalanswer < 0) { fprintf(stderr, "Error: Final answer negative number %f\n", finalanswer); return -3; } return sqrtf(finalanswer); } /* * In an effort to eliminate as much as possible the effect of outside noise, we use principles * from the Fourier Transform to attempt to calculate the return loss of our signal for each setting. * * To begin, we send our output signal out on the line. We then receive back the reflected * response. In the Fourier Transform, each evenly distributed frequency within the window * is correlated (multiplied against, then the resulting samples are added together) with * the real (cos) and imaginary (sin) portions of that frequency base to detect that frequency. * * Instead of doing a complete Fourier Transform, we solve the transform for only our signal * by multiplying the received signal by the real and imaginary portions of our reference * signal. This then gives us the real and imaginary values that we can use to calculate * the return loss of the sinusoids that we sent out on the line. This is done by finding * the magnitude (think polar form) of the vector resulting from the real and imaginary * portions calculated above. * * This essentially filters out any other noise which maybe present on the line which is outside * the frequencies used in our test multi-tone. */ void init_sinetable(void) { int i; if (debug) { fprintf(stdout, "Using sine tables with %d samples\n", SINE_SAMPLES); } for (i = 0; i < SINE_SAMPLES; i++) { sintable[i] = sin(((float)i * 2.0 * M_PI )/(float)(SINE_SAMPLES)); } } /* Sine and cosine table lookup to use periodicity of the calculations being done */ float sin_tbl(int arg, int num_per_period) { arg = arg % num_per_period; arg = (arg * SINE_SAMPLES)/num_per_period; return sintable[arg]; } float cos_tbl(int arg, int num_per_period) { arg = arg % num_per_period; arg = (arg * SINE_SAMPLES)/num_per_period; arg = (arg + SINE_SAMPLES/4) % SINE_SAMPLES; /* Pi/2 adjustment */ return sintable[arg]; } static float db_loss(float measured, float reference) { return 20 * (logf(measured/reference)/logf(10)); } static void one_point_dft(const short *inbuf, int len, int frequency, float *real, float *imaginary) { float myreal = 0, myimag = 0; int i; for (i = 0; i < len; i++) { if (use_table) { myreal += (float) inbuf[i] * cos_tbl(i*frequency, 8000); myimag += (float) inbuf[i] * sin_tbl(i*frequency, 8000); } else { myreal += (float) inbuf[i] * cos((i * 2.0 * M_PI * frequency)/8000); myimag += (float) inbuf[i] * sin((i * 2.0 * M_PI * frequency)/8000); } } myimag *= -1; *real = myreal / (float) len; *imaginary = myimag / (float) len; } static float calc_magnitude(short *inbuf, int insamps) { float real, imaginary, magnitude; float totalmagnitude = 0; int i; for (i = 0; i < freqcount; i++) { one_point_dft(inbuf, insamps, freqs[i], &real, &imaginary); magnitude = sqrtf((real * real) + (imaginary * imaginary)); totalmagnitude += magnitude; } return totalmagnitude; } /** * dumps input and output buffer contents for the echo test - used to see exactly what's going on */ static int maptone(int whichdahdi, int freq, char *dialstr, int delayuntilsilence) { int i = 0; int res = 0, x = 0; struct dahdi_bufferinfo bi; short inbuf[TEST_DURATION]; /* changed from BUFFER_LENGTH - this buffer is for short values, so it should be allocated using the length of the test */ FILE *outfile = NULL; int leadin = 50; int trailout = 100; struct silence_info sinfo; float power_result; float power_waveform; float echo; outfile = fopen("fxotune_dump.vals", "w"); if (!outfile) { fprintf(stdout, "Cannot create fxotune_dump.vals\n"); return -1; } x = 1; if (ioctl(whichdahdi, DAHDI_SETLINEAR, &x)) { fprintf(stderr, "Unable to set channel to signed linear mode.\n"); return -1; } memset(&bi, 0, sizeof(bi)); if (ioctl(whichdahdi, DAHDI_GET_BUFINFO, &bi)) { fprintf(stderr, "Unable to get buffer information!\n"); return -1; } bi.numbufs = 2; bi.bufsize = TEST_DURATION; /* KD - changed from BUFFER_LENGTH; */ bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE; bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE; if (ioctl(whichdahdi, DAHDI_SET_BUFINFO, &bi)) { fprintf(stderr, "Unable to set buffer information!\n"); return -1; } /* Fill the output buffers */ for (i = 0; i < leadin; i++) outbuf[i] = 0; for (; i < TEST_DURATION - trailout; i++){ outbuf[i] = freq > 0 ? gentone(freq, i) : genwaveform(i); /* if frequency is negative, use a multi-part waveform instead of a single frequency */ } for (; i < TEST_DURATION; i++) outbuf[i] = 0; /* Make sure the line is clear */ memset(&sinfo, 0, sizeof(sinfo)); sinfo.device = whichdahdi; sinfo.dialstr = dialstr; sinfo.initial_delay = delayuntilsilence; sinfo.reset_after = 4; /* doesn't matter - we are only running one test */ if (ensure_silence(&sinfo)){ fprintf(stderr, "Unable to get a clear outside line\n"); return -1; } /* Flush buffers */ x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE | DAHDI_FLUSH_EVENT; if (ioctl(whichdahdi, DAHDI_FLUSH, &x)) { fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno)); return -1; } /* send data out on line */ res = write(whichdahdi, outbuf, BUFFER_LENGTH); /* we are sending a TEST_DURATION length array of shorts (which are 2 bytes each) */ if (res != BUFFER_LENGTH) { fprintf(stderr, "Could not write all data to line\n"); return -1; } retry: /* read return response */ res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH); if (res != BUFFER_LENGTH) { int dummy; ioctl(whichdahdi, DAHDI_GETEVENT, &dummy); goto retry; } /* write content of output buffer to debug file */ power_result = power_of(inbuf, TEST_DURATION, 1); power_waveform = power_of(outbuf, TEST_DURATION, 1); echo = power_result/power_waveform; fprintf(outfile, "Buffers, freq=%d, outpower=%0.0f, echo=%0.4f\n", freq, power_result, echo); fprintf(outfile, "Sample, Input (received from the line), Output (sent to the line)\n"); for (i = 0; i < TEST_DURATION; i++){ fprintf(outfile, "%d, %d, %d\n", i, inbuf[i], outbuf[i] ); } fclose(outfile); fprintf(stdout, "echo ratio = %0.4f (%0.1f / %0.1f)\n", echo, power_result, power_waveform); return 0; } /** * Initialize the data store for storing off best calculated results */ static void init_topresults(void) { topresults.numactive = 0; } /** * If this is a best result candidate, store in the top results data store * This is dependent on being the lowest echo value * * @param tbleoffset - The offset into the echo_trys table used * @param setting - Pointer to the settings used to achieve the fgiven value * @param echo - The calculated echo return value (in dB) * @param echo - The calculated magnitude of the response */ static void set_topresults(int tbloffset, struct wctdm_echo_coefs *setting, float echo, float freqres) { int place; int idx; for ( place = 0; place < MAX_RESULTS && place < topresults.numactive; place++) { if (echo < topresults.results[place].echo) { break; } } if (place < MAX_RESULTS) { /* move results to the bottom */ for (idx = topresults.numactive-2; idx >= place; idx--) { topresults.results[idx+1] = topresults.results[idx]; } topresults.results[place].idx = tbloffset; topresults.results[place].settings = *setting; topresults.results[place].echo = echo; topresults.results[place].freqres = freqres; if (MAX_RESULTS > topresults.numactive) { topresults.numactive++; } } } /** * Prints the top results stored to stdout * * @param header - Text that goes in the header of the response */ static void print_topresults(char * header) { int item; fprintf(stdout, "Top %d results for %s\n", topresults.numactive, header); for (item = 0; item < topresults.numactive; item++) { fprintf(stdout, "Res #%d: index=%d, %3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n", item+1, topresults.results[item].idx, topresults.results[item].settings.acim, topresults.results[item].settings.coef1, topresults.results[item].settings.coef2, topresults.results[item].settings.coef3, topresults.results[item].settings.coef4, topresults.results[item].settings.coef5, topresults.results[item].settings.coef6, topresults.results[item].settings.coef7, topresults.results[item].settings.coef8, topresults.results[item].freqres, topresults.results[item].echo); } } /** * Perform calibration type 2 on the specified device * * Determine optimum echo coefficients for the specified device * * New tuning strategy. If we have a number that we can dial that will result in silence from the * switch, the tune will be *much* faster (we don't have to keep hanging up and dialing a digit, etc...) * The downside is that the user needs to actually find a 'no tone' phone number at their CO's switch - but for * really fixing echo problems, this is what it takes. * * Also, for the purposes of optimizing settings, if we pick a single frequency and test with that, * we can try a whole bunch of impedence/echo coefficients. This should give better results than trying * a bunch of frequencies, and we can always do a a frequency sweep to pick between the best 3 or 4 * impedence/coefficients configurations. * * Note: It may be possible to take this even further and do some pertubation analysis on the echo coefficients * themselves (maybe use the 72 entry sweep to find some settings that are close to working well, then * deviate the coefficients a bit to see if we can improve things). A better way to do this would be to * use the optimization strategy from silabs. For reference, here is an application note that describes * the echo coefficients (and acim values): * * http://www.silabs.com/Support%20Documents/TechnicalDocs/an84.pdf * * See Table 13 in this document for a breakdown of acim values by region. * * http://www.silabs.com/Support%20Documents/TechnicalDocs/si3050-18-19.pdf * */ static int acim_tune2(int whichdahdi, int freq, char *dialstr, int delayuntilsilence, int silencegoodfor, struct wctdm_echo_coefs *coefs_out) { int i = 0; int res = 0, x = 0; int lowesttry = -1; float lowesttryresult = 999999999999.0; float lowestecho = 999999999999.0; struct dahdi_bufferinfo bi; short inbuf[TEST_DURATION * 2]; struct silence_info sinfo; int echo_trys_size = 72; int trys = 0; float waveform_power; float freq_result; float echo; init_topresults(); if (debug && !debugoutfile) { if (!(debugoutfile = fopen("fxotune.vals", "w"))) { fprintf(stdout, "Cannot create fxotune.vals\n"); return -1; } } /* Set echo settings */ if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &echo_trys[0])) { fprintf(stderr, "Unable to set impedance on fd %d\n", whichdahdi); return -1; } x = 1; if (ioctl(whichdahdi, DAHDI_SETLINEAR, &x)) { fprintf(stderr, "Unable to set channel to signed linear mode.\n"); return -1; } memset(&bi, 0, sizeof(bi)); if (ioctl(whichdahdi, DAHDI_GET_BUFINFO, &bi)) { fprintf(stderr, "Unable to get buffer information!\n"); return -1; } bi.numbufs = 2; bi.bufsize = BUFFER_LENGTH; bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE; bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE; if (ioctl(whichdahdi, DAHDI_SET_BUFINFO, &bi)) { fprintf(stderr, "Unable to set buffer information!\n"); return -1; } x = DAHDI_OFFHOOK; if (ioctl(whichdahdi, DAHDI_HOOK, &x)) { fprintf(stderr, "Cannot bring fd %d off hook", whichdahdi); return -1; } /* Set up silence settings */ memset(&sinfo, 0, sizeof(sinfo)); sinfo.device = whichdahdi; sinfo.dialstr = dialstr; sinfo.initial_delay = delayuntilsilence; sinfo.reset_after = silencegoodfor; /* Fill the output buffers */ for (i = 0; i < TEST_DURATION; i++) outbuf[i] = freq > 0 ? gentone(freq, i) : genwaveform(i); /* if freq is negative, use a multi-frequency waveform */ /* compute power of input (so we can later compute echo levels relative to input) */ waveform_power = calc_magnitude(outbuf, TEST_DURATION); /* sweep through the various coefficient settings and see how our responses look */ for (trys = 0; trys < echo_trys_size; trys++){ /* ensure silence on the line */ if (ensure_silence(&sinfo)){ fprintf(stderr, "Unable to get a clear outside line\n"); return -1; } if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &echo_trys[trys])) { fprintf(stderr, "Unable to set echo coefficients on fd %d\n", whichdahdi); return -1; } /* Flush buffers */ x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE | DAHDI_FLUSH_EVENT; if (ioctl(whichdahdi, DAHDI_FLUSH, &x)) { fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno)); return -1; } /* send data out on line */ res = write(whichdahdi, outbuf, BUFFER_LENGTH); if (res != BUFFER_LENGTH) { fprintf(stderr, "Could not write all data to line\n"); return -1; } retry: /* read return response */ res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH * 2); if (res != BUFFER_LENGTH * 2) { int dummy; ioctl(whichdahdi, DAHDI_GETEVENT, &dummy); goto retry; } freq_result = calc_magnitude(inbuf, TEST_DURATION * 2); echo = db_loss(freq_result, waveform_power); #if 0 if (debug > 0) fprintf(stdout, "%3d,%d,%d,%d,%d,%d,%d,%d,%d: magnitude = %0.0f, echo = %0.4f dB\n", echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2, echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5, echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8, freq_result, echo); #endif if (freq_result < lowesttryresult){ lowesttry = trys; lowesttryresult = freq_result; lowestecho = echo; } if (debug) { char result[256]; snprintf(result, sizeof(result), "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%f,%f", echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2, echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5, echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8, freq_result, echo ); fprintf(debugoutfile, "%s\n", result); fprintf(stdout, "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n", echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2, echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5, echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8, freq_result, echo); } if (printbest) { set_topresults(trys, &echo_trys[trys], echo, freq_result); } } if (debug > 0) fprintf(stdout, "Config with lowest response = %d, magnitude = %0.0f, echo = %0.4f dB\n", lowesttry, lowesttryresult, lowestecho); memcpy(coefs_out, &echo_trys[lowesttry], sizeof(struct wctdm_echo_coefs)); if (printbest) { print_topresults("Acim2_tune Test"); } return 0; } /** * Perform calibration type 1 on the specified device. Only tunes the line impedance. Look for best response range */ static int acim_tune(int whichdahdi, char *dialstr, int delayuntilsilence, int silencegoodfor, struct wctdm_echo_coefs *coefs_out) { int i = 0, freq = 0, acim = 0; int res = 0, x = 0; struct dahdi_bufferinfo bi; struct wctdm_echo_coefs coefs; short inbuf[TEST_DURATION]; /* changed from BUFFER_LENGTH - this buffer is for short values, so it should be allocated using the length of the test */ int lowest = 0; FILE *outfile = NULL; float acim_results[16]; struct silence_info sinfo; if (debug) { outfile = fopen("fxotune.vals", "w"); if (!outfile) { fprintf(stdout, "Cannot create fxotune.vals\n"); return -1; } } /* Set up silence settings */ memset(&sinfo, 0, sizeof(sinfo)); sinfo.device = whichdahdi; sinfo.dialstr = dialstr; sinfo.initial_delay = delayuntilsilence; sinfo.reset_after = silencegoodfor; /* Set echo settings */ memset(&coefs, 0, sizeof(coefs)); if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &coefs)) { fprintf(stdout, "Skipping non-TDM / non-FXO\n"); return -1; } x = 1; if (ioctl(whichdahdi, DAHDI_SETLINEAR, &x)) { fprintf(stderr, "Unable to set channel to signed linear mode.\n"); return -1; } memset(&bi, 0, sizeof(bi)); if (ioctl(whichdahdi, DAHDI_GET_BUFINFO, &bi)) { fprintf(stderr, "Unable to get buffer information!\n"); return -1; } bi.numbufs = 2; bi.bufsize = BUFFER_LENGTH; bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE; bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE; if (ioctl(whichdahdi, DAHDI_SET_BUFINFO, &bi)) { fprintf(stderr, "Unable to set buffer information!\n"); return -1; } for (acim = 0; acim < 16; acim++) { float freq_results[15]; coefs.acim = acim; if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &coefs)) { fprintf(stderr, "Unable to set impedance on fd %d\n", whichdahdi); return -1; } for (freq = 200; freq <=3000; freq+=200) { /* Fill the output buffers */ for (i = 0; i < TEST_DURATION; i++) outbuf[i] = gentone(freq, i); /* Make sure line is ready for next test iteration */ if (ensure_silence(&sinfo)){ fprintf(stderr, "Unable to get a clear line\n"); return -1; } /* Flush buffers */ x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE | DAHDI_FLUSH_EVENT; if (ioctl(whichdahdi, DAHDI_FLUSH, &x)) { fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno)); return -1; } /* send data out on line */ res = write(whichdahdi, outbuf, BUFFER_LENGTH); if (res != BUFFER_LENGTH) { fprintf(stderr, "Could not write all data to line\n"); return -1; } /* read return response */ retry: /* read return response */ res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH); if (res != BUFFER_LENGTH) { int dummy; ioctl(whichdahdi, DAHDI_GETEVENT, &dummy); goto retry; } /* calculate power of response */ freq_results[(freq/200)-1] = power_of(inbuf+SKIP_SAMPLES, TEST_DURATION-SKIP_SAMPLES, 1); /* changed from inbuf+SKIP_BYTES, BUFFER_LENGTH-SKIP_BYTES, 1 */ if (debug) fprintf(outfile, "%d,%d,%f\n", acim, freq, freq_results[(freq/200)-1]); } acim_results[acim] = power_of(freq_results, 15, 0); } if (debug) { for (i = 0; i < 16; i++) fprintf(outfile, "acim_results[%d] = %f\n", i, acim_results[i]); } /* Find out what the "best" impedance is for the line */ lowest = 0; for (i = 0; i < 16; i++) { if (acim_results[i] < acim_results[lowest]) { lowest = i; } } coefs_out->acim = lowest; coefs_out->coef1 = 0; coefs_out->coef2 = 0; coefs_out->coef3 = 0; coefs_out->coef4 = 0; coefs_out->coef5 = 0; coefs_out->coef6 = 0; coefs_out->coef7 = 0; coefs_out->coef8 = 0; return 0; } static int channel_is_fxo(int channo) { int res = 0; int fd; const char *CTL_DEV = "/dev/dahdi/ctl"; struct dahdi_params params; fd = open(CTL_DEV, O_RDWR, 0600); if (-1 == fd) { fprintf(stderr, "Failed to open %s: %s\n", CTL_DEV, strerror(errno)); return -1; } params.channo = channo; if (ioctl(fd, DAHDI_GET_PARAMS, ¶ms)) { fprintf(stderr, "%d is not a valid channel number.\n", channo); res = -1; } else if (0 == (__DAHDI_SIG_FXS & params.sigcap)) { fprintf(stderr, "Channel %d is not an FXO port.\n", channo); res = -1; } else if (0 == params.sigtype) { fprintf(stderr, "Cannot run on unconfigured channel %d. Please run dahdi_cfg to configure channels before running fxotune.\n", channo); res = -1; } close(fd); return res; } static int channel_open(int channo) { int fd; const char *DEVICE = "/dev/dahdi/channel"; if (channo > 0) { if (channel_is_fxo(channo)) return -1; fd = open(DEVICE, O_RDWR, 0600); if (fd < 0) { perror(DEVICE); return -1; } if (ioctl(fd, DAHDI_SPECIFY, &channo) < 0) { perror("DADHI_SPECIFY ioctl failed"); close(fd); fd = -1; } } else { fprintf(stderr, "Specified channel is not a valid channel number"); fd = -1; } return fd; } /** * Reads echo register settings from the configuration file and pushes them into * the appropriate devices * * @param configfilename the path of the file that the calibration results should be written to * * @return 0 if successful, !0 otherwise */ static int do_set(char *configfilename, int dev_range, int startdev, int stopdev) { FILE *fp = NULL; int res = 0; int fd = 0; fp = fopen(configfile, "r"); if (!fp) { fprintf(stdout, "Cannot open %s!\n",configfile); return -1; } while (res != EOF) { struct wctdm_echo_coefs mycoefs; char completedahdipath[56] = ""; int mydahdi,myacim,mycoef1,mycoef2,mycoef3,mycoef4,mycoef5,mycoef6,mycoef7,mycoef8; res = fscanf(fp, "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d",&mydahdi,&myacim,&mycoef1, &mycoef2,&mycoef3,&mycoef4,&mycoef5,&mycoef6,&mycoef7, &mycoef8); if (res == EOF) { break; } if (dev_range && (mydahdi < startdev || mydahdi > stopdev)) continue; /* Check to be sure conversion is done correctly */ if (OUT_OF_BOUNDS(myacim) || OUT_OF_BOUNDS(mycoef1)|| OUT_OF_BOUNDS(mycoef2)|| OUT_OF_BOUNDS(mycoef3)|| OUT_OF_BOUNDS(mycoef4)|| OUT_OF_BOUNDS(mycoef5)|| OUT_OF_BOUNDS(mycoef6)|| OUT_OF_BOUNDS(mycoef7)|| OUT_OF_BOUNDS(mycoef8)) { fprintf(stdout, "Bounds check error on inputs from %s:%d\n", configfile, mydahdi); return -1; } mycoefs.acim = myacim; mycoefs.coef1 = mycoef1; mycoefs.coef2 = mycoef2; mycoefs.coef3 = mycoef3; mycoefs.coef4 = mycoef4; mycoefs.coef5 = mycoef5; mycoefs.coef6 = mycoef6; mycoefs.coef7 = mycoef7; mycoefs.coef8 = mycoef8; if (debug >= 2) printf("fxotune: set channel %d\n", mydahdi); fd = channel_open(mydahdi); if (fd < 0) { return -1; } if (ioctl(fd, WCTDM_SET_ECHOTUNE, &mycoefs)) { fprintf(stdout, "%s: %s\n", completedahdipath, strerror(errno)); return -1; } close(fd); } fclose(fp); if (debug) fprintf(stdout, "fxotune: successfully set echo coeffecients on FXO modules\n"); return 0; } /** * Output waveform information from a single test * * Clears the line, then sends a single waveform (multi-tone, or single tone), and listens * for the response on the line. Output is written to fxotune_dump.vals * * @param startdev the device to test * @param dialstr the string that should be dialed to clear the dialtone from the line * @param delayuntilsilence the number of seconds to wait after dialing dialstr before starting the test * @param silencegoodfor the number of seconds that the test can run before having to reset the line again * (this is basically the amount of time it takes before the 'if you'd like to make a call...' message * kicks in after you dial dialstr. This test is so short that the value is pretty much ignored. * @param waveformtype the type of waveform to use - -1 = multi-tone waveform, otherwise the specified value * is used as the frequency of a single tone. A value of 0 will output silence. */ static int do_dump(int startdev, char* dialstr, int delayuntilsilence, int silencegoodfor, int waveformtype) { int res = 0; int fd; char dahdidev[80] = ""; int dahdimodule = startdev; fd = channel_open(dahdimodule); if (fd < 0) { return -1; } fprintf(stdout, "Dumping module %s\n", dahdidev); res = maptone(fd, waveformtype, dialstr, delayuntilsilence); close(fd); if (res) { fprintf(stdout, "Failure!\n"); return res; } else { fprintf(stdout, "Done!\n"); return 0; } } /** * Performs calibration on all specified devices * * @param startdev the first device to check * @param enddev the last device to check * @param calibtype the type of calibration to perform. 1=old style (loops through individual frequencies * doesn't optimize echo coefficients. 2=new style (uses multi-tone and optimizes echo coefficients * and acim setting) * @param configfilename the path of the file that the calibration results should be written to * @param dialstr the string that should be dialed to clear the dialtone from the line * @param delayuntilsilence the number of seconds to wait after dialing dialstr before starting the test * @param silencegoodfor the number of seconds that the test can run before having to reset the line again * (this is basically the amount of time it takes before the 'if you'd like to make a call...' message * kicks in after you dial dialstr * * @return 0 if successful, -1 for serious error such as device not available , > 0 indicates the number of channels */ static int do_calibrate(int startdev, int enddev, int calibtype, char* configfilename, char* dialstr, int delayuntilsilence, int silencegoodfor) { int problems = 0; int res = 0; int configfd, fd; int devno = 0; struct wctdm_echo_coefs coefs; configfd = open(configfile, O_CREAT|O_TRUNC|O_WRONLY, 0666); if (configfd < 0) { fprintf(stderr, "Cannot generate config file %s: open: %s\n", configfile, strerror(errno)); return -1; } for (devno = startdev; devno <= enddev; devno++) { fd = channel_open(devno); if (fd < 0) { continue; } fprintf(stdout, "Tuning module %d\n", devno); if (1 == calibtype) res = acim_tune(fd, dialstr, delayuntilsilence, silencegoodfor, &coefs); else res = acim_tune2(fd, -1, dialstr, delayuntilsilence, silencegoodfor, &coefs); close(fd); if (res) { fprintf(stdout, "Failure!\n"); problems++; } else { fprintf(stdout, "Done!\n"); } if (res == 0) { /* Do output to file */ int len = 0; static char output[255] = ""; snprintf(output, sizeof(output), "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d\n", devno, coefs.acim, coefs.coef1, coefs.coef2, coefs.coef3, coefs.coef4, coefs.coef5, coefs.coef6, coefs.coef7, coefs.coef8 ); if (debug) fprintf(stdout, "Found best echo coefficients: %s\n", output); len = strlen(output); res = write(configfd, output, strlen(output)); if (res != len) { fprintf(stdout, "Unable to write line \"%s\" to file.\n", output); return -1; } } } close(configfd); if (problems) fprintf(stdout, "Unable to tune %d devices, even though those devices are present\n", problems); return problems; } int main(int argc , char **argv) { int startdev = 1; /* -b */ int stopdev = 252; /* -e */ int dev_range = 0; /* false */ int calibtype = 2; /* -t */ int waveformtype = -1; /* -w multi-tone by default. If > 0, single tone of specified frequency */ int delaytosilence = 0; /* -l */ int silencegoodfor = 18; /* -m */ char* dialstr = "5"; /* -n */ int res = 0; int doset = 0; /* -s */ int docalibrate = 0; /* -i */ int dodump = 0; /* -d */ int i = 0; int moreargs; for (i = 1; i < argc; i++){ if (!(argv[i][0] == '-' || argv[i][0] == '/') || (strlen(argv[i]) <= 1)){ fprintf(stdout, "Unknown option : %s\n", argv[i]); /* Show usage */ fputs(usage, stdout); return -1; } moreargs = (i < argc - 1); switch(argv[i][1]){ case 's': doset=1; continue; case 'i': docalibrate = 1; if (moreargs){ /* we need to check for a value after 'i' for backwards compatability with command line options of old fxotune */ if (argv[i+1][0] != '-' && argv[i+1][0] != '/') dialstr = argv[++i]; } continue; case 'c': configfile = moreargs ? argv[++i] : configfile; continue; case 'd': dodump = 1; continue; case 'b': startdev = moreargs ? atoi(argv[++i]) : startdev; dev_range = 1; break; case 'e': stopdev = moreargs ? atoi(argv[++i]) : stopdev; dev_range = 1; break; case 't': calibtype = moreargs ? atoi(argv[++i]) : calibtype; break; case 'w': waveformtype = moreargs ? atoi(argv[++i]) : waveformtype; break; case 'l': delaytosilence = moreargs ? atoi(argv[++i]) : delaytosilence; break; case 'm': silencegoodfor = moreargs ? atoi(argv[++i]) : silencegoodfor; break; case 'n': dialstr = moreargs ? argv[++i] : dialstr; break; case 'p': printbest++; break; case 'x': use_table = 1; break; case 'v': debug = strlen(argv[i])-1; break; case 'o': if (moreargs) { audio_dump_fd = open(argv[++i], O_WRONLY|O_CREAT|O_TRUNC, 0666); if (audio_dump_fd == -1) { fprintf(stdout, "Unable to open file %s: %s\n", argv[i], strerror(errno)); return -1; } break; } else { fprintf(stdout, "No path supplied to -o option!\n"); return -1; } default: fprintf(stdout, "Unknown option : %s\n", argv[i]); /* Show usage */ fputs(usage, stdout); return -1; } } if (debug > 3){ fprintf(stdout, "Running with parameters:\n"); fprintf(stdout, "\tdoset=%d\n", doset); fprintf(stdout, "\tdocalibrate=%d\n", docalibrate); fprintf(stdout, "\tdodump=%d\n", dodump); fprintf(stdout, "\tprint best settings=%d\n", printbest); fprintf(stdout, "\tstartdev=%d\n", startdev); fprintf(stdout, "\tstopdev=%d\n", stopdev); fprintf(stdout, "\tcalibtype=%d\n", calibtype); fprintf(stdout, "\twaveformtype=%d\n", waveformtype); fprintf(stdout, "\tdelaytosilence=%d\n", delaytosilence); fprintf(stdout, "\tsilencegoodfor=%d\n", silencegoodfor); fprintf(stdout, "\tdialstr=%s\n", dialstr); fprintf(stdout, "\tdebug=%d\n", debug); } if(use_table) { init_sinetable(); } if (docalibrate){ res = do_calibrate(startdev, stopdev, calibtype, configfile, dialstr, delaytosilence, silencegoodfor); if (!res) return do_set(configfile, dev_range, startdev, stopdev); else return -1; } if (doset) return do_set(configfile, dev_range, startdev, stopdev); if (dodump){ res = do_dump(startdev, dialstr, delaytosilence, silencegoodfor, waveformtype); if (!res) return 0; else return -1; } fputs(usage, stdout); return -1; } dahdi-tools-3.0.0/version.c.in0000644000000000000000000000014413373276276014674 0ustar rootroot/* * version.c.in */ const char dahdi_tools_version[] = "DAHDI Tools Version - @TOOLSVERSION@"; dahdi-tools-3.0.0/xpp/0000755000000000000000000000000013373276276013246 5ustar rootrootdahdi-tools-3.0.0/xpp/astribank_tool.c0000644000000000000000000001210213373276276016421 0ustar rootroot/* * Written by Oron Peled * Copyright (C) 2008, 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include #include "mpptalk.h" #include "astribank.h" #define DBG_MASK 0x80 /* if enabled, adds support for resetting pre-MPP USB firmware - if we * failed opening a device and we were asked to reset it, try also the * old protocol. */ #define SUPPORT_OLD_RESET static char *progname; static void usage() { fprintf(stderr, "Usage: %s [options] -D {/proc/bus/usb|/dev/bus/usb}// [operation...]\n", progname); fprintf(stderr, "\tOptions:\n"); fprintf(stderr, "\t\t[-v] # Increase verbosity\n"); fprintf(stderr, "\t\t[-d mask] # Debug mask (0xFF for everything)\n"); fprintf(stderr, "\tOperations:\n"); fprintf(stderr, "\t\t[-n] # Renumerate device\n"); fprintf(stderr, "\t\t[-r kind] # Reset: kind = {half|full}\n"); fprintf(stderr, "\t\t[-p port] # TwinStar: USB port number [0, 1]\n"); fprintf(stderr, "\t\t[-w (0|1)] # TwinStar: Watchdog off or on guard\n"); fprintf(stderr, "\t\t[-Q] # Query device properties\n"); exit(1); } static int reset_kind(const char *arg) { static const struct { const char *name; int type_code; } reset_kinds[] = { { "half", 0 }, { "full", 1 }, }; int i; for(i = 0; i < sizeof(reset_kinds)/sizeof(reset_kinds[0]); i++) { if(strcasecmp(reset_kinds[i].name, arg) == 0) return reset_kinds[i].type_code; } ERR("Unknown reset kind '%s'\n", arg); return -1; } int main(int argc, char *argv[]) { char *devpath = NULL; struct astribank *astribank; struct mpp_device *mpp; const char options[] = "vd:D:nr:p:w:Q"; int opt_renumerate = 0; char *opt_port = NULL; char *opt_watchdog = NULL; char *opt_reset = NULL; int opt_query = 0; int ret; progname = argv[0]; while (1) { int c; c = getopt (argc, argv, options); if (c == -1) break; switch (c) { case 'D': devpath = optarg; break; case 'n': opt_renumerate++; break; case 'p': opt_port = optarg; break; case 'w': opt_watchdog = optarg; break; case 'r': opt_reset = optarg; /* * Sanity check so we can reject bad * arguments before device access. */ if(reset_kind(opt_reset) < 0) usage(); break; case 'Q': opt_query = 1; break; case 'v': verbose++; break; case 'd': debug_mask = strtoul(optarg, NULL, 0); break; case 'h': default: ERR("Unknown option '%c'\n", c); usage(); } } if(!devpath) { ERR("Missing device path\n"); usage(); } DBG("Startup %s\n", devpath); astribank = astribank_new(devpath); if(!astribank) { ERR("Failed initializing Astribank\n"); return 1; } mpp = astribank_mpp_open(astribank); /* * First process reset options. We want to be able * to reset minimal USB firmwares even if they don't * implement the full MPP protocol (e.g: EEPROM_BURN) */ if(opt_reset) { int full_reset; if((full_reset = reset_kind(opt_reset)) < 0) { ERR("Bad reset kind '%s'\n", opt_reset); return 1; } DBG("Resetting (%s)\n", opt_reset); if((ret = mpp_reset(mpp, full_reset)) < 0) { ERR("%s Resetting astribank failed: %d\n", (full_reset) ? "Full" : "Half", ret); } goto out; } show_astribank_info(astribank); if(opt_query) { show_hardware(mpp); } else if(opt_renumerate) { DBG("Renumerate\n"); if((ret = mpp_renumerate(mpp)) < 0) { ERR("Renumerating astribank failed: %d\n", ret); } } else if(opt_watchdog) { int watchdogstate = strtoul(opt_watchdog, NULL, 0); DBG("TWINSTAR: Setting watchdog %s-guard\n", (watchdogstate) ? "on" : "off"); if((ret = mpp_tws_setwatchdog(mpp, watchdogstate)) < 0) { ERR("Failed to set watchdog to %d\n", watchdogstate); return 1; } } else if(opt_port) { int new_portnum = strtoul(opt_port, NULL, 0); int tws_portnum = mpp_tws_portnum(mpp); char *msg = (new_portnum == tws_portnum) ? " Same same, never mind..." : ""; DBG("TWINSTAR: Setting portnum to %d.%s\n", new_portnum, msg); if((ret = mpp_tws_setportnum(mpp, new_portnum)) < 0) { ERR("Failed to set USB portnum to %d\n", new_portnum); return 1; } } out: astribank_destroy(astribank); return 0; } dahdi-tools-3.0.0/xpp/pic_loader.c0000644000000000000000000001673713373276276015531 0ustar rootroot/* * Written by Oron Peled * Copyright (C) 2008, 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include "hexfile.h" #include "pic_loader.h" #define DBG_MASK 0x20 #define MAX_HEX_LINES 10000 #define TIMEOUT 500 enum xpp_packet_types { PIC_REQ_XOP = 0x09, PIC_REP_XOP = 0x0A }; struct xpp_packet_header { struct { uint16_t len; uint8_t op; uint8_t unit; } PACKED header; union { struct { struct { uint8_t flags; uint8_t card_type; uint16_t offs; } pic_header; uint8_t data[3]; } PACKED pic_packet; } d; } PACKED; int send_picline(struct astribank *ab, uint8_t card_type, enum pic_command pcmd, int offs, uint8_t *data, int data_len) { int recv_answer = 0; char buf[PACKET_SIZE]; struct xpp_packet_header *phead = (struct xpp_packet_header *)buf; int pack_len; int ret; assert(ab != NULL); pack_len = data_len + sizeof(phead->header) + sizeof(phead->d.pic_packet.pic_header); phead->header.len = pack_len; phead->header.op = PIC_REQ_XOP; phead->header.unit = 0x00; phead->d.pic_packet.pic_header.flags = pcmd; phead->d.pic_packet.pic_header.card_type = card_type; phead->d.pic_packet.pic_header.offs = offs; if(data) memcpy(phead->d.pic_packet.data, data, data_len); switch (pcmd) { case PIC_START_FLAG: break; case PIC_DATA_FLAG: break; case PIC_END_FLAG: recv_answer = 1; break; case PIC_ENDS_FLAG: break; } DBG("PICLINE: pack_len=%d pcmd=%d\n", pack_len, pcmd); dump_packet(LOG_DEBUG, DBG_MASK, "dump:picline[W]", (char *)phead, pack_len); ret = astribank_send(ab, 0, buf, pack_len, TIMEOUT); if(ret < 0) { ERR("astribank_send failed: %d\n", ret); return ret; } DBG("astribank_send: Written %d bytes\n", ret); if (recv_answer) { ret = astribank_recv(ab, 0, buf, sizeof(buf), TIMEOUT); if(ret <= 0) { ERR("No USB packs to read\n"); return ret; } else { phead = (struct xpp_packet_header *)buf; if(phead->header.op != PIC_REP_XOP) { ERR("Got unexpected reply OP=0x%02X\n", phead->header.op); dump_packet(LOG_ERR, DBG_MASK, "hexline[ERR]", buf, ret); return -EINVAL; } DBG("received OP=0x%02X, checksum=%02X\n", phead->header.op, phead->d.pic_packet.data[0]); if(phead->d.pic_packet.data[0] != 0) { ERR("PIC burning, bad checksum\n"); return -EINVAL; } } } return 0; } static const char *pic_basename(const char *fname, uint8_t *card_type) { const char *basename; regex_t regex; char ebuf[BUFSIZ]; const char re[] = "PIC_TYPE_([0-9]+)\\.hex"; regmatch_t pmatch[2]; /* One for the whole match, one for the number */ int nmatch = (sizeof(pmatch)/sizeof(pmatch[0])); int len; int ret; basename = strrchr(fname, '/'); if(!basename) basename = fname; if((ret = regcomp(®ex, re, REG_ICASE | REG_EXTENDED)) != 0) { regerror(ret, ®ex, ebuf, sizeof(ebuf)); ERR("regcomp: %s\n", ebuf); return NULL; } if((ret = regexec(®ex, basename, nmatch, pmatch, 0)) != 0) { regerror(ret, ®ex, ebuf, sizeof(ebuf)); ERR("regexec: %s\n", ebuf); regfree(®ex); return NULL; } /* * Should have both complete match and a parentheses match */ if(pmatch[0].rm_so == -1 || pmatch[1].rm_so == -1) { ERR("pic_basename: Bad match: pmatch[0].rm_so=%d pmatch[1].rm_so=%d\n", pmatch[0].rm_so, pmatch[1].rm_so == -1); regfree(®ex); return NULL; } len = pmatch[1].rm_eo - pmatch[1].rm_so; if(len >= sizeof(ebuf) - 1) len = sizeof(ebuf) - 1; memcpy(ebuf, basename + pmatch[1].rm_so, len); ebuf[len] = '\0'; DBG("match: %s\n", ebuf); ret = atoi(ebuf); if(ret <= 0 || ret > 9) { ERR("pic_basename: Bad type number %d\n", ret); regfree(®ex); return NULL; } *card_type = ret; regfree(®ex); return basename; } /* * Returns: true on success, false on failure */ static int pic_burn(struct astribank *ab, const struct hexdata *hexdata) { const char *v = hexdata->version_info; const char *basename; uint8_t *data; unsigned char check_sum = 0; uint8_t card_type; int ret; unsigned int i; const char *devstr; const struct xusb_device *xusb; v = (v[0]) ? v : "Unknown"; assert(ab != NULL); assert(hexdata != NULL); xusb = xusb_dev_of_astribank(ab); devstr = xusb_devpath(xusb); i = xusb_packet_size(xusb); if(i != 512) { ERR("%s: Skip PIC burning (not USB2)\n", devstr); return 0; } INFO("%s [%s]: Loading PIC Firmware: %s (version %s)\n", devstr, xusb_serial(xusb), hexdata->fname, hexdata->version_info); basename = pic_basename(hexdata->fname, &card_type); if(!basename) { ERR("%s: Bad PIC filename '%s'. Abort.\n", devstr, hexdata->fname); return 0; } DBG("basename=%s card_type=%d maxlines=%d\n", basename, card_type, hexdata->maxlines); /* * Try to read extra left-overs from USB controller */ for(i = 2; i; i--) { char buf[PACKET_SIZE]; if (astribank_recv(ab, 0, buf, sizeof(buf), TIMEOUT) <= 0) break; } if((ret = send_picline(ab, card_type, PIC_START_FLAG, 0, NULL, 0)) != 0) { perror("Failed sending start hexline"); return 0; } for(i = 0; i < hexdata->maxlines; i++) { struct hexline *hexline; unsigned int len; hexline = hexdata->lines[i]; if(!hexline) { ERR("%s: hexdata finished early (line %d)", devstr, i); return 0; } if(hexline->d.content.header.tt == TT_DATA) { len = hexline->d.content.header.ll; /* don't send checksum */ if(len != 3) { ERR("%s: Bad line len %d\n", devstr, len); return 0; } data = hexline->d.content.tt_data.data; check_sum ^= data[0] ^ data[1] ^ data[2]; ret = send_picline(ab, card_type, PIC_DATA_FLAG, hexline->d.content.header.offset, data, len); if(ret) { perror("Failed sending data hexline"); return 0; } } else if(hexline->d.content.header.tt == TT_EOF) { break; } else { ERR("%s: Unexpected TT = %d in line %d\n", devstr, hexline->d.content.header.tt, i); return 0; } } if((ret = send_picline(ab, card_type, PIC_END_FLAG, 0, &check_sum, 1)) != 0) { perror("Failed sending end hexline"); return 0; } DBG("Finished...\n"); return 1; } int load_pic(struct astribank *ab, int numfiles, char *filelist[]) { int i; const char *devstr; devstr = xusb_devpath(xusb_dev_of_astribank(ab)); DBG("%s: Loading %d PIC files...\n", devstr, numfiles); for(i = 0; i < numfiles; i++) { struct hexdata *picdata; const char *curr = filelist[i]; DBG("%s\n", curr); if((picdata = parse_hexfile(curr, MAX_HEX_LINES)) == NULL) { perror(curr); return -errno; } if(!pic_burn(ab, picdata)) { ERR("%s: PIC %s burning failed\n", devstr, curr); return -ENODEV; } free_hexdata(picdata); } if((i = send_picline(ab, 0, PIC_ENDS_FLAG, 0, NULL, 0)) != 0) { ERR("%s: PIC end burning failed\n", devstr); return -ENODEV; } return 0; } dahdi-tools-3.0.0/xpp/mpptalk.c0000644000000000000000000007517713373276276015103 0ustar rootroot/* * Written by Oron Peled * Copyright (C) 2008, 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include "hexfile.h" #include "mpptalk.h" #define DBG_MASK 0x04 enum eeprom_burn_state { BURN_STATE_NONE = 0, BURN_STATE_STARTED = 1, BURN_STATE_ENDED = 2, BURN_STATE_FAILED = 3, }; const char *eeprom_type2str(int et) { const static char *msgs[] = { [EEPROM_TYPE_NONE] = "NONE", [EEPROM_TYPE_SMALL] = "SMALL", [EEPROM_TYPE_LARGE] = "LARGE", [EEPROM_TYPE_UNUSED] = "UNUSED", }; if(et > sizeof(msgs)/sizeof(msgs[0])) return NULL; return msgs[et]; }; const char *dev_dest2str(int dest) { const static char *msgs[] = { [DEST_NONE] = "NONE", [DEST_FPGA] = "FPGA", [DEST_EEPROM] = "EEPROM", }; if(dest > sizeof(msgs)/sizeof(msgs[0])) return NULL; return msgs[dest]; }; /* * OP Codes: * MSB of op signifies a reply from device */ #define MPP_RENUM 0x0B /* Trigger USB renumeration */ #define MPP_EEPROM_SET 0x0D /* AB capabilities */ #define MPP_CAPS_GET 0x0E #define MPP_CAPS_GET_REPLY 0x8E #define MPP_CAPS_SET 0x0F #define MPP_DEV_SEND_START 0x05 #define MPP_DEV_SEND_SEG 0x07 #define MPP_DEV_SEND_END 0x09 /* Astribank Status */ #define MPP_STATUS_GET 0x11 #define MPP_STATUS_GET_REPLY 0x91 #define MPP_STATUS_GET_REPLY_V13 0x91 /* backward compat */ /* Get extra vendor information */ #define MPP_EXTRAINFO_GET 0x13 #define MPP_EXTRAINFO_GET_REPLY 0x93 #define MPP_EXTRAINFO_SET 0x15 /* Set extra vendor information */ #define MPP_EEPROM_BLK_RD 0x27 #define MPP_EEPROM_BLK_RD_REPLY 0xA7 #define MPP_SER_SEND 0x37 #define MPP_SER_RECV 0xB7 #define MPP_RESET 0x45 /* Reset both FPGA and USB firmwares */ #define MPP_HALF_RESET 0x47 /* Reset only FPGA firmware */ /* Twinstar */ #define MPP_TWS_WD_MODE_SET 0x31 /* Set watchdog off/on guard */ #define MPP_TWS_WD_MODE_GET 0x32 /* Current watchdog mode */ #define MPP_TWS_WD_MODE_GET_REPLY 0xB2 /* Current watchdog mode */ #define MPP_TWS_PORT_SET 0x34 /* USB-[0/1] */ #define MPP_TWS_PORT_GET 0x35 /* USB-[0/1] */ #define MPP_TWS_PORT_GET_REPLY 0xB5 /* USB-[0/1] */ #define MPP_TWS_PWR_GET 0x36 /* Power: bits -> USB ports */ #define MPP_TWS_PWR_GET_REPLY 0xB6 /* Power: bits -> USB ports */ CMD_DEF(MPP, STATUS_GET); CMD_DEF(MPP, STATUS_GET_REPLY, uint8_t i2cs_data; #define STATUS_FPGA_LOADED(x) ((x) & 0x01) uint8_t status; /* BIT(0) - FPGA is loaded */ struct firmware_versions fw_versions; ); CMD_DEF(MPP, EEPROM_SET, struct eeprom_table data; ); CMD_DEF(MPP, CAPS_GET); CMD_DEF(MPP, CAPS_GET_REPLY, struct eeprom_table data; struct capabilities capabilities; struct capkey key; ); CMD_DEF(MPP, CAPS_SET, struct eeprom_table data; struct capabilities capabilities; struct capkey key; ); CMD_DEF(MPP, EXTRAINFO_GET); CMD_DEF(MPP, EXTRAINFO_GET_REPLY, struct extrainfo info; ); CMD_DEF(MPP, EXTRAINFO_SET, struct extrainfo info; ); CMD_DEF(MPP, RENUM); CMD_DEF(MPP, EEPROM_BLK_RD, uint16_t offset; uint16_t len; ); CMD_DEF(MPP, EEPROM_BLK_RD_REPLY, uint16_t offset; uint8_t data[0]; ); CMD_DEF(MPP, DEV_SEND_START, uint8_t dest; char ihex_version[VERSION_LEN]; ); CMD_DEF(MPP, DEV_SEND_END); CMD_DEF(MPP, DEV_SEND_SEG, uint16_t offset; uint8_t data[0]; ); CMD_DEF(MPP, RESET); CMD_DEF(MPP, HALF_RESET); CMD_DEF(MPP, SER_SEND, uint8_t data[0]; ); CMD_DEF(MPP, SER_RECV, uint8_t data[0]; ); CMD_DEF(MPP, TWS_WD_MODE_SET, uint8_t wd_active; ); CMD_DEF(MPP, TWS_WD_MODE_GET); CMD_DEF(MPP, TWS_WD_MODE_GET_REPLY, uint8_t wd_active; ); CMD_DEF(MPP, TWS_PORT_SET, uint8_t portnum; ); CMD_DEF(MPP, TWS_PORT_GET); CMD_DEF(MPP, TWS_PORT_GET_REPLY, uint8_t portnum; ); CMD_DEF(MPP, TWS_PWR_GET); CMD_DEF(MPP, TWS_PWR_GET_REPLY, uint8_t power; ); union XTALK_PDATA(MPP) { MEMBER(MPP, STATUS_GET); MEMBER(MPP, STATUS_GET_REPLY); MEMBER(MPP, EEPROM_SET); MEMBER(MPP, CAPS_GET); MEMBER(MPP, CAPS_GET_REPLY); MEMBER(MPP, CAPS_SET); MEMBER(MPP, EXTRAINFO_GET); MEMBER(MPP, EXTRAINFO_GET_REPLY); MEMBER(MPP, EXTRAINFO_SET); MEMBER(MPP, RENUM); MEMBER(MPP, EEPROM_BLK_RD); MEMBER(MPP, EEPROM_BLK_RD_REPLY); MEMBER(MPP, DEV_SEND_SEG); MEMBER(MPP, DEV_SEND_START); MEMBER(MPP, DEV_SEND_END); MEMBER(MPP, RESET); MEMBER(MPP, HALF_RESET); MEMBER(MPP, SER_SEND); MEMBER(MPP, SER_RECV); /* Twinstar */ MEMBER(MPP, TWS_WD_MODE_SET); MEMBER(MPP, TWS_WD_MODE_GET); MEMBER(MPP, TWS_WD_MODE_GET_REPLY); MEMBER(MPP, TWS_PORT_SET); MEMBER(MPP, TWS_PORT_GET); MEMBER(MPP, TWS_PORT_GET_REPLY); MEMBER(MPP, TWS_PWR_GET); MEMBER(MPP, TWS_PWR_GET_REPLY); } PACKED members; /* * Statuses */ #define STAT_OK 0x00 /* acknowledges previous command */ #define STAT_FAIL 0x01 /* Last command failed */ #define STAT_RESET_FAIL 0x02 /* reset failed */ #define STAT_NODEST 0x03 /* No destination is selected */ #define STAT_MISMATCH 0x04 /* Data mismatch */ #define STAT_NOACCESS 0x05 /* No access */ #define STAT_BAD_CMD 0x06 /* Bad command */ #define STAT_TOO_SHORT 0x07 /* Packet is too short */ #define STAT_ERROFFS 0x08 /* Offset error */ #define STAT_NOCODE 0x09 /* Source was not burned before */ #define STAT_NO_LEEPROM 0x0A /* Large EEPROM was not found */ #define STAT_NO_EEPROM 0x0B /* No EEPROM was found */ #define STAT_WRITE_FAIL 0x0C /* Writing to device failed */ #define STAT_FPGA_ERR 0x0D /* FPGA error */ #define STAT_KEY_ERR 0x0E /* Bad Capabilities Key */ #define STAT_NOCAPS_ERR 0x0F /* No matching capability */ #define STAT_NOPWR_ERR 0x10 /* No power on USB connector */ #define STAT_CAPS_FPGA_ERR 0x11 /* Setting of the capabilities while FPGA is loaded */ struct xtalk_protocol mpp_proto = { .name = "MPP", .proto_version = 0x14, .commands = { CMD_SEND(MPP, STATUS_GET), CMD_RECV(MPP, STATUS_GET_REPLY), CMD_SEND(MPP, EEPROM_SET), CMD_SEND(MPP, CAPS_GET), CMD_RECV(MPP, CAPS_GET_REPLY), CMD_SEND(MPP, CAPS_SET), CMD_SEND(MPP, EXTRAINFO_GET), CMD_RECV(MPP, EXTRAINFO_GET_REPLY), CMD_SEND(MPP, EXTRAINFO_SET), CMD_SEND(MPP, RENUM), CMD_SEND(MPP, EEPROM_BLK_RD), CMD_RECV(MPP, EEPROM_BLK_RD_REPLY), CMD_SEND(MPP, DEV_SEND_SEG), CMD_SEND(MPP, DEV_SEND_START), CMD_SEND(MPP, DEV_SEND_END), CMD_SEND(MPP, RESET), CMD_SEND(MPP, HALF_RESET), CMD_SEND(MPP, SER_SEND), CMD_SEND(MPP, SER_RECV), /* Twinstar */ CMD_SEND(MPP, TWS_WD_MODE_SET), CMD_SEND(MPP, TWS_WD_MODE_GET), CMD_RECV(MPP, TWS_WD_MODE_GET_REPLY), CMD_SEND(MPP, TWS_PORT_SET), CMD_SEND(MPP, TWS_PORT_GET), CMD_RECV(MPP, TWS_PORT_GET_REPLY), CMD_SEND(MPP, TWS_PWR_GET), CMD_RECV(MPP, TWS_PWR_GET_REPLY), }, .ack_statuses = { [STAT_OK] = "Acknowledges previous command", [STAT_FAIL] = "Last command failed", [STAT_RESET_FAIL] = "Reset failed", [STAT_NODEST] = "No destination is selected", [STAT_MISMATCH] = "Data mismatch", [STAT_NOACCESS] = "No access", [STAT_BAD_CMD] = "Bad command", [STAT_TOO_SHORT] = "Packet is too short", [STAT_ERROFFS] = "Offset error", [STAT_NOCODE] = "Source was not burned before", [STAT_NO_LEEPROM] = "Large EEPROM was not found", [STAT_NO_EEPROM] = "No EEPROM was found", [STAT_WRITE_FAIL] = "Writing to device failed", [STAT_FPGA_ERR] = "FPGA error", [STAT_KEY_ERR] = "Bad Capabilities Key", [STAT_NOCAPS_ERR] = "No matching capability", [STAT_NOPWR_ERR] = "No power on USB connector", [STAT_CAPS_FPGA_ERR] = "Setting of the capabilities while FPGA is loaded", } }; struct mpp_device { struct xtalk_base *xtalk_base; struct xtalk_sync *xtalk_sync; enum eeprom_burn_state burn_state; int eeprom_type; int status; struct firmware_versions fw_versions; }; struct xusb_iface *xubs_iface_of_mpp(struct mpp_device *mpp) { return xusb_iface_of_xtalk_base(mpp->xtalk_base); } struct mpp_device *mpp_new(struct xusb_iface *iface) { struct mpp_device *mpp_dev; int ret; mpp_dev = calloc(sizeof(*mpp_dev), 1); if (!mpp_dev) { ERR("Out of memory\n"); goto err; } mpp_dev->xtalk_base = xtalk_base_new_on_xusb(iface); mpp_dev->xtalk_sync = xtalk_sync_new(mpp_dev->xtalk_base); ret = xtalk_sync_set_protocol(mpp_dev->xtalk_sync, &mpp_proto); if(ret < 0) { ERR("MPP Protocol registration failed: %d\n", ret); goto err; } return mpp_dev; err: if (mpp_dev) free(mpp_dev); return NULL; } void mpp_delete(struct mpp_device *dev) { xtalk_sync_delete(dev->xtalk_sync); dev->xtalk_base = NULL; free(dev); } struct xtalk_sync *xtalk_of_mpp(const struct mpp_device *dev) { return dev->xtalk_sync; } struct cmd_queue { struct cmd_queue *next; struct cmd_queue *prev; struct xtalk_command *cmd; }; static struct cmd_queue output_queue = { .next = &output_queue, .prev = &output_queue, .cmd = NULL }; void dump_command(struct xtalk_command *cmd) { uint16_t len; int i; len = cmd->header.len; if(len < sizeof(struct mpp_header)) { ERR("Command too short (%d)\n", len); return; } INFO("DUMP: OP=0x%X len=%d seq=%d\n", cmd->header.op, cmd->header.len, cmd->header.seq); for(i = 0; i < len - sizeof(struct mpp_header); i++) { INFO(" %2d. 0x%X\n", i, cmd->alt.raw_data[i]); } } static int set_ihex_version(char *dst, const char *src) { memcpy(dst, src, VERSION_LEN); return 0; } enum eeprom_type mpp_eeprom_type(struct mpp_device *mpp_dev) { return mpp_dev->eeprom_type; } /* * Protocol Commands */ int mpp_status_query(struct mpp_device *mpp_dev) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, XTALK_OP(MPP, STATUS_GET), 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } mpp_dev->eeprom_type = 0x3 & (CMD_FIELD(reply, MPP, STATUS_GET_REPLY, i2cs_data) >> 3); mpp_dev->status = CMD_FIELD(reply, MPP, STATUS_GET_REPLY, status); mpp_dev->fw_versions = CMD_FIELD(reply, MPP, STATUS_GET_REPLY, fw_versions); DBG("EEPROM TYPE: %02x\n", mpp_dev->eeprom_type); DBG("FPGA Firmware: %s\n", (mpp_dev->status & 0x1) ? "Loaded" : "Empty"); DBG("Firmware Versions: USB='%s' FPGA='%s' EEPROM='%s'\n", mpp_dev->fw_versions.usb, mpp_dev->fw_versions.fpga, mpp_dev->fw_versions.eeprom); free_command(reply); return ret; } int mpp_eeprom_set(struct mpp_device *mpp_dev, const struct eeprom_table *et) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_EEPROM_SET, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } memcpy(&CMD_FIELD(cmd, MPP, EEPROM_SET, data), et, sizeof(*et)); ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } free_command(reply); return 0; } int mpp_renumerate(struct mpp_device *mpp_dev) { struct xtalk_command *cmd; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_RENUM, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } ret = process_command(xtalk_sync, cmd, NULL, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } return 0; } int mpp_caps_get(struct mpp_device *mpp_dev, struct eeprom_table *eeprom_table, struct capabilities *capabilities, struct capkey *key) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_CAPS_GET, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } assert(reply->header.op == MPP_CAPS_GET_REPLY); if(eeprom_table) { memcpy(eeprom_table, (void *)&CMD_FIELD(reply, MPP, CAPS_GET_REPLY, data), sizeof(*eeprom_table)); } if(capabilities) { const struct capabilities *cap = &CMD_FIELD(reply, MPP, CAPS_GET_REPLY, capabilities); memcpy(capabilities, cap, sizeof(*capabilities)); } if(key) { const struct capkey *k = &CMD_FIELD(reply, MPP, CAPS_GET_REPLY, key); memcpy(key, k, sizeof(*key)); } free_command(reply); return 0; } int mpp_caps_set(struct mpp_device *mpp_dev, const struct eeprom_table *eeprom_table, const struct capabilities *capabilities, const struct capkey *key) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_CAPS_SET, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, data), eeprom_table, sizeof(*eeprom_table)); memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, capabilities), capabilities, sizeof(*capabilities)); memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, key), key, sizeof(*key)); ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } free_command(reply); return 0; } int mpp_extrainfo_get(struct mpp_device *mpp_dev, struct extrainfo *info) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_EXTRAINFO_GET, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } assert(reply->header.op == MPP_EXTRAINFO_GET_REPLY); if(info) { int i; memcpy(info, (void *)&CMD_FIELD(reply, MPP, EXTRAINFO_GET_REPLY, info), sizeof(*info)); /* * clean non-printing characters */ for (i = sizeof(*info) - 1; i >= 0; i--) { if (info->text[i] != (char)0xFF) break; info->text[i] = '\0'; } } free_command(reply); return 0; } int mpp_extrainfo_set(struct mpp_device *mpp_dev, const struct extrainfo *info) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_EXTRAINFO_SET, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } memcpy(&CMD_FIELD(cmd, MPP, EXTRAINFO_SET, info), info, sizeof(*info)); ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } free_command(reply); return 0; } int mpp_eeprom_blk_rd(struct mpp_device *mpp_dev, uint8_t *buf, uint16_t offset, uint16_t len) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; int size; DBG("len = %d, offset = %d\n", len, offset); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_EEPROM_BLK_RD, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } CMD_FIELD(cmd, MPP, EEPROM_BLK_RD, len) = len; CMD_FIELD(cmd, MPP, EEPROM_BLK_RD, offset) = offset; ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); size = ret; goto out; } size = reply->header.len - sizeof(struct mpp_header) - sizeof(XTALK_STRUCT(MPP, EEPROM_BLK_RD_REPLY)); INFO("size=%d offset=0x%X\n", size, CMD_FIELD(reply, MPP, EEPROM_BLK_RD_REPLY, offset)); dump_packet(LOG_DEBUG, DBG_MASK, "BLK_RD", (char *)reply, ret); if(size > len) { ERR("Truncating reply (was %d, now %d)\n", size, len); size = len; } memcpy(buf, CMD_FIELD(reply, MPP, EEPROM_BLK_RD_REPLY, data), size); out: free_command(reply); return size; } int mpp_send_start(struct mpp_device *mpp_dev, int dest, const char *ihex_version) { struct xtalk_command *cmd; struct xtalk_command *reply = NULL; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret = 0; DBG("dest = %s ihex_version = '%s'\n", dev_dest2str(dest), ihex_version); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_DEV_SEND_START, 0)) == NULL) { ERR("new_command failed\n"); ret = -ENOMEM; goto out; } CMD_FIELD(cmd, MPP, DEV_SEND_START, dest) = dest; set_ihex_version(CMD_FIELD(cmd, MPP, DEV_SEND_START, ihex_version), ihex_version); ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); goto out; } out: if(reply) free_command(reply); mpp_dev->burn_state = (ret > 0) ? BURN_STATE_STARTED : BURN_STATE_FAILED; return ret; } int mpp_send_end(struct mpp_device *mpp_dev) { struct xtalk_command *cmd; struct xtalk_command *reply = NULL; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret = 0; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_DEV_SEND_END, 0)) == NULL) { ERR("new_command failed\n"); ret = -ENOMEM; goto out; } ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); goto out; } out: if(reply) free_command(reply); mpp_dev->burn_state = (ret > 0) ? BURN_STATE_ENDED : BURN_STATE_FAILED; return ret; } int mpp_send_seg(struct mpp_device *mpp_dev, const uint8_t *data, uint16_t offset, uint16_t len) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if(mpp_dev->burn_state != BURN_STATE_STARTED) { ERR("Tried to send a segment while burn_state=%d\n", mpp_dev->burn_state); return -EINVAL; } DBG("len = %d, offset = %d (0x%02X, 0x%02X)\n", len, offset, *data, *(data + 1)); if((cmd = new_command(xtalk_base, MPP_DEV_SEND_SEG, len)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } CMD_FIELD(cmd, MPP, DEV_SEND_SEG, offset) = offset; memcpy(CMD_FIELD(cmd, MPP, DEV_SEND_SEG, data), data, len); #if 0 { FILE *fp; if((fp = fopen("seg_data.bin", "a")) == NULL) { perror("seg_data.bin"); exit(1); } if(fwrite(CMD_FIELD(cmd, MPP, DEV_SEND_SEG, data), len, 1, fp) != 1) { perror("fwrite"); exit(1); } fclose(fp); } #endif ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } free_command(reply); return 0; } int mpp_reset(struct mpp_device *mpp_dev, int full_reset) { struct xtalk_command *cmd; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; int op = (full_reset) ? MPP_RESET: MPP_HALF_RESET; DBG("full = %s\n", (full_reset) ? "YES" : "NO"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, op, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } ret = process_command(xtalk_sync, cmd, NULL, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } return 0; } int mpp_serial_cmd(struct mpp_device *mpp_dev, const uint8_t *in, uint8_t *out, uint16_t len) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; uint8_t *data; DBG("len=%d\n", len); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_SER_SEND, len)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } data = CMD_FIELD(cmd, MPP, SER_SEND, data); memcpy(data, in, len); ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } assert(reply->header.op == MPP_SER_RECV); data = CMD_FIELD(reply, MPP, SER_RECV, data); memcpy(out, data, len); free_command(reply); return 0; } int mpps_card_info(struct mpp_device *mpp_dev, int unit, uint8_t *card_type, uint8_t *card_status) { /* * Serial commands must have equal send/receive size */ struct card_info_command { uint8_t ser_op; uint8_t addr; uint8_t card_full_type; /* (type << 4 | subtype) */ uint8_t card_status; /* BIT(0) - PIC burned */ } PACKED; struct card_info_command ci_send; struct card_info_command ci_recv; int ret; memset(&ci_send, 0, sizeof(ci_send)); memset(&ci_recv, 0, sizeof(ci_recv)); ci_send.ser_op = SER_CARD_INFO_GET; ci_send.addr = (unit << 4); /* low nibble is subunit */ ret = mpp_serial_cmd(mpp_dev, (uint8_t *)&ci_send, (uint8_t *)&ci_recv, sizeof(struct card_info_command)); if (ret < 0) return ret; *card_type = ci_recv.card_full_type; *card_status = ci_recv.card_status; return 0; } int mpps_stat(struct mpp_device *mpp_dev, int unit, uint8_t *fpga_configuration, uint8_t *status) { /* * Serial commands must have equal send/receive size */ struct fpga_stat_command { uint8_t ser_op; uint8_t fpga_configuration; uint8_t status; /* BIT(0) - Watchdog timer status */ } PACKED; struct fpga_stat_command fs_send; struct fpga_stat_command fs_recv; int ret; memset(&fs_send, 0, sizeof(fs_send)); memset(&fs_recv, 0, sizeof(fs_recv)); fs_send.ser_op = SER_STAT_GET; ret = mpp_serial_cmd(mpp_dev, (uint8_t *)&fs_send, (uint8_t *)&fs_recv, sizeof(struct fpga_stat_command)); if(ret < 0) return ret; *fpga_configuration = fs_recv.fpga_configuration; *status = fs_recv.status; return 0; } int mpp_tws_watchdog(struct mpp_device *mpp_dev) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_TWS_WD_MODE_GET, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } ret = CMD_FIELD(reply, MPP, TWS_WD_MODE_GET_REPLY, wd_active); DBG("wd_active=0x%X\n", ret); free_command(reply); return ret == 1; } int mpp_tws_setwatchdog(struct mpp_device *mpp_dev, int yes) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("%s\n", (yes) ? "YES" : "NO"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_TWS_WD_MODE_SET, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } CMD_FIELD(cmd, MPP, TWS_WD_MODE_SET, wd_active) = (yes) ? 1 : 0; ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } free_command(reply); return 0; } int mpp_tws_powerstate(struct mpp_device *mpp_dev) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_TWS_PWR_GET, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } ret = CMD_FIELD(reply, MPP, TWS_PWR_GET_REPLY, power); DBG("power=0x%X\n", ret); free_command(reply); return ret; } int mpp_tws_portnum(struct mpp_device *mpp_dev) { struct xtalk_command *cmd; struct xtalk_command *reply; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if((cmd = new_command(xtalk_base, MPP_TWS_PORT_GET, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } ret = process_command(xtalk_sync, cmd, &reply, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } ret = CMD_FIELD(reply, MPP, TWS_PORT_GET_REPLY, portnum); DBG("portnum=0x%X\n", ret); free_command(reply); return ret; } int mpp_tws_setportnum(struct mpp_device *mpp_dev, uint8_t portnum) { struct xtalk_command *cmd; struct xtalk_sync *xtalk_sync; struct xtalk_base *xtalk_base; uint16_t tx_seq; int ret; DBG("\n"); assert(mpp_dev != NULL); xtalk_sync = mpp_dev->xtalk_sync; xtalk_base = mpp_dev->xtalk_base; if(portnum >= 2) { ERR("Invalid portnum (%d)\n", portnum); return -EINVAL; } if((cmd = new_command(xtalk_base, MPP_TWS_PORT_SET, 0)) == NULL) { ERR("new_command failed\n"); return -ENOMEM; } CMD_FIELD(cmd, MPP, TWS_PORT_SET, portnum) = portnum; ret = process_command(xtalk_sync, cmd, NULL, &tx_seq); if(ret < 0) { ERR("process_command failed: %d\n", ret); return ret; } return 0; } /* * data structures */ void show_eeprom(const struct eeprom_table *eprm, FILE *fp) { int rmajor; int rminor; char buf[BUFSIZ]; rmajor = (eprm->release >> 8) & 0xFF; rminor = eprm->release & 0xFF;; memset(buf, 0, LABEL_SIZE + 1); memcpy(buf, eprm->label, LABEL_SIZE); fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Source", eprm->source); fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Vendor", eprm->vendor); fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Product", eprm->product); fprintf(fp, "EEPROM: %-15s: %d.%d\n", "Release", rmajor, rminor); fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Config", eprm->config_byte); fprintf(fp, "EEPROM: %-15s: '%s'\n", "Label", buf); } void show_capabilities(const struct capabilities *capabilities, FILE *fp) { fprintf(fp, "Capabilities: FXS ports: %2d\n", capabilities->ports_fxs); fprintf(fp, "Capabilities: FXO ports: %2d\n", capabilities->ports_fxo); fprintf(fp, "Capabilities: BRI ports: %2d\n", capabilities->ports_bri); fprintf(fp, "Capabilities: PRI ports: %2d\n", capabilities->ports_pri); fprintf(fp, "Capabilities: ECHO ports: %2d\n", capabilities->ports_echo); fprintf(fp, "Capabilities: TwinStar : %s\n", (CAP_EXTRA_TWINSTAR(capabilities)) ? "Yes" : "No"); } void show_astribank_status(struct mpp_device *mpp_dev, FILE *fp) { char version_buf[BUFSIZ]; int is_loaded = STATUS_FPGA_LOADED(mpp_dev->status); fprintf(fp, "Astribank: EEPROM : %s\n", eeprom_type2str(mpp_dev->eeprom_type)); fprintf(fp, "Astribank: FPGA status : %s\n", is_loaded ? "Loaded" : "Empty"); if(is_loaded) { memset(version_buf, 0, sizeof(version_buf)); memcpy(version_buf, mpp_dev->fw_versions.fpga, VERSION_LEN); fprintf(fp, "Astribank: FPGA version: %s\n", version_buf); } } void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp) { char buf[EXTRAINFO_SIZE + 1]; memcpy(buf, extrainfo->text, EXTRAINFO_SIZE); buf[EXTRAINFO_SIZE] = '\0'; /* assure null termination */ fprintf(fp, "Extrainfo: : '%s'\n", buf); } int twinstar_show(struct mpp_device *mpp, FILE *fp) { int watchdog; int powerstate; int portnum; int i; if((watchdog = mpp_tws_watchdog(mpp)) < 0) { ERR("Failed getting TwinStar information\n"); return watchdog; } if((powerstate = mpp_tws_powerstate(mpp)) < 0) { ERR("Failed getting TwinStar powerstate\n"); return powerstate; } if((portnum = mpp_tws_portnum(mpp)) < 0) { ERR("Failed getting TwinStar portnum\n"); return portnum; } fprintf(fp, "TwinStar: Connected to : USB-%1d\n", portnum); fprintf(fp, "TwinStar: Watchdog : %s\n", (watchdog) ? "on-guard" : "off-guard"); for(i = 0; i < 2; i++) { int pw = (1 << i) & powerstate; fprintf(fp, "TwinStar: USB-%1d POWER : %s\n", i, (pw) ? "ON" : "OFF"); } return 0; } int show_hardware(struct mpp_device *mpp_dev) { int ret; struct eeprom_table eeprom_table; struct capabilities capabilities; struct extrainfo extrainfo; ret = mpp_caps_get(mpp_dev, &eeprom_table, &capabilities, NULL); if(ret < 0) return ret; show_eeprom(&eeprom_table, stdout); show_astribank_status(mpp_dev, stdout); if(mpp_dev->eeprom_type == EEPROM_TYPE_LARGE) { show_capabilities(&capabilities, stdout); if(STATUS_FPGA_LOADED(mpp_dev->status)) { uint8_t unit; uint8_t card_status; uint8_t card_type; uint8_t fpga_configuration; uint8_t status; for(unit = 0; unit < 5; unit++) { ret = mpps_card_info(mpp_dev, unit, &card_type, &card_status); if(ret < 0) return ret; printf("CARD %d: type=%x.%x %s\n", unit, ((card_type >> 4) & 0xF), (card_type & 0xF), ((card_status & 0x1) ? "PIC" : "NOPIC")); } ret = mpps_stat(mpp_dev, unit, &fpga_configuration, &status); if (ret < 0) return ret; printf("FPGA: %-17s: %d\n", "Configuration num", fpga_configuration); printf("FPGA: %-17s: %s\n", "Watchdog Timer", (SER_STAT_WATCHDOG_READY(status)) ? "ready" : "expired"); printf("FPGA: %-17s: %s\n", "XPD Alive", (SER_STAT_XPD_ALIVE(status)) ? "yes" : "no"); } ret = mpp_extrainfo_get(mpp_dev, &extrainfo); if(ret < 0) return ret; show_extrainfo(&extrainfo, stdout); if(CAP_EXTRA_TWINSTAR(&capabilities)) { if ((eeprom_table.product & 0xFFF0) != 0x1160) printf("TwinStar: NO\n"); else twinstar_show(mpp_dev, stdout); } } return 0; } dahdi-tools-3.0.0/xpp/genconf_parameters0000644000000000000000000001371713373276276017044 0ustar rootroot# # /etc/dahdi/genconf_parameters # # This file contains parameters that affect the # dahdi_genconf configuration generator. # # Syntax: # * A comment from '#' to end of line # * Blank lines ignored # * Whitespace at end of line trimmed # * Single valued items: # key value # * List valued items: # key # value1 # value2 # ... # # When generating extensions for chan_dahdi.conf or users.conf etc: the # extension number will be channel_number+base_exten . The default is: #base_exten 4000 # # Make FXS (analog phones) extensions answer immediately (sets # 'immediate = yes' for them in chan_dahdi.conf). Don't enable this before # you're read documentation about this option. #fxs_immediate yes # # For FXS (analog phones) - use KS or LS? ks is the only method for # Asterisk to provide disconnect supervision and thus it would normally # be preferred and is the default. #fxs_default_start ls # # For FXO (analog lines) - use KS or LS? KS is the default and is # normally the better choice as it allows detecting hang-ups on many # lines. #fxo_default_start ls # Set tone zone values. This is used for playing tones (busy, dial-tone # and such). The default is 'us'. This sets the value for both loadzone # and defaultzone in system.conf . #lc_country il # The dialplan context into which to send trunks in chan_dahdi.conf or # users.conf. The default value is: #context_lines from-pstn # # The dialplan context into which to send extensions in chan_dahdi.conf or # users.conf. The default value is: #context_phones from-internal # # Two extra contexts for the input ports and output ports of an # Astribank. Default values are: #context_input astbank-input #context_output astbank-output # A group to put all analog phones in. By default 0, so you can dial to # the 'first phone available' using Dahdi/g5 . #group_phones 5 # # A group in which to put all the channels belonging to some trunk. # Thus you can dial through "some trunk" using Dahdi/G0/NUMBER #group_lines 0 # Channels of digital trunk of span N are also added to group 10+N (that # is: 14 for channels of span 4). # Do we want to use PtP ('bri') or PtMP ('bri_ptmp') for BRI? PtMP # allows connecting several CPE devices on the same network device # (several BRI phones on the same line, kind of like several analog # phones on the same analog line). However it is generally brings # unnecessary complexity for a pbx-pbx connection. It is still the # default as this is normally what you get for a BRI PSTN connection. #bri_sig_style bri # # If this option is set (that is: not remmed-out), BRI NT ports will # also be set as overlap. This is useful if you want to connect ISDN # phones. #brint_overlap # The echo canceler to use. If you have a hardware echo canceler, just # leave it be, as this one won't be used anyway. # # The default is mg2, but it may change in the future. E.g: a packager # that bundles a better echo canceler may set it as the default, or # dahdi_genconf will scan for the "best" echo canceler. # #echo_can hpec #echo_can oslec #echo_can none # to avoid echo canceler altogether # bri_hardhdlc: # 'yes' - forces BRI cards to use 'hardhdlc' signalling. # 'no' - forces BRI cards to use 'dchan' (an alias for 'fcshdlc'). # It is usefull only for dahdi with the bristuff patch. # # If it is left out or set to 'auto': # * Information supplied by the driver is used to decide: # - Currently implemented for Astribanks. # - Taken from /sys/bus/xpds/drivers/bri/dchan_hardhdlc. # * Without this info, falls back to 'hardhdlc'. #bri_hardhdlc auto # For MFC/R2 Support: 'R2' will make E1 spans CAS and with the # 'r2_idle_bits' bit in system.conf . It will also make dahdi_genconf default # to generating the channels of this card in unicall.conf rather than in # chan_dahdi.conf . The meaning of this may be extended somehow to support # R2 through openr2/chan_dahdi later on. #pri_connection_type R2 #pri_connection_type CAS # # Explicitly set the idle bits for E1 CAS (Sample value is the default): #r2_idle_bits 1101 # # Set T1 framing type to d4 instead of esf: #tdm_framing d4 # # Use E&M on CAS (default is FXS/FXO). If set, E1 spans will be used as # E&M-E1 and T1 will use the requested type: #em_signalling em #em_signalling em_w #em_signalling featd #em_signalling featdtmf #em_signalling featdtmf_ta #em_signalling featb #em_signalling fgccama #em_signalling fgccamamf # # pri_termtype contains a list of settings: # Currently the only setting is for TE or NT (the default is TE). This # sets two different but normally related configuration items: # # A TE span will have *_cpe signalling in Asterisk and will also get # timing from the remote party. # # A NT span will have *_new signalling in Asterisk and will provide # timing to the remote party. # # pri_termtype is a list if span specs and configuration (TE/NT) for # them. The first spec that matches is used. The matching is of perl # regular expressions, but with '*' and '?' have their meaning from # basic regular expressions. #pri_termtype # SPAN/2 NT # SPAN/4 NT # #pri_termtype # SPAN/* NT # # Astribanks can be matched by span and also by their: # LABEL + XPD number: # this is burned into the Astribank and won't change # if it's connected via different USB port/hub # CONNECTOR + XPD number: # The USB path to which the Astribank is connected. # Replacing an Astribank and connecting to the same USB port/hub # would not change this property. However, any change in USB # wiring (e.g: adding another hub) may alter this. # NUM (XBUS number) + XPD number: # The XBUS number. This is not stable and may even change # between boots. # #pri_termtype # LABEL/usb:INT01216/XPD-0[123] NT # LABEL/usb:INT00375/XPD-0[123] NT # CONNECTOR/@usb-0000:00:1d.7-1/XPD-0[123] NT # CONNECTOR/@usb-0000:00:1d.7-2/XPD-0[123] NT # NUM/XBUS-01/XPD-0[123] NT # NUM/XBUS-03/XPD-0[123] NT dahdi-tools-3.0.0/xpp/xpp_timing0000755000000000000000000000026413373276276015354 0ustar rootroot#! /bin/sh grep 'DRIFT:' /sys/bus/astribanks/devices/xbus-*/timing | sed \ -e 's,/sys/bus/astribanks/devices/,,' \ -e 's,/timing:,: ,' \ -e 's,DRIFT: ,,' \ -e 's/^[^:]*:/\U&/' dahdi-tools-3.0.0/xpp/astribank_license.h0000644000000000000000000000113613373276276017100 0ustar rootroot#ifndef ASTRIBANK_ALLOW_H #define ASTRIBANK_ALLOW_H #include "mpptalk.h" enum license_markers { LICENSE_MARKER_NONE = 0, LICENSE_MARKER_XORCOM = 1, LICENSE_MARKER_GENERIC = 2, }; int license_marker_valid(unsigned int which); void license_markers_help(const char *prefix, FILE *fp); int write_to_file( struct eeprom_table *eeprom_table, struct capabilities *caps, struct capkey *key, unsigned int marker, FILE *f); int read_from_file( struct eeprom_table *eeprom_table, struct capabilities *caps, struct capkey *capkey, unsigned int *used_marker, FILE *f); #endif /* ASTRIBANK_ALLOW_H */ dahdi-tools-3.0.0/xpp/lsdahdi0000755000000000000000000000631413373276276014610 0ustar rootroot#! /usr/bin/perl -w # # Written by Oron Peled # Copyright (C) 2007, Xorcom # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # # $Id$ # use strict; use File::Basename; BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); } use Dahdi; use Dahdi::Span; use Dahdi::Xpp; use Dahdi::Xpp::Xbus; use Dahdi::Xpp::Xpd; my @xbuses = Dahdi::Xpp::xbuses; my @xpds = map { $_->xpds } @xbuses; foreach my $span (Dahdi::spans()) { my $spanno = $span->num; my $xpd = Dahdi::Xpp::xpd_of_span($span); my @lines; my $index = 0; @lines = @{$xpd->lines} if defined $xpd; printf "### Span %2d: %s %s\n", $span->num, $span->name, $span->description; foreach my $chan ($span->chans()) { my %type_map = ( OUT => 'Output', IN => 'Input' ); my ($type) = map { $type_map{$_} or $_ } $chan->type || ("unknown"); my $batt = ""; $batt = "(battery)" if $chan->battery; my @alarms = $chan->alarms; my $alarm_str = join(" ", @alarms); printf "%3d %-10s %-10s %s %s %s\n", $chan->num, $type, $chan->signalling, $chan->info, $batt, $alarm_str; $index++; } } __END__ =head1 NAME lsdahdi - List all Dahdi channels with their types and spans. =head1 SYNOPSIS lsdahdi =head1 DESCRIPTION Example output: ### Span 1: WCTDM/0 "Wildcard TDM400P REV E/F Board 1" 1 FXO FXOLS (In use) 2 FXS FXSKS 3 FXS FXSKS 4 FXS FXSKS ### Span 2: XBUS-00/XPD-00 "Xorcom XPD #00/00: FXO" 5 FXO FXSKS (In use) 6 FXO FXSKS (In use) (no pcm) 7 FXO FXSKS (In use) (no pcm) 8 FXO FXSKS (In use) (no pcm) 9 FXO FXSKS (In use) (no pcm) 10 FXO FXSKS (In use) (no pcm) 11 FXO FXSKS (In use) (no pcm) 12 FXO FXSKS (In use) (no pcm) ### Span 3: XBUS-00/XPD-10 "Xorcom XPD #00/10: FXO" 13 FXO FXSKS (In use) (no pcm) 14 FXO FXSKS (In use) (no pcm) 15 FXO FXSKS (In use) (no pcm) 16 FXO FXSKS (In use) (no pcm) 17 FXO FXSKS (In use) (no pcm) 18 FXO FXSKS (In use) (no pcm) 19 FXO FXSKS (In use) (no pcm) 20 FXO FXSKS (In use) (no pcm) ... ### Span 6: XBUS-01/XPD-00 "Xorcom XPD #01/00: FXS" 37 FXS FXOLS (In use) 38 FXS FXOLS (In use) (no pcm) 39 FXS FXOLS (In use) (no pcm) 40 FXS FXOLS (In use) (no pcm) 41 FXS FXOLS (In use) (no pcm) 42 FXS FXOLS (In use) (no pcm) 43 FXS FXOLS (In use) (no pcm) 44 FXS FXOLS (In use) (no pcm) 45 Output FXOLS (In use) (no pcm) 46 Output FXOLS (In use) (no pcm) 47 Input FXOLS (In use) (no pcm) 48 Input FXOLS (In use) (no pcm) 49 Input FXOLS (In use) (no pcm) 50 Input FXOLS (In use) (no pcm) The first column is the type of the channel (port, for an analog device) and the second one is the signalling (if set). =head1 FILES lsdahdi is a somewhat glorified 'cat /proc/dahdi/*' . Unlike that command, it sorts the spans with the proper order. It also formats the output slightly differently. dahdi-tools-3.0.0/xpp/astribank_allow.c0000644000000000000000000001061213373276276016566 0ustar rootroot/* * Written by Oron Peled and * Alex Landau * Copyright (C) 2008, 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include "mpptalk.h" #include "astribank.h" #include "astribank_license.h" #define DBG_MASK 0x80 static char *progname; static void usage() { fprintf(stderr, "Usage: %s [options...] -D {/proc/bus/usb|/dev/bus/usb}// options\n", progname); fprintf(stderr, "\tOptions:\n"); fprintf(stderr, "\t\t[-v] # Increase verbosity\n"); fprintf(stderr, "\t\t[-d mask] # Debug mask (0xFF for everything)\n"); fprintf(stderr, "\t\t[-w] # Write capabilities to EEPROM, otherwise read capabilities\n"); fprintf(stderr, "\t\t[-f filename] # License filename (stdin/stdout if not specified)\n\n"); fprintf(stderr, "\t\t[-m num] # Numeric code of License markers to generate\n"); license_markers_help("\t", stderr); exit(1); } int main(int argc, char *argv[]) { char *devpath = NULL; struct astribank *astribank; struct mpp_device *mpp; struct eeprom_table eeprom_table; struct capabilities caps; struct capkey key; const char options[] = "vd:D:wf:m:"; int do_write = 0; unsigned int marker = LICENSE_MARKER_GENERIC; FILE *file; char *filename = NULL; int ret; progname = argv[0]; while (1) { int c; c = getopt (argc, argv, options); if (c == -1) break; switch (c) { case 'D': devpath = optarg; break; case 'v': verbose++; break; case 'd': debug_mask = strtoul(optarg, NULL, 0); break; case 'w': do_write = 1; break; case 'f': filename = optarg; break; case 'm': marker = strtoul(optarg, NULL, 0); if (!license_marker_valid(marker)) usage(); break; case 'h': default: ERR("Unknown option '%c'\n", c); usage(); } } if(!devpath) { ERR("Missing device path\n"); usage(); } DBG("Startup %s\n", devpath); astribank = astribank_new(devpath); if(!astribank) { ERR("Failed initializing Astribank\n"); return 1; } mpp = astribank_mpp_open(astribank); ret = mpp_eeprom_type(mpp); if(ret != EEPROM_TYPE_LARGE) { ERR("Cannot use this program with astribank EEPROM type %d (need %d)\n", ret, EEPROM_TYPE_LARGE); return 1; } ret = mpp_caps_get(mpp, &eeprom_table, &caps, &key); if(ret < 0) { ERR("Failed to get original capabilities: %d\n", ret); return 1; } if (do_write) { unsigned int used_marker; /* update capabilities based on input file */ file = stdin; if (filename) { file = fopen(filename, "r"); if (file == NULL) { ERR("Can't open file '%s'\n", filename); return 1; } } ret = read_from_file(&eeprom_table, &caps, &key, &used_marker, file); if (ret < 0) { ERR("Failed to read capabilities from file: %d\n", ret); return 1; } show_capabilities(&caps, stderr); INFO("Burning capabilities\n"); ret = mpp_caps_set(mpp, &eeprom_table, &caps, &key); if(ret < 0) { ERR("Capabilities burning failed: %d\n", ret); return 1; } INFO("Done\n"); if (file != stdin) fclose(file); } else { /* print capabilities to stdout */ file = stdout; if (filename) { file = fopen(filename, "w"); if (file == NULL) { ERR("Can't create file '%s'\n", filename); return 1; } } ret = write_to_file(&eeprom_table, &caps, &key, marker, file); if (ret < 0) { ERR("Failed to write capabilities to file: %d\n", ret); return 1; } if (file != stdout) fclose(file); } astribank_destroy(astribank); return 0; } dahdi-tools-3.0.0/xpp/astribank_hexload.80000644000000000000000000000733413373276276017030 0ustar rootroot.TH "ASTRIBANK_HEXLOAD" "8" "30 May 2011" "" "" .SH NAME astribank_hexload \- Xorcom Astribank (xpp) firmware loader .SH SYNOPSIS .B astribank_hexload \-D \fIdevice-path\fR \-F [\fIoptions\fR] \fIhexfile\fR .B astribank_hexload \-D \fIdevice-path\fR \-p [\fIoptions\fR] \fIhexfile1 .. hexfile4\fR .B astribank_hexload \-D \fIdevice-path\fR \-O [-A] [-S \fIspan-specs\fR] [\fIoptions\fR] \fIimagefile\fR .B astribank_hexload \-D \fIdevice-path\fR \-o [\fIoptions\fR] .B astribank_hexload \-D \fIdevice-path\fR \-E [\fIoptions\fR] \fIhexfile\fR .B astribank_hexload \-h .SH DESCRIPTION .B astribank_hexload is a second-stage firmware loader for Xorcom Astribanks. Note that some very old models use fpga_load(8) instead. This legacy tool hasn't been used for several releases. It can be found in version 2.6 and below of dahdi-tools. The astribank_hexload(8) program is used to load a file in the Intel HEX format into a Xorcom Astribank. It can be used to load either an FPGA firmware or a PIC firmware. It is normally run by the script xpp_fxloader. .SH OPTIONS .B \-D .I device-path .RS Required. The device to read from/write to. This is \fIbus_num\fR/\fIdevice_num\fR, where \fIbus_num\fR and \fIdevice_num\fR are the first two numbers in the output of lsusb(8) or dahdi_hardware(8). On older versions of this tool you needed a complete path to the device, which would be /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR, or /proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR. .RE One of the following is required: .B \-F .RS The firmware to load is a FPGA firmware. .RE .B \-p .RS The firmwares to load is are PIC firmwares. All (typically 4) should be on the command-line. .RE .B \-O .RS The firmware to load is an Octasic echo canceller firmware image file. .RE .B \-o .RS Don't load firmware. Just print the version number of the currently-loaded Octasic echo canceller firmware. .RE .B \-E .RS The firmware to load is a special EEPROM burning one. .RE Other options: .B \-v .RS Increase verbosity. May be used multiple times. .RE .B \-d \fImask\fR .RS Set debug mask to \fImask\fR. Default is 0, 0xFF is "everything". .RE .B \-h .RS Displays usage message. .RE .B \-A .RS When loading a Octasic echo canceller firmware, set the channels of the first Astribank module to use aLaw (G.711a). This is what you'd normally use for BRI and E1. If not set, the default mu-Law (G.711u), which is what you'd normally use for FXS, FXO and T1. .RE .B \-S \fIspan-specs\fR .RS This option should only be used when loading Octasic echo canceller firmware and only if the first Astribank module is PRI. Its goal is to allow specifying different \fIline-mode\fR (E1/T1/J1) in different ports of the PRI module. \fBastribank_hexload\fR use the \fIspan-specs\fR argument to select aLaw/uLaw for each of the PRI ports in the module. The \fIspan-specs\fR is a list of items separated by whitespace or commas. Each item is composed of a port selector, colon and a \fIline-mode\fR specifier. This syntax follows the syntax of specifiers in \fB/etc/dahdi/span-types.conf\fR. Examples: .RS 3:E1 \- The 3'rd port is E1. *:T1 \- Any unspecified port is T1 (wildcard match). 1:T1,2:T1,*:E1 \- First and second ports are T1, the rest are E1. .RE If the \fB\-S\fR is not given, the PRI default is determined by the existence of the \fB\-A-fR option. .RE .SH SEE ALSO fxload(8), lsusb(8), astribank_tool(8) .SH AUTHOR This manual page was written by Tzafrir Cohen . Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL. dahdi-tools-3.0.0/xpp/echo_loader.c0000644000000000000000000006225713373276276015672 0ustar rootroot/* * Written by Oron Peled * Copyright (C) 2008, 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "echo_loader.h" #include "parse_span_specs.h" #ifdef __GNUC__ #define PACKED __attribute__((packed)) #else #define PACKED #endif #define DBG_MASK 0x10 #define TIMEOUT 1000 #define ECHO_MAX_CHANS 128 #define ECHO_RIN_STREAM 0 #define ECHO_ROUT_STREAM 1 #define ECHO_SIN_STREAM 2 #define ECHO_SOUT_STREAM 3 #define ECHO_RIN_STREAM2 4 #define ECHO_SIN_STREAM2 6 #define ECHO_ROUT_STREAM2 5 #define ECHO_SOUT_STREAM2 7 #define EC_VER_TEST 0xABCD #define EC_VER_INVALID 0xFFFF static float oct_fw_load_timeout = 2.0; struct echo_mod { tPOCT6100_INSTANCE_API pApiInstance; UINT32 ulEchoChanHndl[256]; struct astribank *astribank; int maxchans; }; enum xpp_packet_types { SPI_SND_XOP = 0x0F, SPI_RCV_XOP = 0x10, TST_SND_XOP = 0x35, TST_RCV_XOP = 0x36, }; struct xpp_packet_header { struct { uint16_t len; uint8_t op; uint8_t unit; } PACKED header; union { struct { uint8_t header; uint8_t flags; uint8_t addr_l; uint8_t addr_h; uint8_t data_l; uint8_t data_h; } PACKED spi_pack; struct { uint8_t tid; uint8_t tsid; } PACKED tst_pack; } alt; } PACKED; static struct usb_buffer { char data[PACKET_SIZE]; int max_len; int curr; /* statistics */ int min_send; int max_send; int num_sends; long total_bytes; struct timeval start; struct timeval end; } usb_buffer; static void usb_buffer_init(struct astribank *astribank, struct usb_buffer *ub) { ub->max_len = xusb_packet_size(xusb_dev_of_astribank(astribank)); ub->curr = 0; ub->min_send = INT_MAX; ub->max_send = 0; ub->num_sends = 0; ub->total_bytes = 0; gettimeofday(&ub->start, NULL); } static long usb_buffer_usec(struct usb_buffer *ub) { struct timeval now; gettimeofday(&now, NULL); return (now.tv_sec - ub->start.tv_sec) * 1000000 + (now.tv_usec - ub->start.tv_usec); } static void usb_buffer_showstatistics(struct astribank *astribank, struct usb_buffer *ub) { long usec; usec = usb_buffer_usec(ub); AB_INFO(astribank, "Octasic statistics: packet_size=[%d, %ld, %d] packets=%d, bytes=%ld msec=%ld usec/packet=%ld\n", ub->min_send, ub->total_bytes / ub->num_sends, ub->max_send, ub->num_sends, ub->total_bytes, usec / 1000, usec / ub->num_sends); } static int usb_buffer_flush(struct astribank *astribank, struct usb_buffer *ub) { int ret; long t; long sec; static int last_sec; if (ub->curr == 0) return 0; ret = astribank_send(astribank, 0, ub->data, ub->curr, TIMEOUT); if (ret < 0) { AB_ERR(astribank, "xusb_send failed: %d\n", ret); return ret; } DBG("%s: Written %d bytes\n", __func__, ret); if (ret > ub->max_send) ub->max_send = ret; if (ret < ub->min_send) ub->min_send = ret; ub->total_bytes += ret; ub->num_sends++; ub->curr = 0; sec = usb_buffer_usec(ub) / (1000 * 1000); if (sec > last_sec) { DBG("bytes/sec=%ld average len=%ld\n", ub->total_bytes / sec, ub->total_bytes / ub->num_sends); last_sec = sec; } /* * Best result with high frequency firmware: 21 seconds * Octasic statistics: packet_size=[10, 239, 510] packets=26806, bytes=6419640 usec=21127883 usec/packet=788 * t = 0.3 * ret - 150; */ t = oct_fw_load_timeout * ret - 150; if (t > 0) usleep(t); return ret; } static int usb_buffer_append(struct astribank *astribank, struct usb_buffer *ub, char *buf, int len) { if (ub->curr + len >= ub->max_len) { AB_ERR(astribank, "%s: buffer too small ub->curr=%d, len=%d, ub->max_len=%d\n", __func__, ub->curr, len, ub->max_len); return -ENOMEM; } memcpy(ub->data + ub->curr, buf, len); ub->curr += len; return len; } static int usb_buffer_send(struct astribank *astribank, struct usb_buffer *ub, char *buf, int len, int timeout, int recv_answer) { int ret = 0; if (ub->curr + len >= ub->max_len) { ret = usb_buffer_flush(astribank, ub); if (ret < 0) return ret; } if ((ret = usb_buffer_append(astribank, ub, buf, len)) < 0) { return ret; } DBG("%s: %d bytes %s\n", __func__, len, (recv_answer) ? "recv" : "send"); if (recv_answer) { struct xpp_packet_header *phead; ret = usb_buffer_flush(astribank, ub); if (ret < 0) return ret; ret = astribank_recv(astribank, 0, buf, PACKET_SIZE, TIMEOUT); if (ret <= 0) { AB_ERR(astribank, "No USB packs to read: %s\n", strerror(-ret)); return -EINVAL; } DBG("%s: %d bytes recv\n", __func__, ret); phead = (struct xpp_packet_header *)buf; if (phead->header.op != SPI_RCV_XOP && phead->header.op != TST_RCV_XOP) { AB_ERR(astribank, "Got unexpected reply OP=0x%02X\n", phead->header.op); dump_packet(LOG_ERR, DBG_MASK, "hexline[ERR]", buf, ret); return -EINVAL; } dump_packet(LOG_DEBUG, DBG_MASK, "dump:echoline[R]", (char *)phead, phead->header.len); switch(phead->header.op) { case SPI_RCV_XOP: ret = (phead->alt.spi_pack.data_h << 8) | phead->alt.spi_pack.data_l; break; case TST_RCV_XOP: ret = (phead->alt.tst_pack.tid << 8) | phead->alt.tst_pack.tsid; break; default: ret = -EINVAL; } } return ret; } int spi_send(struct astribank *astribank, uint16_t addr, uint16_t data, int recv_answer, int ver) { int ret; char buf[PACKET_SIZE]; struct xpp_packet_header *phead = (struct xpp_packet_header *)buf; int pack_len; int spi_flags; assert(astribank != NULL); spi_flags = 0x30 | (recv_answer ? 0x40 : 0x00) | (ver ? 0x01 : 0x00); pack_len = sizeof(phead->header) + sizeof(phead->alt.spi_pack); phead->header.len = pack_len; phead->header.op = SPI_SND_XOP; phead->header.unit = 0x40; /* EC has always this unit num */ phead->alt.spi_pack.header = 0x05; phead->alt.spi_pack.flags = spi_flags; phead->alt.spi_pack.addr_l = (addr >> 0) & 0xFF; phead->alt.spi_pack.addr_h = (addr >> 8) & 0xFF; phead->alt.spi_pack.data_l = (data >> 0) & 0xFF; phead->alt.spi_pack.data_h = (data >> 8) & 0xFF; dump_packet(LOG_DEBUG, DBG_MASK, "dump:echoline[W]", (char *)phead, pack_len); ret = usb_buffer_send(astribank, &usb_buffer, buf, pack_len, TIMEOUT, recv_answer); if (ret < 0) { AB_ERR(astribank, "usb_buffer_send failed: %d\n", ret); return ret; } DBG("%s: Written %d bytes\n", __func__, ret); return ret; } int test_send(struct astribank *astribank) { int ret; char buf[PACKET_SIZE]; struct xpp_packet_header *phead = (struct xpp_packet_header *)buf; int pack_len; assert(astribank != NULL); pack_len = sizeof(phead->header) + sizeof(phead->alt.tst_pack); phead->header.len = 6; phead->header.op = 0x35; phead->header.unit = 0x00; phead->alt.tst_pack.tid = 0x28; /* EC TestId */ phead->alt.tst_pack.tsid = 0x00; /* EC SubId */ dump_packet(LOG_DEBUG, DBG_MASK, "dump:echoline[W]", (char *)phead, pack_len); ret = usb_buffer_send(astribank, &usb_buffer, buf, pack_len, TIMEOUT, 1); if (ret < 0) { AB_ERR(astribank, "usb_buffer_send failed: %d\n", ret); return ret; } DBG("%s: Written %d bytes\n", __func__, ret); return ret; } int echo_send_data(struct astribank *astribank, const unsigned int addr, const unsigned int data) { int ret; /* DBG("SEND: %04X -> [%04X]\n", data, addr); DBG("\t\t[%04X] <- %04X\n", 0x0008, (addr >> 20)); DBG("\t\t[%04X] <- %04X\n", 0x000A, (addr >> 4) & ((1 << 16) - 1)); DBG("\t\t[%04X] <- %04X\n", 0x0004, data); DBG("\t\t[%04X] <- %04X\n", 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (3 << 12) | 1); */ DBG("SND:\n"); ret = spi_send(astribank, 0x0008, (addr >> 20) , 0, 0); if (ret < 0) goto failed; ret = spi_send(astribank, 0x000A, (addr >> 4) & ((1 << 16) - 1) , 0, 0); if (ret < 0) goto failed; ret = spi_send(astribank, 0x0004, data , 0, 0); if (ret < 0) goto failed; ret = spi_send(astribank, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (3 << 12) | 1 , 0, 0); if (ret < 0) goto failed; return cOCT6100_ERR_OK; failed: AB_ERR(astribank, "echo_send_data: spi_send failed (ret = %d)\n", ret); return ret; } int echo_recv_data(struct astribank *astribank, const unsigned int addr) { unsigned int data = 0x00; int ret; DBG("RCV:\n"); ret = spi_send(astribank, 0x0008, (addr >> 20) , 0, 0); if (ret < 0) goto failed; ret = spi_send(astribank, 0x000A, (addr >> 4) & ((1 << 16) - 1) , 0, 0); if (ret < 0) goto failed; ret = spi_send(astribank, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | 1 , 0, 0); if (ret < 0) goto failed; ret = spi_send(astribank, 0x0004, data , 1, 0); if (ret < 0) goto failed; return ret; failed: AB_ERR(astribank, "echo_recv_data: spi_send failed (ret = %d)\n", ret); return ret; } int load_file(char *filename, unsigned char **ppBuf, UINT32 *pLen) { unsigned char *pbyFileData = NULL; FILE *pFile; DBG("Loading %s file...\n", filename); pFile = fopen(filename, "rb"); if (pFile == NULL) { ERR("fopen: %s\n", strerror(errno)); return -ENODEV; } fseek(pFile, 0L, SEEK_END); *pLen = ftell(pFile); fseek(pFile, 0L, SEEK_SET); pbyFileData = (unsigned char *)malloc(*pLen); if (pbyFileData == NULL) { fclose(pFile); ERR("malloc\n"); return -ENODEV; } else { DBG("allocated mem for pbyFileData\n"); } if (fread(pbyFileData, 1, *pLen, pFile) != *pLen) { fclose(pFile); ERR("fread: %s\n", strerror(errno)); return -ENODEV; } fclose(pFile); DBG("Successful loading %s file into memory " "(size = %d, DUMP: first = %02X %02X, last = %02X %02X)\n", filename, *pLen, pbyFileData[0], pbyFileData[1], pbyFileData[(*pLen)-2], pbyFileData[(*pLen)-1]); *ppBuf = pbyFileData; return 0; } UINT32 Oct6100UserGetTime(tPOCT6100_GET_TIME f_pTime) { ///* Why couldn't they just take a timeval like everyone else? */ struct timeval tv; unsigned long long total_usecs; unsigned int mask = ~0; gettimeofday(&tv, 0); total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) + (((unsigned long long)(tv.tv_usec))); f_pTime->aulWallTimeUs[0] = (total_usecs & mask); f_pTime->aulWallTimeUs[1] = (total_usecs >> 32); //printf("Inside of Oct6100UserGetTime\n"); return cOCT6100_ERR_OK; } UINT32 Oct6100UserMemSet(PVOID f_pAddress, UINT32 f_ulPattern, UINT32 f_ulLength) { memset(f_pAddress, f_ulPattern, f_ulLength); return cOCT6100_ERR_OK; } UINT32 Oct6100UserMemCopy(PVOID f_pDestination, const void *f_pSource, UINT32 f_ulLength) { memcpy(f_pDestination, f_pSource, f_ulLength); return cOCT6100_ERR_OK; } UINT32 Oct6100UserCreateSerializeObject(tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate) { return cOCT6100_ERR_OK; } UINT32 Oct6100UserDestroySerializeObject(tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy) { #ifdef OCTASIC_DEBUG ERR("I should never be called! (destroy serialize object)\n"); #endif return cOCT6100_ERR_OK; } UINT32 Oct6100UserSeizeSerializeObject(tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize) { /* Not needed */ return cOCT6100_ERR_OK; } UINT32 Oct6100UserReleaseSerializeObject(tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease) { /* Not needed */ return cOCT6100_ERR_OK; } UINT32 Oct6100UserDriverWriteApi(tPOCT6100_WRITE_PARAMS f_pWriteParams) { const unsigned int addr = f_pWriteParams->ulWriteAddress; const unsigned int data = f_pWriteParams->usWriteData; const struct echo_mod *echo_mod = (struct echo_mod *)(f_pWriteParams->pProcessContext); struct astribank *astribank = echo_mod->astribank; int ret; ret = echo_send_data(astribank, addr, data); if (ret < 0) { ERR("echo_send_data failed (ret = %d)\n", ret); return cOCT6100_ERR_FATAL_DRIVER_WRITE_API; } return cOCT6100_ERR_OK; } UINT32 Oct6100UserDriverWriteSmearApi(tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams) { unsigned int addr; unsigned int data; unsigned int len; const struct echo_mod *echo_mod; struct astribank *astribank; unsigned int i; len = f_pSmearParams->ulWriteLength; echo_mod = (struct echo_mod *)f_pSmearParams->pProcessContext; astribank = echo_mod->astribank; for (i = 0; i < len; i++) { int ret; addr = f_pSmearParams->ulWriteAddress + (i << 1); data = f_pSmearParams->usWriteData; ret = echo_send_data(astribank, addr, data); if (ret < 0) { ERR("echo_send_data failed (ret = %d)\n", ret); return cOCT6100_ERR_FATAL_DRIVER_WRITE_API; } } return cOCT6100_ERR_OK; } UINT32 Oct6100UserDriverWriteBurstApi(tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams) { unsigned int addr; unsigned int data; unsigned int len = f_pBurstParams->ulWriteLength; const struct echo_mod *echo_mod = (struct echo_mod *)f_pBurstParams->pProcessContext; struct astribank *astribank = echo_mod->astribank; unsigned int i; for (i = 0; i < len; i++) { int ret; addr = f_pBurstParams->ulWriteAddress + (i << 1); data = f_pBurstParams->pusWriteData[i]; ret = echo_send_data(astribank, addr, data); if (ret < 0) { ERR("echo_send_data failed (ret = %d)\n", ret); return cOCT6100_ERR_FATAL_DRIVER_WRITE_API; } } return cOCT6100_ERR_OK; } UINT32 Oct6100UserDriverReadApi(tPOCT6100_READ_PARAMS f_pReadParams) { const unsigned int addr = f_pReadParams->ulReadAddress; const struct echo_mod *echo_mod; struct astribank *astribank; int ret; echo_mod = (struct echo_mod *)f_pReadParams->pProcessContext; astribank = echo_mod->astribank; ret = echo_recv_data(astribank, addr); if (ret < 0) { ERR("echo_recv_data failed (%d)\n", ret); return cOCT6100_ERR_FATAL_DRIVER_READ_API; } *f_pReadParams->pusReadData = ret; return cOCT6100_ERR_OK; } UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams) { unsigned int addr; unsigned int len; const struct echo_mod *echo_mod; struct astribank *astribank; unsigned int i; len = f_pBurstParams->ulReadLength; echo_mod = (struct echo_mod *)f_pBurstParams->pProcessContext; astribank = echo_mod->astribank; for (i = 0;i < len; i++) { unsigned int ret; addr = f_pBurstParams->ulReadAddress + (i << 1); ret = echo_recv_data(astribank, addr); if (ret < 0) { ERR("echo_recv_data failed (%d)\n", ret); return cOCT6100_ERR_FATAL_DRIVER_READ_API; } f_pBurstParams->pusReadData[i] = ret; } return cOCT6100_ERR_OK; } inline int get_ver(struct astribank *astribank) { return spi_send(astribank, 0, 0, 1, 1); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ UINT32 init_octasic(char *filename, struct astribank *astribank, struct span_specs *span_specs) { int cpld_ver; struct echo_mod *echo_mod; UINT32 nChan; UINT32 nSlot; UINT32 pcmLaw; UINT32 ulResult; tOCT6100_GET_INSTANCE_SIZE InstanceSize; tPOCT6100_INSTANCE_API pApiInstance; tOCT6100_CHIP_OPEN OpenChip; UINT32 ulImageByteSize; PUINT8 pbyImageData = NULL; /*=========================================================================*/ /* Channel resources.*/ tOCT6100_CHANNEL_OPEN ChannelOpen; UINT32 ulChanHndl; enum tdm_codec tdm_codec; int spanno; if (test_send(astribank) < 0) return cOCT6100_ERR_FATAL; cpld_ver = get_ver(astribank); AB_INFO(astribank, "Check EC_CPLD version: %d\n", cpld_ver); if (cpld_ver < 0) return cOCT6100_ERR_FATAL; else if (cpld_ver == EC_VER_TEST) { AB_INFO(astribank, "+---------------------------------------------------------+\n"); AB_INFO(astribank, "| WARNING: TEST HARDWARE IS ON THE BOARD INSTEAD OF EC!!! |\n"); AB_INFO(astribank, "+---------------------------------------------------------+\n"); return cOCT6100_ERR_OK; } /**************************************************************************/ /**************************************************************************/ /* 1) Configure and Open the OCT6100. */ /**************************************************************************/ /**************************************************************************/ memset(&InstanceSize, 0, sizeof(tOCT6100_GET_INSTANCE_SIZE)); memset(&OpenChip, 0, sizeof(tOCT6100_CHIP_OPEN)); echo_mod = malloc(sizeof(struct echo_mod)); if (!echo_mod) { AB_ERR(astribank, "cannot allocate memory for echo_mod\n"); return cOCT6100_ERR_FATAL; } DBG("allocated mem for echo_mod\n"); memset(echo_mod, 0, sizeof(struct echo_mod)); /* Fill the OCT6100 Chip Open configuration structure with default values */ ulResult = Oct6100ChipOpenDef(&OpenChip); if (ulResult != cOCT6100_ERR_OK) { AB_ERR(astribank, "Oct6100ChipOpenDef failed: result=%X\n", ulResult); return ulResult; } OpenChip.pProcessContext = echo_mod; /* Configure clocks */ /* upclk oscillator is at 33.33 Mhz */ OpenChip.ulUpclkFreq = cOCT6100_UPCLK_FREQ_33_33_MHZ; /* mclk will be generated by internal PLL at 133 Mhz */ OpenChip.fEnableMemClkOut = TRUE; OpenChip.ulMemClkFreq = cOCT6100_MCLK_FREQ_133_MHZ; /* General parameters */ OpenChip.fEnableChannelRecording = TRUE; /* Chip ID.*/ OpenChip.ulUserChipId = 1; /* Set the max number of accesses to 1024 to speed things up */ /* OpenChip.ulMaxRwAccesses = 1024; */ /* Set the maximums that the chip needs to support for this test */ OpenChip.ulMaxChannels = 256; OpenChip.ulMaxPlayoutBuffers = 2; OpenChip.ulMaxBiDirChannels = 0; OpenChip.ulMaxConfBridges = 0; OpenChip.ulMaxPhasingTssts = 0; OpenChip.ulMaxTdmStreams = 8; OpenChip.ulMaxTsiCncts = 0; /* External Memory Settings: Use DDR memory*/ OpenChip.ulMemoryType = cOCT6100_MEM_TYPE_DDR; OpenChip.ulNumMemoryChips = 1; OpenChip.ulMemoryChipSize = cOCT6100_MEMORY_CHIP_SIZE_32MB; /* Load the image file */ ulResult = load_file( filename, &pbyImageData, &ulImageByteSize); if (ulResult != 0) { AB_ERR(astribank, "Failed load_file %s (%08X)\n", filename, ulResult); return ulResult; } if (pbyImageData == NULL || ulImageByteSize == 0){ AB_ERR(astribank, "Bad pbyImageData or ulImageByteSize\n"); return cOCT6100_ERR_FATAL; } /* Assign the image file.*/ OpenChip.pbyImageFile = pbyImageData; OpenChip.ulImageSize = ulImageByteSize; /* * Inserting default values into tOCT6100_GET_INSTANCE_SIZE * structure parameters. */ Oct6100GetInstanceSizeDef(&InstanceSize); /* Get the size of the OCT6100 instance structure. */ ulResult = Oct6100GetInstanceSize(&OpenChip, &InstanceSize); if (ulResult != cOCT6100_ERR_OK) { AB_ERR(astribank, "Oct6100GetInstanceSize failed (%08X)\n", ulResult); return ulResult; } pApiInstance = malloc(InstanceSize.ulApiInstanceSize); echo_mod->pApiInstance = pApiInstance; echo_mod->astribank = astribank; if (!pApiInstance) { AB_ERR(astribank, "Out of memory (can't allocate %d bytes)!\n", InstanceSize.ulApiInstanceSize); return cOCT6100_ERR_FATAL; } /* Perform actual open of chip */ ulResult = Oct6100ChipOpen(pApiInstance, &OpenChip); if (ulResult != cOCT6100_ERR_OK) { AB_ERR(astribank, "Oct6100ChipOpen failed: result=%X\n", ulResult); return ulResult; } DBG("%s: OCT6100 is open\n", __func__); /* Free the image file data */ free(pbyImageData); /**************************************************************************/ /**************************************************************************/ /* 2) Open channels in echo cancellation mode. */ /**************************************************************************/ /**************************************************************************/ for (nChan = 0; nChan < ECHO_MAX_CHANS; nChan++) { nSlot = nChan; /* open a channel.*/ Oct6100ChannelOpenDef(&ChannelOpen); /* Assign the handle memory.*/ ChannelOpen.pulChannelHndl = &ulChanHndl; /* Set the channel to work at the echo cancellation mode.*/ ChannelOpen.ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_NORMAL; spanno = nChan % 4; assert(spanno >= 0 && spanno < MAX_SPANNO); tdm_codec = span_specs->span_is_alaw[spanno]; if (tdm_codec == TDM_CODEC_UNKNOWN) { AB_ERR(astribank, "Calculated bad alaw/ulaw on channel %d\n", nChan); return cOCT6100_ERR_FATAL; } if (nChan < 4) AB_INFO(astribank, "ECHO PRI port %d = %s\n", spanno+1, (tdm_codec == TDM_CODEC_ALAW) ? "alaw" : "ulaw"); pcmLaw = ((tdm_codec == TDM_CODEC_ALAW) ? cOCT6100_PCM_A_LAW: cOCT6100_PCM_U_LAW); /* Configure the TDM interface.*/ ChannelOpen.TdmConfig.ulRinPcmLaw = pcmLaw; ChannelOpen.TdmConfig.ulRinStream = ECHO_RIN_STREAM; ChannelOpen.TdmConfig.ulRinTimeslot = nSlot; ChannelOpen.TdmConfig.ulSinPcmLaw = pcmLaw; ChannelOpen.TdmConfig.ulSinStream = ECHO_SIN_STREAM; ChannelOpen.TdmConfig.ulSinTimeslot = nSlot; ChannelOpen.TdmConfig.ulRoutPcmLaw = pcmLaw; ChannelOpen.TdmConfig.ulRoutStream = ECHO_ROUT_STREAM; ChannelOpen.TdmConfig.ulRoutTimeslot = nSlot; ChannelOpen.TdmConfig.ulSoutPcmLaw = pcmLaw; ChannelOpen.TdmConfig.ulSoutStream = ECHO_SOUT_STREAM; ChannelOpen.TdmConfig.ulSoutTimeslot = nSlot; /* Set the desired VQE features.*/ ChannelOpen.VqeConfig.fEnableNlp = TRUE; ChannelOpen.VqeConfig.fRinDcOffsetRemoval = TRUE; ChannelOpen.VqeConfig.fSinDcOffsetRemoval = TRUE; ChannelOpen.VqeConfig.ulComfortNoiseMode = cOCT6100_COMFORT_NOISE_NORMAL; /* cOCT6100_COMFORT_NOISE_NORMAL cOCT6100_COMFORT_NOISE_EXTENDED, cOCT6100_COMFORT_NOISE_OFF, cOCT6100_COMFORT_NOISE_FAST_LATCH */ ulResult = Oct6100ChannelOpen( pApiInstance, &ChannelOpen); if (ulResult != cOCT6100_ERR_OK) { AB_ERR(astribank, "Found error on chan %d\n", nChan); return ulResult; } } /**************************************************************************/ /**************************************************************************/ /* *) Open channels in echo cancellation mode for second bus. */ /**************************************************************************/ /**************************************************************************/ for (nChan = 8; nChan < 32; nChan++) { nSlot = (nChan >> 3) * 32 + (nChan & 0x07); /* open a channel.*/ Oct6100ChannelOpenDef(&ChannelOpen); /* Assign the handle memory.*/ ChannelOpen.pulChannelHndl = &ulChanHndl; /* Set the channel to work at the echo cancellation mode.*/ ChannelOpen.ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_NORMAL; /* Configure the TDM interface.*/ ChannelOpen.TdmConfig.ulRinStream = ECHO_RIN_STREAM2;; ChannelOpen.TdmConfig.ulRinTimeslot = nSlot; ChannelOpen.TdmConfig.ulSinStream = ECHO_SIN_STREAM2; ChannelOpen.TdmConfig.ulSinTimeslot = nSlot; ChannelOpen.TdmConfig.ulRoutStream = ECHO_ROUT_STREAM2; ChannelOpen.TdmConfig.ulRoutTimeslot = nSlot; ChannelOpen.TdmConfig.ulSoutStream = ECHO_SOUT_STREAM2; ChannelOpen.TdmConfig.ulSoutTimeslot = nSlot; /* Set the desired VQE features.*/ ChannelOpen.VqeConfig.fEnableNlp = TRUE; ChannelOpen.VqeConfig.fRinDcOffsetRemoval = TRUE; ChannelOpen.VqeConfig.fSinDcOffsetRemoval = TRUE; ChannelOpen.VqeConfig.ulComfortNoiseMode = cOCT6100_COMFORT_NOISE_NORMAL; /* cOCT6100_COMFORT_NOISE_NORMAL cOCT6100_COMFORT_NOISE_EXTENDED, cOCT6100_COMFORT_NOISE_OFF, cOCT6100_COMFORT_NOISE_FAST_LATCH */ ulResult = Oct6100ChannelOpen( pApiInstance, &ChannelOpen); if (ulResult != cOCT6100_ERR_OK) { AB_ERR(astribank, "Found error on chan %d\n", nChan); return ulResult; } } DBG("%s: Finishing\n", __func__); free(pApiInstance); free(echo_mod); return cOCT6100_ERR_OK; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int load_echo(struct astribank *astribank, char *filename, int default_is_alaw, const char *span_spec) { int ret; UINT32 octasic_status; struct span_specs *span_specs; span_specs = parse_span_specifications(span_spec, default_is_alaw); if (!span_specs) { AB_ERR(astribank, "ECHO parsing span specs failed\n"); return -EFAULT; } AB_INFO(astribank, "Loading ECHOCAN Firmware: %s (default %s)\n", filename, (default_is_alaw) ? "alaw" : "ulaw"); usb_buffer_init(astribank, &usb_buffer); octasic_status = init_octasic(filename, astribank, span_specs); free_span_specifications(span_specs); if (octasic_status != cOCT6100_ERR_OK) { AB_ERR(astribank, "ECHO %s burning failed (%08X)\n", filename, octasic_status); return -ENODEV; } ret = usb_buffer_flush(astribank, &usb_buffer); if (ret < 0) { AB_ERR(astribank, "ECHO %s buffer flush failed (%d)\n", filename, ret); return -ENODEV; } usb_buffer_showstatistics(astribank, &usb_buffer); return 0; } int echo_ver(struct astribank *astribank) { usb_buffer_init(astribank, &usb_buffer); return get_ver(astribank); } dahdi-tools-3.0.0/xpp/astribank.h0000644000000000000000000000211513373276276015374 0ustar rootroot#ifndef ASTRIBANK_H #define ASTRIBANK_H #include struct astribank *astribank_new(const char *path); void astribank_destroy(struct astribank *ab); void show_astribank_info(const struct astribank *ab); struct xusb_iface *astribank_xpp_open(struct astribank *ab); struct mpp_device *astribank_mpp_open(struct astribank *ab); struct xusb_device *xusb_dev_of_astribank(const struct astribank *ab); const char *astribank_devpath(const struct astribank *ab); const char *astribank_serial(const struct astribank *ab); int astribank_send(struct astribank *ab, int interface_num, const char *buf, int len, int timeout); int astribank_recv(struct astribank *ab, int interface_num, char *buf, size_t len, int timeout); #define AB_REPORT(report_type, astribank, fmt, ...) \ report_type("%s [%s]: " fmt, \ astribank_devpath(astribank), \ astribank_serial(astribank), \ ## __VA_ARGS__) #define AB_INFO(astribank, fmt, ...) \ AB_REPORT(INFO, astribank, fmt, ## __VA_ARGS__) #define AB_ERR(astribank, fmt, ...) \ AB_REPORT(ERR, astribank, fmt, ## __VA_ARGS__) #endif /* ASTRIBANK_H */ dahdi-tools-3.0.0/xpp/mpptalk.h0000644000000000000000000001115313373276276015070 0ustar rootroot#ifndef MPPTALK_H #define MPPTALK_H /* * Written by Oron Peled * Copyright (C) 2008, 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * MPPTALK - Example XTALK dialect */ #include #include #ifdef __GNUC__ #define PACKED __attribute__((packed)) #else #define PACKED #endif /*---------------- Common types --------------------*/ /* * The eeprom_table is common to all eeprom types. */ #define LABEL_SIZE 8 struct eeprom_table { uint8_t source; /* C0 - small eeprom, C2 - large eeprom */ uint16_t vendor; uint16_t product; uint16_t release; /* BCD encoded release */ uint8_t config_byte; /* Must be 0 */ uint8_t label[LABEL_SIZE]; } PACKED; #define VERSION_LEN 6 struct firmware_versions { char usb[VERSION_LEN]; char fpga[VERSION_LEN]; char eeprom[VERSION_LEN]; } PACKED; struct capabilities { uint8_t ports_fxs; uint8_t ports_fxo; uint8_t ports_bri; uint8_t ports_pri; uint8_t extra_features; /* BIT(0) - TwinStar */ uint8_t ports_echo; uint8_t reserved[2]; uint32_t timestamp; } PACKED; #define CAP_EXTRA_TWINSTAR(c) ((c)->extra_features & 0x01) #define CAP_EXTRA_TWINSTAR_SET(c) do {(c)->extra_features |= 0x01;} while (0) #define CAP_EXTRA_TWINSTAR_CLR(c) do {(c)->extra_features &= ~0x01;} while (0) #define KEYSIZE 16 struct capkey { uint8_t k[KEYSIZE]; } PACKED; #define EXTRAINFO_SIZE 24 struct extrainfo { char text[EXTRAINFO_SIZE]; } PACKED; struct mpp_header { uint16_t len; uint16_t seq; uint8_t op; /* MSB: 0 - to device, 1 - from device */ } PACKED; enum mpp_ser_op { SER_CARD_INFO_GET = 0x1, SER_STAT_GET = 0x3, /* Status bits */ #define SER_STAT_WATCHDOG_READY(s) ((s) & 0x01) #define SER_STAT_XPD_ALIVE(s) ((s) & 0x02) }; /* EEPROM_QUERY: i2cs(ID1, ID0) */ enum eeprom_type { EEPROM_TYPE_NONE = 0, EEPROM_TYPE_SMALL = 1, EEPROM_TYPE_LARGE = 2, EEPROM_TYPE_UNUSED = 3, }; enum dev_dest { DEST_NONE = 0x00, DEST_FPGA = 0x01, DEST_EEPROM = 0x02, }; /*---------------- PROTOCOL ------------------------*/ /* API */ struct mpp_device; struct mpp_device *mpp_new(struct xusb_iface *iface); void mpp_delete(struct mpp_device *dev); struct xusb_iface *xubs_iface_of_mpp(struct mpp_device *mpp); int mpp_status_query(struct mpp_device *mpp_dev); enum eeprom_type mpp_eeprom_type(struct mpp_device *mpp_dev); void show_eeprom(const struct eeprom_table *eprm, FILE *fp); void show_capabilities(const struct capabilities *capabilities, FILE *fp); void show_astribank_status(struct mpp_device *mpp_dev, FILE *fp); void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp); int twinstar_show(struct mpp_device *mpp, FILE *fp); int show_hardware(struct mpp_device *mpp_dev); int mpp_renumerate(struct mpp_device *mpp_dev); int mpp_send_start(struct mpp_device *mpp_dev, int dest, const char *ihex_version); int mpp_send_end(struct mpp_device *mpp_dev); int mpp_send_seg(struct mpp_device *mpp_dev, const uint8_t *data, uint16_t offset, uint16_t len); int mpp_reset(struct mpp_device *mpp_dev, int full_reset); int mpp_caps_get(struct mpp_device *mpp_dev, struct eeprom_table *eeprom_table, struct capabilities *capabilities, struct capkey *key); int mpp_caps_set(struct mpp_device *mpp_dev, const struct eeprom_table *eeprom_table, const struct capabilities *capabilities, const struct capkey *key); /* * serial sub-protocol to FPGA */ int mpps_card_info(struct mpp_device *mpp, int unit, uint8_t *card_type, uint8_t *card_status); int mpps_stat(struct mpp_device *mpp, int unit, uint8_t *maincard_version, uint8_t *status); /* * Twinstar */ int mpp_tws_watchdog(struct mpp_device *mpp); int mpp_tws_setwatchdog(struct mpp_device *mpp, int yes); int mpp_tws_powerstate(struct mpp_device *mpp); int mpp_tws_portnum(struct mpp_device *mpp); int mpp_tws_setportnum(struct mpp_device *mpp, uint8_t portnum); const char *dev_dest2str(int dest); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* MPPTALK_H */ dahdi-tools-3.0.0/xpp/xpp_blink0000755000000000000000000001014313373276276015161 0ustar rootroot#! /usr/bin/perl -w # # Written by Oron Peled # Copyright (C) 2007, Xorcom # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # # $Id$ # use strict; use File::Basename; BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); } use Dahdi; use Dahdi::Span; use Dahdi::Xpp; use Dahdi::Xpp::Xbus; sub usage { die "Usage: $0 {on|off|bzzt} {span | chan | xpd [] | label