diff -uNr zaptel-1.2.1.orig/zaptel.c zaptel-1.2.1/zaptel.c --- zaptel-1.2.1.orig/zaptel.c 2005-12-02 11:03:01.000000000 +1100 +++ zaptel-1.2.1/zaptel.c 2006-01-15 17:51:05.000000000 +1100 @@ -360,6 +360,8 @@ static struct zt_span *spans[ZT_MAX_SPANS]; static struct zt_chan *chans[ZT_MAX_CHANNELS]; +static struct zt_ec_data ec_data_preload[ZT_MAX_CHANNELS]; +static struct zt_ec_data ec_data_dump[ZT_MAX_CHANNELS]; static int maxspans = 0; static int maxchans = 0; @@ -3018,6 +3020,25 @@ #endif #endif /* ALLOW_CHAN_DIAG */ break; + case ZT_EC_PRELOAD: + if (copy_from_user(&j, (void *)data, sizeof(int))) + return -EFAULT; + if (copy_from_user(&ec_data_preload[j], (void *)data, sizeof(struct zt_ec_data))) + return -EFAULT; + return 0; + case ZT_EC_DUMP: + if (copy_from_user(&j, (void *)data, sizeof(int))) + return -EFAULT; + chan = chans[j]; + if (chan && chan->ec && chan->ec->a_i && chan->ec->a_s) { + memset(&ec_data_dump[j], 0, sizeof(struct zt_ec_data)); + ec_data_dump[j].N_d = chan->ec->N_d; + memcpy(ec_data_dump[j].a_i, chan->ec->a_i, chan->ec->N_d * sizeof(int)); + memcpy(ec_data_dump[j].a_s, chan->ec->a_s, chan->ec->N_d * sizeof(short)); + } + if (copy_to_user((void *)data, &ec_data_dump[j], sizeof(struct zt_ec_data))) + return -EFAULT; + return 0; default: return -ENOTTY; } @@ -4160,6 +4181,16 @@ ec = echo_can_create(j, 0); if (!ec) return -ENOMEM; + if (ec_data_preload[chan->channo].N_d == ec->N_d) + { + printk("Using preloaded ec data for channel %d\n", chan->channo); + memcpy(ec->a_i, ec_data_preload[chan->channo].a_i, ec->N_d*sizeof(int)); + memcpy(ec->a_s, ec_data_preload[chan->channo].a_s, ec->N_d*sizeof(short)); + } + else + { + printk("No preloaded ec data for channel %d\n", chan->channo); + } spin_lock_irqsave(&chan->lock, flags); chan->echocancel = j; chan->ec = ec; diff -uNr zaptel-1.2.1.orig/zaptel.h zaptel-1.2.1/zaptel.h --- zaptel-1.2.1.orig/zaptel.h 2005-11-30 05:42:08.000000000 +1100 +++ zaptel-1.2.1/zaptel.h 2006-01-15 17:40:02.000000000 +1100 @@ -298,6 +298,14 @@ int spanno; /* Span number (filled in by zaptel) */ } ZT_DYNAMIC_SPAN; +struct zt_ec_data +{ + int channo; /* only matters for ioctl */ + int N_d; + int a_i[256]; + short a_s[256]; +}; + /* Define the max # of outgoing DTMF or MFv1 digits to queue in-kernel */ #define ZT_MAX_DTMF_BUF 256 @@ -647,6 +655,9 @@ #define ZT_STARTUP _IOW (ZT_CODE, 99, int) #define ZT_SHUTDOWN _IOW (ZT_CODE, 100, int) +#define ZT_EC_DUMP _IOR (ZT_CODE, 101, struct zt_ec_data) +#define ZT_EC_PRELOAD _IOW (ZT_CODE, 102, struct zt_ec_data) + #define ZT_TONE_ZONE_MAX 128 #define ZT_TONE_ZONE_DEFAULT -1 /* To restore default */ diff -uNr zaptel-1.2.1.orig/zt_ec_dump.c zaptel-1.2.1/zt_ec_dump.c --- zaptel-1.2.1.orig/zt_ec_dump.c 1970-01-01 10:00:00.000000000 +1000 +++ zaptel-1.2.1/zt_ec_dump.c 2006-01-15 17:40:02.000000000 +1100 @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifdef STANDALONE_ZAPATA +#include "zaptel.h" +#else +#include +#endif + +enum {OUTPUT_TYPE_HUMAN, OUTPUT_TYPE_GRAPH, OUTPUT_TYPE_TAB, OUTPUT_TYPE_CSV, OUTPUT_TYPE_RAW}; + +void usage() { + fprintf(stderr, "Usage: zt_ec_dump [-c] [-t] -d \n"); + fprintf(stderr, " -c csv output\n"); + fprintf(stderr, " -t tab delimited output\n"); + fprintf(stderr, " -g graph output\n"); + fprintf(stderr, " -r raw output (for reading by zt_ec_preload)\n"); + fprintf(stderr, " -d CHAN work with channel CHAN\n"); +} + +#define GRAPH_X 80 +#define GRAPH_Y 24 + +int main(int argc, char *argv[]) +{ + int fd; + struct zt_ec_data data; + int count; + int ret; + int min, max; + int x, y; + int output_type = OUTPUT_TYPE_HUMAN; + int channo = -1; + char graph[GRAPH_Y][GRAPH_X + 1]; + int zero = 0; + + + while((ret = getopt(argc, argv, "ctgrd:")) != -1) { + switch(ret) { + case '?': + usage(); + return 1; + case 'c': + output_type = OUTPUT_TYPE_CSV; + break; + case 't': + output_type = OUTPUT_TYPE_TAB; + break; + case 'g': + output_type = OUTPUT_TYPE_GRAPH; + break; + case 'r': + output_type = OUTPUT_TYPE_RAW; + break; + case 'd': + channo = atoi(optarg); + break; + } + } + if (channo < 0) { + usage(); + return 1; + } + data.channo = channo; + fd = open("/dev/zap/ctl", O_RDWR); + if (fd < 0) { + perror("open(/dev/zap/ctl"); + exit(1); + } + if (ioctl(fd, ZT_EC_DUMP, &data)) { + perror("ioctl(ZT_EC_DUMP)"); + exit(1); + } + close(fd); + if (output_type != OUTPUT_TYPE_RAW) { + printf("channel %d: %d taps\n", channo, data.N_d); + } + min = MAXINT; + max = MININT; + if (output_type == OUTPUT_TYPE_GRAPH) { + for (y = 0; y < GRAPH_Y; y++) { + memset(graph[y], 32, GRAPH_X); + graph[y][GRAPH_X] = 0; + } + for (count = 0; count < data.N_d; count++) { + if (data.a_s[count] > max) + max = data.a_s[count]; + if (data.a_s[count] < min) + min = data.a_s[count]; + } + zero = GRAPH_Y * (0 - min) / (max - min); + } + for (count = 0; count < data.N_d; count++) { + switch(output_type) { + case OUTPUT_TYPE_TAB: + printf("%d\t%d\n", data.a_i[count], data.a_s[count]); + break; + case OUTPUT_TYPE_CSV: + printf("%d,%d\n", data.a_i[count], data.a_s[count]); + break; + case OUTPUT_TYPE_GRAPH: + x = GRAPH_X * count / data.N_d; + y = GRAPH_Y * (data.a_s[count] - min) / (max - min); + if (y >= zero) { + while (y >= zero) { + graph[y][x] = '*'; + y--; + } + } else { + while (y <= zero) { + graph[y][x] = '*'; + y++; + } + } + break; + case OUTPUT_TYPE_RAW: + if (count > 0) + putchar(' '); + printf("%d %d", data.a_i[count], data.a_s[count]); + break; + default: + printf("%3d: %10d %6d\n", count, data.a_i[count], data.a_s[count]); + } + } + if (output_type == OUTPUT_TYPE_GRAPH) { + for (y = GRAPH_Y - 1; y >= 0; y--) + puts(graph[y]); + } + exit(0); +} diff -uNr zaptel-1.2.1.orig/zt_ec_preload.c zaptel-1.2.1/zt_ec_preload.c --- zaptel-1.2.1.orig/zt_ec_preload.c 1970-01-01 10:00:00.000000000 +1000 +++ zaptel-1.2.1/zt_ec_preload.c 2006-01-15 17:40:02.000000000 +1100 @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifdef STANDALONE_ZAPATA +#include "zaptel.h" +#else +#include +#endif + +void usage() { + fprintf(stderr, "Usage: zt_ec_preload -d \n"); + fprintf(stderr, " -d CHAN work with channel CHAN\n"); +} + +int main(int argc, char *argv[]) +{ + int fd; + struct zt_ec_data data; + int count; + int ret; + int channo = -1; + + while((ret = getopt(argc, argv, "d:")) != -1) { + switch(ret) { + case '?': + usage(); + return 1; + case 'd': + channo = atoi(optarg); + break; + } + } + if (channo < 0) { + usage(); + return 1; + } + data.channo = channo; + fd = open("/dev/zap/ctl", O_RDWR); + if (fd < 0) { + perror("open(/dev/zap/ctl"); + exit(1); + } + //printf("%d\n", scanf("%d %hd", &data.a_i[0], &data.a_s[0])); + for (count = 0, data.N_d = 0; count < 256 && scanf("%d %hd", &data.a_i[count], &data.a_s[count]) == 2; count++) + data.N_d++; + if (data.N_d == 0) { + printf("No data read\n"); + return 1; + } + if (ioctl(fd, ZT_EC_PRELOAD, &data)) { + perror("ioctl(ZT_EC_PRELOAD)"); + exit(1); + } + close(fd); + printf("%d values loaded\n", data.N_d); + exit(0); +}