xpp: support loading Octasic EC firmware

Echo Cancellation firmware is loaded by xpp/stribank_hexload
(Using the oct612x code).

* astribank_hexload: options -O/-o/-A for handling the Octasic echo
  cancellation firmware.
* astribank_tool: report that.
* xpp_fxloader: Run astribank_hexload, if needed.
* dahdi_perl: The EC module is an extra XPD, but not a "telephony device"
  and hence not a span. Deal with that.
* waitfor_xpds: may need to wait a bit longer for firmware loading.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>


git-svn-id: http://svn.astersk.org/svn/dahdi/tools/trunk@10032 17933a7a-c749-41c5-a318-cba88f637d49
This commit is contained in:
Tzafrir Cohen 2011-07-10 16:25:18 +00:00
parent d3cadf5352
commit ccd13cfd47
12 changed files with 1000 additions and 17 deletions

View File

@ -37,8 +37,23 @@ PERL_MODS := $(shell cd perl_modules; echo $(PERL_MODS_PAT))
# FIXME: Are those values really sane?
HOSTCC ?= $(CC)
USE_OCTASIC := yes
OCTASIC_DIR := oct612x
CFLAGS += -g -Wall $(USB_INCLUDE)
ifneq (no,$(USE_OCTASIC))
OCT_OBJS = $(shell $(OCTASIC_DIR)/octasic-helper objects $(OCTASIC_DIR))
OCT_SRCS = $(shell echo $(OCT_OBJS) | tr -s ' ' '\n' | sed 's/\.o$$/.c/g')
OCT_HERE_OBJS = $(shell echo $(OCT_OBJS) | tr -s ' ' '\n' | sed 's,^.*/,,')
OCT_CFLAGS = $(shell $(OCTASIC_DIR)/octasic-helper cflags $(OCTASIC_DIR))
OCT_DEFINES = \
-DPTR_TYPE=uint32_t \
-DcOCT6100_INTERNAL_SUPER_ARRAY_SIZE=1024 \
-DcOCT6100_MAX_ECHO_CHANNELS=672 \
-DcOCT6100_MAX_MIXER_EVENTS=1344
ECHO_LOADER = echo_loader.o
endif
%.8: %
pod2man --section 8 $^ > $@ || $(RM) $@
@ -57,7 +72,7 @@ PERL_MANS = $(PERL_SCRIPTS:%=%.8)
XTALK_OBJS = xtalk/xtalk.o xtalk/xusb.o xtalk/xlist.o xtalk/debug.o
ASTRIBANK_OBJS = astribank_usb.o mpptalk.o $(XTALK_OBJS)
ABHEXLOAD_OBJS = astribank_hexload.o hexfile.o pic_loader.o $(ASTRIBANK_OBJS) $(OCT_OBJS)
ABHEXLOAD_OBJS = astribank_hexload.o hexfile.o pic_loader.o $(ECHO_LOADER) $(ASTRIBANK_OBJS) $(OCT_HERE_OBJS)
ABTOOL_OBJS = astribank_tool.o $(ASTRIBANK_OBJS)
ABALLOW_OBJS = astribank_allow.o $(ASTRIBANK_OBJS)
@ -112,6 +127,7 @@ fpga_load: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
astribank_hexload: $(ABHEXLOAD_OBJS)
astribank_hexload: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
astribank_hexload: CFLAGS+=$(OCT_CFLAGS)
astribank_tool: $(ABTOOL_OBJS)
astribank_tool: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
@ -124,9 +140,26 @@ astribank_is_starting: LIBS+=$(EXTRA_LIBS)
fpga_load.o: CFLAGS+=-D_GNU_SOURCE # We use memrchr()
hex2iic: hex2iic.o iic.o hexfile.o
test_parse: test_parse.o hexfile.o
test_parse: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
ifneq (no,$(USE_OCTASIC))
.octasic.depend: $(OCTASIC_DIR)/octasic-helper Makefile ../config.status
$(CC) -MM $(OCT_CFLAGS) \
`$(OCTASIC_DIR)/octasic-helper objects | \
tr -s ' ' '\n' | \
sed -e 's,.*,$(OCTASIC_DIR)/&,' -e 's/\.o$$/.c/'` > $@
-include .octasic.depend
$(OCT_HERE_OBJS): Makefile
$(CC) -c $(CFLAGS) $(OCT_CFLAGS) $(OCT_DEFINES) $(OCT_SRCS)
endif
%: %.o
$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
@ -135,7 +168,7 @@ test_parse: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
touch $@
clean:
$(RM) .depend *.o xtalk/*.o $(TARGETS)
$(RM) .depend .octasic.depend *.o xtalk/*.o $(OCT_HERE_OBJS) $(TARGETS)
.PHONY: depend
depend: .depend

View File

@ -955,6 +955,9 @@ following command in order to load the FPGA firmware manually:
# pick the right name according to the device ID. FPGA_1161.hex is for
# 116x Astribanks:
astribank_hexload -D /dev/bus/usb/MMM/NNN -F /usr/share/dahdi/FPGA_1161.hex
# If the device has an echo canceller unit (If the unit is BRI/E1, you
# need to add an extra -A to the command-line after the -O)
#astribank_hexload -D /dev/bus/usb/MMM/NNN -O /usr/share/dahdi/OCT6104E-256D.ima
# Note the shell expantion in this line:
astribank_hexload -D /dev/bus/usb/MMM/NNN -p /usr/share/dahdi/PIC_TYPE_[1-4].hex
# reenumerate (disconnect and reconnect)
@ -1072,6 +1075,9 @@ xpd_bri::
BRI ("ISDN") modules. Module type 3.
xpd_pri::
The module for controlling E1/T1 modules. Module type 4.
xpd_echo::
The module for controlling hardware echo canceller modules. Module type 5.
Does not generate a span.
xpp_usb::
The functionality needed to connect to the USB bus.

View File

@ -106,6 +106,7 @@ static int write_to_file(struct eeprom_table *eeprom_table, struct capabilities
fprintf(f, "Capabilities.Port.FXO: %d\n", caps->ports_fxo);
fprintf(f, "Capabilities.Port.BRI: %d\n", caps->ports_bri);
fprintf(f, "Capabilities.Port.PRI: %d\n", caps->ports_pri);
fprintf(f, "Capabilities.Port.ECHO: %d\n", caps->ports_echo);
fprintf(f, "Capabilities.Twinstar: %d\n", CAP_EXTRA_TWINSTAR(caps));
fprintf(f, "Data:\n");
bin_to_file(eeprom_table, sizeof(*eeprom_table), f);

View File

@ -1,11 +1,19 @@
.TH "ASTRIBANK_HEXLOAD" "8" "29 March 2009" "" ""
.TH "ASTRIBANK_HEXLOAD" "8" "30 May 2011" "" ""
.SH NAME
astribank_tool \- Xorcom Astribank (xpp) firmware loader
.SH SYNOPSIS
.B astribank_tool \-D \fIdevice-path\fR <\fB\-F|\-p\fR> [\fIoptions\fR] \fIhexfile\fR
.B astribank_tool \-D \fIdevice-path\fR \-F [\fIoptions\fR] \fIhexfile\fR
.B astribank_tool [\-h]
.B astribank_tool \-D \fIdevice-path\fR \-p [\fIoptions\fR] \fIhexfile1 .. hexfile4\fR
.B astribank_tool \-D \fIdevice-path\fR \-O [-A] [\fIoptions\fR] \fIimagefile\fR
.B astribank_tool \-D \fIdevice-path\fR \-o [\fIoptions\fR]
.B astribank_tool \-D \fIdevice-path\fR \-E [\fIoptions\fR] \fIhexfile\fR
.B astribank_tool \-h
.SH DESCRIPTION
.B astribank_hexload
@ -28,6 +36,8 @@ 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.
@ -35,9 +45,29 @@ The firmware to load is a FPGA firmware.
.B \-p
.RS
The firmware to load is a PIC firmware.
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.
@ -53,6 +83,14 @@ Set debug mask to \fImask\fR. Default is 0, 0xFF is "everything".
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
.SH SEE ALSO
fxload(8), lsusb(8), astribank_tool(8), fpga_load(8)

View File

@ -31,7 +31,9 @@
#include "hexfile.h"
#include "mpptalk.h"
#include "pic_loader.h"
#include "echo_loader.h"
#include "astribank_usb.h"
#include "../autoconfig.h"
#define DBG_MASK 0x80
#define MAX_HEX_LINES 10000
@ -43,9 +45,14 @@ static void usage()
fprintf(stderr, "Usage: %s [options...] -D {/proc/bus/usb|/dev/bus/usb}/<bus>/<dev> hexfile...\n", progname);
fprintf(stderr, "\tOptions: {-F|-p}\n");
fprintf(stderr, "\t\t[-E] # Burn to EEPROM\n");
#if HAVE_OCTASIC
fprintf(stderr, "\t\t[-O] # Load Octasic firmware\n");
fprintf(stderr, "\t\t[-o] # Show Octasic version\n");
#endif
fprintf(stderr, "\t\t[-F] # Load FPGA firmware\n");
fprintf(stderr, "\t\t[-p] # Load PIC firmware\n");
fprintf(stderr, "\t\t[-v] # Increase verbosity\n");
fprintf(stderr, "\t\t[-A] # Set A-Law for 1st module\n");
fprintf(stderr, "\t\t[-d mask] # Debug mask (0xFF for everything)\n");
exit(1);
}
@ -146,9 +153,15 @@ int main(int argc, char *argv[])
{
char *devpath = NULL;
int opt_pic = 0;
int opt_echo = 0;
int opt_ecver = 0;
#if HAVE_OCTASIC
int opt_alaw = 0;
#endif
int opt_dest = 0;
int opt_sum = 0;
enum dev_dest dest = DEST_NONE;
const char options[] = "vd:D:EFp";
const char options[] = "vd:D:EFOopA";
int iface_num;
int ret;
@ -169,7 +182,7 @@ int main(int argc, char *argv[])
ERR("The -F and -E options are mutually exclusive.\n");
usage();
}
opt_dest = 1;
opt_dest++;
dest = DEST_EEPROM;
break;
case 'F':
@ -177,9 +190,20 @@ int main(int argc, char *argv[])
ERR("The -F and -E options are mutually exclusive.\n");
usage();
}
opt_dest = 1;
opt_dest++;
dest = DEST_FPGA;
break;
#if HAVE_OCTASIC
case 'O':
opt_echo = 1;
break;
case 'o':
opt_ecver = 1;
break;
case 'A':
opt_alaw = 1;
break;
#endif
case 'p':
opt_pic = 1;
break;
@ -195,12 +219,17 @@ int main(int argc, char *argv[])
usage();
}
}
if((opt_dest ^ opt_pic) == 0) {
ERR("The -F, -E and -p options are mutually exclusive.\n");
opt_sum = opt_dest + opt_pic + opt_echo;
if(opt_sum > 1 || (opt_sum == 0 && opt_ecver == 0)) {
ERR("The -F, -E"
#if HAVE_OCTASIC
", -O"
#endif
" and -p options are mutually exclusive, if neither is used then -o should present\n");
usage();
}
iface_num = (opt_dest) ? 1 : 0;
if(!opt_pic) {
if(!opt_pic && !opt_ecver) {
if(optind != argc - 1) {
ERR("Got %d hexfile names (Need exactly one hexfile)\n",
argc - 1 - optind);
@ -227,7 +256,7 @@ int main(int argc, char *argv[])
return 1;
}
astribank_close(astribank, 0);
} else if(opt_pic) {
} else if(opt_pic || opt_echo || opt_ecver) {
/*
* XPP Interface
*/
@ -237,11 +266,28 @@ int main(int argc, char *argv[])
ERR("%s: Opening astribank failed\n", devpath);
return 1;
}
//show_astribank_info(astribank);
#if HAVE_OCTASIC
if (opt_ecver) {
if((ret = echo_ver(astribank)) < 0) {
ERR("%s: Get Octasic version failed (Is Echo canceller card connected?)\n", devpath);
return 1;
} else
INFO("Octasic version: 0x%0X\n", ret);
}
#endif
if (opt_pic) {
if ((ret = load_pic(astribank, argc - optind, argv + optind)) < 0) {
ERR("%s: Loading PIC's failed\n", devpath);
return 1;
}
#if HAVE_OCTASIC
} else if (opt_echo) {
if((ret = load_echo(astribank, argv[optind], opt_alaw)) < 0) {
ERR("%s: Loading ECHO's failed\n", devpath);
return 1;
}
#endif
}
astribank_close(astribank, 0);
}

View File

@ -95,7 +95,7 @@ static int show_hardware(struct astribank_device *astribank)
if(astribank->eeprom_type == EEPROM_TYPE_LARGE) {
show_capabilities(&capabilities, stdout);
if(STATUS_FPGA_LOADED(astribank->status)) {
for(unit = 0; unit < 4; unit++) {
for(unit = 0; unit < 5; unit++) {
ret = mpps_card_info(astribank, unit, &card_type, &card_status);
if(ret < 0)
return ret;

View File

@ -15,6 +15,7 @@ use Dahdi;
use Dahdi::Span;
use Dahdi::Xpp;
use Dahdi::Xpp::Xbus;
use Dahdi::Xpp::Xpd;
use Getopt::Std;
sub usage {
@ -64,7 +65,7 @@ foreach my $xbus (Dahdi::Xpp::xbuses($sorter)) {
myprintf "%-10s\t%3s-%s\t%s\n",
$xbus->name, $xbus->xpporder, $xbus->label, $xbus->connector;
next unless $xbus->status eq 'CONNECTED';
foreach my $xpd ($xbus->xpds()) {
foreach my $xpd (Dahdi::Xpp::Xpd::telephony_devs($xbus->xpds())) {
my $prev = $xpd->dahdi_registration($on);
if(!defined($prev)) { # Failure
printf "%s: Failed %s\n", $xpd->fqn, $!;

784
xpp/echo_loader.c Normal file
View File

@ -0,0 +1,784 @@
/*
* Written by Oron Peled <oron@actcom.co.il>
* 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 <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <regex.h>
#include <sys/time.h>
#include "echo_loader.h"
#include "debug.h"
#include <oct6100api/oct6100_api.h>
#define DBG_MASK 0x03
#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_device *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_device *astribank, struct usb_buffer *ub)
{
ub->max_len = xusb_packet_size(astribank->xusb);
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_device *astribank, struct usb_buffer *ub)
{
long usec;
usec = usb_buffer_usec(ub);
INFO("%s [%s]: Octasic statistics: packet_size=[%d, %ld, %d] packets=%d, bytes=%ld msec=%ld usec/packet=%d\n",
xusb_devpath(astribank->xusb),
xusb_serial(astribank->xusb),
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_device *astribank, struct usb_buffer *ub)
{
int ret;
long t;
long sec;
static int last_sec;
if (ub->curr == 0)
return 0;
ret = xusb_send(astribank->xusb, ub->data, ub->curr, TIMEOUT);
if(ret < 0) {
ERR("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_device *astribank, struct usb_buffer *ub,
char *buf, int len)
{
if (ub->curr + len >= ub->max_len) {
ERR("%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_device *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 = xusb_recv(astribank->xusb, buf, PACKET_SIZE, TIMEOUT);
if(ret <= 0) {
ERR("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) {
ERR("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_device *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;
assert(astribank != NULL);
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 = 0x30 | (recv_answer ? 0x40: 0x00) | (ver ? 0x01: 0x00);
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) {
ERR("usb_buffer_send failed: %d\n", ret);
return ret;
}
DBG("%s: Written %d bytes\n", __func__, ret);
return ret;
}
int test_send(struct astribank_device *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) {
ERR("usb_buffer_send failed: %d\n", ret);
return ret;
}
DBG("%s: Written %d bytes\n", __func__, ret);
return ret;
}
void echo_send_data(struct astribank_device *astribank, const unsigned int addr, const unsigned int data)
{
/* 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");
spi_send(astribank, 0x0008, (addr >> 20) , 0, 0);
spi_send(astribank, 0x000A, (addr >> 4) & ((1 << 16) - 1) , 0, 0);
spi_send(astribank, 0x0004, data , 0, 0);
spi_send(astribank, 0x0000, (((addr >> 1) & 0x7) << 9) |
(1 << 8) | (3 << 12) | 1 , 0, 0);
}
unsigned int echo_recv_data(struct astribank_device *astribank, const unsigned int addr)
{
unsigned int data = 0x00;
unsigned int ret;
DBG("RCV:\n");
spi_send(astribank, 0x0008, (addr >> 20) , 0, 0);
spi_send(astribank, 0x000A, (addr >> 4) & ((1 << 16) - 1) , 0, 0);
spi_send(astribank, 0x0000, (((addr >> 1) & 0x7) << 9) |
(1 << 8) | 1 , 0, 0);
ret = spi_send(astribank, 0x0004, data , 1, 0);
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\n");
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");
}
fread(pbyFileData, 1, *pLen, pFile);
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_device *astribank = echo_mod->astribank;
echo_send_data(astribank, addr, data);
return cOCT6100_ERR_OK;
}
UINT32 Oct6100UserDriverWriteSmearApi(tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams)
{
unsigned int addr;
unsigned int data;
unsigned int len = f_pSmearParams->ulWriteLength;
const struct echo_mod *echo_mod = (struct echo_mod *)f_pSmearParams->pProcessContext;
struct astribank_device *astribank = echo_mod->astribank;
unsigned int i;
for (i = 0; i < len; i++) {
addr = f_pSmearParams->ulWriteAddress + (i << 1);
data = f_pSmearParams->usWriteData;
echo_send_data(astribank, addr, data);
}
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_device *astribank = echo_mod->astribank;
unsigned int i;
for (i = 0; i < len; i++) {
addr = f_pBurstParams->ulWriteAddress + (i << 1);
data = f_pBurstParams->pusWriteData[i];
echo_send_data(astribank, addr, data);
}
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 echo_mod *)f_pReadParams->pProcessContext;
struct astribank_device *astribank = echo_mod->astribank;
*f_pReadParams->pusReadData = echo_recv_data(astribank, addr);
return cOCT6100_ERR_OK;
}
UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams)
{
unsigned int addr;
unsigned int len = f_pBurstParams->ulReadLength;
const struct echo_mod *echo_mod = (struct echo_mod *)f_pBurstParams->pProcessContext;
struct astribank_device *astribank = echo_mod->astribank;
unsigned int i;
for (i = 0;i < len; i++) {
addr = f_pBurstParams->ulReadAddress + (i << 1);
f_pBurstParams->pusReadData[i] = echo_recv_data(astribank, addr);
}
return cOCT6100_ERR_OK;
}
inline int get_ver(struct astribank_device *astribank)
{
return spi_send(astribank, 0, 0, 1, 1);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
UINT32 init_octasic(char *filename, struct astribank_device *astribank, int is_alaw)
{
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;
test_send(astribank);
cpld_ver = get_ver(astribank);
INFO("%s [%s]: Check EC_CPLD version: %d\n",
xusb_devpath(astribank->xusb),
xusb_serial(astribank->xusb),
cpld_ver);
if (cpld_ver < 0)
return cpld_ver;
else if (cpld_ver == EC_VER_TEST) {
INFO("+---------------------------------------------------------+\n");
INFO("| WARNING: TEST HARDWARE IS ON THE BOARD INSTEAD OF EC!!! |\n");
INFO("+---------------------------------------------------------+\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));
if (!(echo_mod = malloc(sizeof(struct echo_mod)))) {
ERR("cannot allocate memory for echo_mod\n");
return 1;
}
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) {
ERR("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 (pbyImageData == NULL || ulImageByteSize == 0){
ERR("Bad pbyImageData or ulImageByteSize\n");
return 1;
}
if ( ulResult != 0 ) {
ERR("Failed load_file %s (%08X)\n", filename, ulResult);
return ulResult;
}
/* 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)
{
ERR("Oct6100GetInstanceSize failed (%08X)\n", ulResult);
return ulResult;
}
pApiInstance = malloc(InstanceSize.ulApiInstanceSize);
echo_mod->pApiInstance = pApiInstance;
echo_mod->astribank = astribank;
if (!pApiInstance) {
ERR("Out of memory (can't allocate %d bytes)!\n", InstanceSize.ulApiInstanceSize);
return 1;
}
/* Perform actual open of chip */
ulResult = Oct6100ChipOpen(pApiInstance, &OpenChip);
if (ulResult != cOCT6100_ERR_OK) {
ERR("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;
pcmLaw = (is_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) {
ERR("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) {
ERR("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_device *astribank, char *filename, int is_alaw)
{
int iLen;
int ret;
unsigned char *pbyFileData = NULL;
const char *devstr;
devstr = xusb_devpath(astribank->xusb);
INFO("%s [%s]: Loading ECHOCAN Firmware: %s (%s)\n",
devstr, xusb_serial(astribank->xusb), filename,
(is_alaw) ? "alaw" : "ulaw");
usb_buffer_init(astribank, &usb_buffer);
ret = init_octasic(filename, astribank, is_alaw);
if (ret) {
ERR("ECHO %s burning failed (%08X)\n", filename, ret);
return -ENODEV;
}
ret = usb_buffer_flush(astribank, &usb_buffer);
if (ret < 0) {
ERR("ECHO %s buffer flush failed (%d)\n", filename, ret);
return -ENODEV;
}
usb_buffer_showstatistics(astribank, &usb_buffer);
return 0;
}
int echo_ver(struct astribank_device *astribank)
{
usb_buffer_init(astribank, &usb_buffer);
return get_ver(astribank);
}

32
xpp/echo_loader.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef ECHO_LOADER_H
#define ECHO_LOADER_H
/*
* Written by Oron Peled <oron@actcom.co.il>
* 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 <stdint.h>
#include "astribank_usb.h"
int spi_send(struct astribank_device *astribank, uint16_t addr, uint16_t data, int recv_answer, int ver);
int load_echo(struct astribank_device *astribank, char *filename, int is_alaw);
int echo_ver(struct astribank_device *astribank);
#endif /* ECHO_LOADER_H */

View File

@ -327,6 +327,14 @@ sub new($$$$$) {
# static xpd related helper functions
#------------------------------------
# Returns only the telephony XPD's from a list
# of one or more XPD's.
# I.e: Filters-out ECHO cancelers
sub telephony_devs {
my @devs = grep { $_->channels } @_;
return @devs;
}
sub format_rank($$) {
my ($rank, $prio) = @_;
my $width = 2;

View File

@ -56,7 +56,7 @@ fi
# Wait for driver and first device
echo -n 1>&2 "Astribanks detection "
tries=10
tries=40
while [ ! -e "/sys/bus/astribanks/devices/xbus-00" ]
do
if [ "$tries" -le 0 ]; then

View File

@ -67,9 +67,11 @@ USB_PREFIX=
FIRMWARE_DIR="${FIRMWARE_DIR:-/usr/share/dahdi}"
ASTRIBANK_HEXLOAD=${ASTRIBANK_HEXLOAD:-/usr/sbin/astribank_hexload}
ASTRIBANK_TOOL=${ASTRIBANK_TOOL:-/usr/sbin/astribank_tool}
XPP_CONFIG="${XPP_CONFIG:-/etc/dahdi/xpp.conf}"
XPP_UDEV_SLEEP_TIME="${XPP_UDEV_SLEEP_TIME:-15}"
USB_FW="${USB_FW:-USB_FW.hex}"
USB_RECOV="${USB_RECOV:-USB_RECOV.hex}"
if [ -r "$DEFAULTS" ]; then
. "$DEFAULTS"
@ -151,6 +153,38 @@ load_fw_device() {
debug "FPGA loading $fw into $dev"
run_astribank_hexload -D "$dev" -F "$FIRMWARE_DIR/$fw"
if [ "$fw" = "FPGA_1161.hex" ]; then
echo_file="$FIRMWARE_DIR/OCT6104E-256D.ima"
law=''
law_str='uLaw'
abtool_output=`$ASTRIBANK_TOOL -D "$dev" -Q 2>/dev/null`
card_type=`echo "$abtool_output" | grep '^CARD 4:' | cut -d= -f2 | cut -d. -f1`
if [ "$card_type" = '5' ]; then
debug "ECHO burning into $dev: $echo_file"
card_type_first=`echo "$abtool_output" | grep '^CARD 0:' | cut -d= -f2 | cut -d. -f1`
case "$card_type_first" in
3) law="-A";;
4)
pri_protocol=''
if [ -r "$XPP_CONFIG" ]; then
pri_protocol=`awk '/^pri_protocol/ {print $2}' $XPP_CONFIG`
fi
# "E1" or empty (implied E1) means aLaw
if [ "$pri_protocol" != 'T1' ]; then
law='-A'
fi
;;
esac
if [ "$law" = '-A' ]; then
law_str="aLaw"
fi
caps_num=`echo "$abtool_output" | grep 'ECHO ports' | sed -e 's/.*: *//'`
debug "ECHO: 1st module is $law_str, $caps_num channels allowed."
if [ "$caps_num" != '0' ]; then
run_astribank_hexload -D "$dev" -O $law "$echo_file"
else
$LOGGER "WARNING: ECHO burning was skipped (no capabilities)"
fi
fi
pic_files=`echo "$FIRMWARE_DIR"/PIC_TYPE_[1-4].hex`
debug "PIC burning into $dev: $pic_files"
run_astribank_hexload -D "$dev" -p $pic_files