wanpipe/patches/kdrivers/wanec/wanec_cmd.c

2719 lines
79 KiB
C

/*************************************************************
* wanec_cmd.c WANPIPE Echo Canceller Layer (WANEC_LIP)
*
*
*
* ===========================================================
*
* May 10 2006 Alex Feldman Initial Version
*
* March 19, 2006 Alex Feldman Enable Sout Adaptive Noise
* Reduction for all channel by
* default.
*
* January 9, 2008 David Rokhvarg
* Added support for Sangoma MS Windows Driver
*
*/
/*=============================================================
* Includes
*/
#include "wanpipe_includes.h"
#include "wanpipe_defines.h"
#include "wanpipe_debug.h"
#include "wanpipe.h"
#if defined(__LINUX__)
# include "if_wanpipe.h"
#endif
int verbose;
#include "oct6100_api.h"
#include "oct6100_version.h"
#include "wanec_iface.h"
#include "wanec_tones.h"
/*=============================================================
* Definitions
*/
#define WANEC_MAX_PORT_RANGE 32
#define WANEC_MAX_BRI_PORT_RANGE 2
#define WANEC_READ_LIMIT 0x10000
#define WANEC_MAX_CONFBRIDGE_DEF 32
#define WANEC_MAC_PLAYOUT_BUFFERS 32
#define WANEC_MAX_TONEEVENTS 8
#define WANEC_MAX_PLAYOUTEVENTS 8
/*=============================================================
* Global Parameters
*/
UINT32 WanEcToneListDTMF[] =
{
SOUT_DTMF_0,
SOUT_DTMF_1,
SOUT_DTMF_2,
SOUT_DTMF_3,
SOUT_DTMF_4,
SOUT_DTMF_5,
SOUT_DTMF_6,
SOUT_DTMF_7,
SOUT_DTMF_8,
SOUT_DTMF_9,
SOUT_DTMF_A,
SOUT_DTMF_B,
SOUT_DTMF_C,
SOUT_DTMF_D,
SOUT_DTMF_STAR,
SOUT_DTMF_POUND,
ROUT_DTMF_0,
ROUT_DTMF_1,
ROUT_DTMF_2,
ROUT_DTMF_3,
ROUT_DTMF_4,
ROUT_DTMF_5,
ROUT_DTMF_6,
ROUT_DTMF_7,
ROUT_DTMF_8,
ROUT_DTMF_9,
ROUT_DTMF_A,
ROUT_DTMF_B,
ROUT_DTMF_C,
ROUT_DTMF_D,
ROUT_DTMF_STAR,
ROUT_DTMF_POUND
};
UINT32 WanEcToneListFaxCalling[] =
{
SOUT_G168_1100GB_ON,
ROUT_G168_1100GB_ON
};
UINT32 WanEcToneListFaxCalled[] =
{
SOUT_G168_2100GB_ON,
ROUT_G168_2100GB_ON,
SOUT_G168_2100GB_WSPR,
ROUT_G168_2100GB_WSPR
};
/*=============================================================
* Function prototype
*/
int wanec_ChipOpenPrep(wan_ec_dev_t *ec_dev, char *devname, wanec_config_t *config, int verbose);
int wanec_ChipOpen(wan_ec_dev_t*, int);
int wanec_ChipClose(wan_ec_dev_t*, int verbose);
int wanec_ChipStats(wan_ec_dev_t *ec_dev, wanec_chip_stats_t *chip_stats, int reset, int verbose);
int wanec_ChipImage(wan_ec_dev_t *ec_dev, wanec_chip_image_t *chip_image, int verbose);
int wanec_ChannelOpen(wan_ec_dev_t*, INT, int);
int wanec_ChannelClose(wan_ec_dev_t*, INT, int);
int wanec_ChannelModifyOpmode(wan_ec_dev_t*, INT, UINT32, int verbose);
int wanec_ChannelModifyCustom(wan_ec_dev_t*, INT, wanec_chan_custom_t*, int verbose);
int wanec_ChannelStats(wan_ec_dev_t*, INT channel, wanec_chan_stats_t *chan_stats, int reset);
int wanec_ChannelMute(wan_ec_dev_t*, INT channel, wanec_chan_mute_t*, int);
int wanec_ChannelUnMute(wan_ec_dev_t*, INT channel, wanec_chan_mute_t*, int);
int wanec_DtmfRemoval(wan_ec_dev_t *ec_dev, INT channel, int enable, int verbose);
int wanec_TonesCtrl(wan_ec_t *ec, int cmd, int ec_chan, wanec_tone_config_t*, int verbose);
int wanec_DebugChannel(wan_ec_dev_t*, INT channel, int verbose);
int wanec_DebugGetData(wan_ec_dev_t*, wanec_chan_monitor_t *chan_monitor, int verbose);
int wanec_BufferLoad(wan_ec_dev_t *ec_dev, wanec_buffer_config_t *buffer_config, int verbose);
int wanec_BufferUnload(wan_ec_dev_t *ec_dev, wanec_buffer_config_t *buffer_config, int verbose);
int wanec_BufferPlayoutAdd(wan_ec_t *ec, int channel, wanec_playout_t *playout, int verbose);
int wanec_BufferPlayoutStart(wan_ec_t *ec, int channel, wanec_playout_t *playout, int verbose);
int wanec_BufferPlayoutStop(wan_ec_t *ec, int channel, wanec_playout_t *playout, int verbose);
int wanec_ConfBridgeOpen(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int verbose);
int wanec_ConfBridgeClose(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int verbose);
int wanec_ConfBridgeChanAdd(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, int verbose);
int wanec_ConfBridgeChanRemove(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, int verbose);
int wanec_ConfBridgeChanMute(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, int verbose);
int wanec_ConfBridgeChanUnMute(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, int verbose);
int wanec_ConfBridgeDominantSpeakerSet(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, int enable, int verbose);
int wanec_ConfBridgeMaskChange(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, UINT32 mask, int verbose);
int wanec_ConfBridgeGetStats(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int verbose);
int wanec_ToneEvent(wan_ec_t *ec, int verbose);
int wanec_PlayoutEvent(wan_ec_t *ec, int verbose);
int wanec_ISR(wan_ec_t *ec, int verbose);
int wanec_fe2ec_channel(wan_ec_dev_t*, int);
static int wanec_hndl2ec_channel(wan_ec_t *ec, UINT32 ChannelHndl);
static int wanec_ec2fe_channel(wan_ec_t*, int, wan_ec_dev_t**);
extern int wanec_ChipParam(wan_ec_t*,tPOCT6100_CHIP_OPEN, wan_custom_conf_t*, int);
extern int wanec_ChanParam(wan_ec_t*,tPOCT6100_CHANNEL_MODIFY, wan_custom_conf_t*, int);
extern int wanec_ChanParamList(wan_ec_t *ec);
u32 wanec_req_write(void*, u32 write_addr, u16 write_data);
u32 wanec_req_write_smear(void*, u32 addr, u16 data, u32 len);
u32 wanec_req_write_burst(void*, u32 addr, u16 *data, u32 len);
u32 wanec_req_read(void*, u32 addr, u16 *data);
u32 wanec_req_read_burst(void*, u32 addr, u16 *data, u32 len);
extern int wan_ec_write_internal_dword(wan_ec_dev_t *ec_dev, u32 addr1, u32 data);
extern int wan_ec_read_internal_dword(wan_ec_dev_t *ec_dev, u32 addr1, u32 *data);
static int wanec_ToneEnable(wan_ec_t *ec, int ec_chan, UINT32 tone_id, int verbose);
static int wanec_ToneDisable(wan_ec_t *ec, int ec_chan, UINT32 tone_id, int verbose);
/*=============================================================
* Function definition
*/
static int wanec_hndl2ec_channel(wan_ec_t *ec, UINT32 ChannelHndl)
{
int ec_chan = 0;
for(ec_chan = 0; ec_chan < MAX_EC_CHANS; ec_chan++) {
if (ec->pEchoChannelHndl[ec_chan] == ChannelHndl){
return ec_chan;
}
}
return 0;
}
int wanec_fe2ec_channel(wan_ec_dev_t *ec_dev, int fe_channel)
{
int ec_channel = 0;
/* WANEC_MAX_BRI_PORT_RANGE = 2 */
/* WANEC_MAX_PORT_RANGE = 32 */
/* For A500, fe_lineno 1-> 24 */
if (ec_dev->card->adptr_type == AFT_ADPTR_FLEXBRI) {
if (ec_dev->fe_lineno == 4){
//if (ec_dev->fe_media == WAN_MEDIA_FXOFXS){
ec_channel = WANEC_MAX_PORT_RANGE + (fe_channel-1);
} else {
ec_channel = (ec_dev->fe_lineno * WANEC_MAX_BRI_PORT_RANGE + (fe_channel-1));
}
} else {
if (ec_dev->fe_media == WAN_MEDIA_BRI){
if (ec_dev->fe_lineno >= 12){
ec_channel = WANEC_MAX_PORT_RANGE;
}
ec_channel += (ec_dev->fe_lineno * WANEC_MAX_BRI_PORT_RANGE + (fe_channel-1));
}else if (ec_dev->fe_media == WAN_MEDIA_T1 ||
ec_dev->fe_media == WAN_MEDIA_FXOFXS ||
ec_dev->card->adptr_type == AFT_ADPTR_B601) {
ec_channel = ec_dev->fe_lineno * WANEC_MAX_PORT_RANGE + (fe_channel-1);
} else {
/*ec_channel = ec_dev->fe_lineno * ec_dev->fe_max_chans + channel;*/
ec_channel = ec_dev->fe_lineno * WANEC_MAX_PORT_RANGE + fe_channel;
}
}
return ec_channel;
}
static int wanec_ec2fe_channel(wan_ec_t *ec, int ec_chan, wan_ec_dev_t **ec_dev)
{
wan_ec_dev_t *ec_dev_tmp;
int fe_chan;
ec_dev_tmp = ec->pEcDevMap[ec_chan];
if (ec_dev_tmp == NULL) return 0;
fe_chan = ec_chan % WANEC_MAX_PORT_RANGE;
if (ec_dev_tmp->fe_media == WAN_MEDIA_BRI){
fe_chan = fe_chan % WANEC_MAX_BRI_PORT_RANGE;
fe_chan++;
}else{
if (ec_dev_tmp->fe_media == WAN_MEDIA_T1 ||
ec_dev_tmp->fe_media == WAN_MEDIA_FXOFXS ||
ec_dev_tmp->card->adptr_type == AFT_ADPTR_B601){
fe_chan++;
}
}
if (ec_dev && *ec_dev) *ec_dev = ec_dev_tmp;
return fe_chan;
}
/******************************************************************
**
**
*******************************************************************/
int wanec_ChipStats(wan_ec_dev_t *ec_dev, wanec_chip_stats_t *chip_stats, int reset, int verbose)
{
wan_ec_t *ec;
tOCT6100_CHIP_STATS f_ChipStats;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
if (chip_stats){
PRINT2(verbose, "%s: Reading chip statistics...\n",
ec->name);
}
Oct6100ChipGetStatsDef( &f_ChipStats );
f_ChipStats.fResetChipStats = reset;
ulResult = Oct6100ChipGetStats(
ec->pChipInstance,
&f_ChipStats);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_EVENT(
"%s: Reading chip statistics...\tFailed (err=0x%X)\n",
ec->name, ulResult);
return -EINVAL;
}
if (chip_stats){
memcpy( &chip_stats->f_ChipStats,
&f_ChipStats,
sizeof(tOCT6100_CHIP_STATS));
}
return 0;
}
/******************************************************************
**
**
*******************************************************************/
tOCT6100_CHIP_IMAGE_INFO f_ChipImageInfo;
#if 0
tOCT6100_GET_HW_REVISION f_Revision;
#endif
int wanec_ChipImage(wan_ec_dev_t *ec_dev, wanec_chip_image_t *chip_image, int verbose)
{
wan_ec_t *ec;
UINT32 ulResult;
int err;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
if (chip_image){
PRINT2(verbose, "%s: Reading chip image info...\n",
ec->name);
}
Oct6100ChipGetImageInfoDef( &f_ChipImageInfo );
ulResult = Oct6100ChipGetImageInfo(
ec->pChipInstance,
&f_ChipImageInfo);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_EVENT(
"%s: Reading chip image info...\tFailed (err=0x%X)\n",
ec->name, ulResult);
return -EINVAL;
}
if (chip_image){
if (chip_image->f_ChipImageInfo){
/* If user initialized chip_image->f_ChipImageInfo pointer, then
* copy image information to chip_image->f_ChipImageInfo. */
err = WAN_COPY_TO_USER(
chip_image->f_ChipImageInfo,
&f_ChipImageInfo,
sizeof(tOCT6100_CHIP_IMAGE_INFO));
if (err){
DEBUG_EVENT(
"%s: Failed to copy chip image info to user space [%s:%d]!\n",
ec->name, __FUNCTION__,__LINE__);
return -EINVAL;
}
}else{
/* If user set chip_image->f_ChipImageInfo to NULL, then
* print image information to wanpipelog. */
DEBUG_EVENT(
"%s: Echo Canceller image description:\n%s\n",
ec->name, f_ChipImageInfo.szVersionNumber);
DEBUG_EVENT(
"%s: Echo Canceller image build ID\t\t\t%08X\n",
ec->name, f_ChipImageInfo.ulBuildId);
DEBUG_EVENT(
"%s: Echo Canceller maximum number of channels\t%d\n",
ec->name, f_ChipImageInfo.ulMaxChannels);
#if 0
PRINT2(verbose,
"%s: Echo Canceller maximum tail displacement\t\t%d\n",
ec->name, f_ChipImageInfo.ulMaxTailDisplacement);
PRINT2(verbose,
"%s: Echo Canceller per channel tail displacement\t%s\n",
ec->name,
(f_ChipImageInfo.fPerChannelTailDisplacement == TRUE)?"TRUE":"FALSE");
PRINT2(verbose,
"%s: Echo Canceller per channel tail length\t\t%s\n",
ec->name,
(f_ChipImageInfo.fPerChannelTailLength == TRUE)?"TRUE":"FALSE");
PRINT2(verbose,
"%s: Echo Canceller maximum tail length\t\t%d\n",
ec->name, f_ChipImageInfo.ulMaxTailLength);
PRINT2(verbose,
"%s: Echo Canceller buffer Playout support\t\t%s\n",
ec->name,
(f_ChipImageInfo.fBufferPlayout == TRUE)?"TRUE":"FALSE");
PRINT2(verbose,
"%s: Echo Canceller adaptive noise reduction\t\t%s\n",
ec->name,
(f_ChipImageInfo.fAdaptiveNoiseReduction==TRUE)?"TRUE":"FALSE");
PRINT2(verbose,
"%s: Echo Canceller SOUT noise bleaching\t\t%s\n",
ec->name,
(f_ChipImageInfo.fSoutNoiseBleaching==TRUE)?"TRUE":"FALSE");
PRINT2(verbose,
"%s: Echo Canceller ROUT noise reduction\t\t%s\n",
ec->name,
(f_ChipImageInfo.fRoutNoiseReduction==TRUE)?"TRUE":"FALSE");
PRINT2(verbose,
"%s: Echo Canceller ROUT noise reduction level\t\t%s\n",
ec->name,
(f_ChipImageInfo.fRoutNoiseReductionLevel==TRUE)?"TRUE":"FALSE");
PRINT2(verbose,
"%s: Echo Canceller automatic level control\t\t%s\n",
ec->name,
(f_ChipImageInfo.fAutoLevelControl==TRUE)?"TRUE":"FALSE");
PRINT2(verbose,
"%s: Echo Canceller acoustic echo cancellation\t\t%s\n",
ec->name,
(f_ChipImageInfo.fAcousticEcho==TRUE)?"TRUE":"FALSE");
PRINT2(verbose,
"%s: Echo Canceller conferencing\t\t%s\n",
ec->name,
(f_ChipImageInfo.fConferencing==TRUE)?"TRUE":"FALSE");
PRINT2(verbose,
"%s: Echo Canceller conferencing noise reduction\t\t%s\n",
ec->name,
(f_ChipImageInfo.fConferencingNoiseReduction==TRUE)?"TRUE":"FALSE");
#endif
}
}
if (f_ChipImageInfo.ulMaxChannels < (unsigned int)ec->max_ec_chans){
ec->max_ec_chans = f_ChipImageInfo.ulMaxChannels-1;
}
// DEBUG_EVENT(verbose, "%s: Reading hw revision...\n",
// ec->name);
#if 0
DEBUG_EVENT(verbose, "%s: Reading hw revision...\n",
ec->name);
ec->f_Revision.ulUserChipId = 0;
ec->f_Revision.pProcessContext = &ec->f_Context;
ulResult = Oct6100GetHwRevision(&ec->f_Revision);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_EVENT(
"%s: Reading hw revision...\tFailed (err=0x%X)\n",
ec->name, ulResult);
return EINVAL;
}
#endif
return 0;
}
int wanec_ChipOpenPrep(wan_ec_dev_t *ec_dev, char *devname, wanec_config_t *config, int verbose)
{
tOCT6100_GET_INSTANCE_SIZE InstanceSize;
wan_ec_t *ec;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
WAN_ASSERT(config->imageData == NULL);
ec = ec_dev->ec;
ulResult = Oct6100ChipOpenDef( &ec->f_OpenChip );
/*==============================================================*/
/* Configure clocks */
/* upclk oscillator is at 33.33 Mhz */
ec->f_OpenChip.ulUpclkFreq = cOCT6100_UPCLK_FREQ_33_33_MHZ;
/* mclk will be generated by internal PLL at 133 Mhz */
ec->f_OpenChip.fEnableMemClkOut = TRUE;
#if 1
ec->f_OpenChip.ulMemClkFreq = cOCT6100_MCLK_FREQ_133_MHZ;
#else
ec->f_OpenChip.ulMemClkFreq = cOCT6100_MCLK_FREQ_125_MHZ; /*125*/
#endif
/*==============================================================*/
/*==============================================================*/
/* General parameters */
/* Chip ID.*/
ec->f_OpenChip.ulUserChipId = ec->chip_no;
/* Set the max number of accesses to 1024 to speed things up */
ec->f_OpenChip.ulMaxRwAccesses = 1024;
/* Set the maximums that the chip needs to support for this test */
ec->f_OpenChip.ulMaxChannels = config->max_channels;
ec->f_OpenChip.ulMaxBiDirChannels = 0;
ec->f_OpenChip.ulMaxConfBridges = 0; //WANEC_MAX_CONFBRIDGE_DEF;
ec->f_OpenChip.ulMaxPhasingTssts = 0;
ec->f_OpenChip.ulMaxTdmStreams = 32;
ec->f_OpenChip.ulMaxTsiCncts = 2;
/*==============================================================*/
/*==============================================================*/
/* External Memory Settings */
/* Use DDR memory.*/
#if 1
ec->f_OpenChip.ulMemoryType = cOCT6100_MEM_TYPE_SDR;
#else
ec->f_OpenChip.ulMemoryType = cOCT6100_MEM_TYPE_DDR;
#endif
/*
**f_OpenChip.ulMemoryChipSize = cOCT6100_MEMORY_CHIP_SIZE_8MB;
**f_OpenChip.ulMemoryChipSize = cOCT6100_MEMORY_CHIP_SIZE_16MB;*/
ec->f_OpenChip.ulMemoryChipSize = config->memory_chip_size;
ec->f_OpenChip.ulNumMemoryChips = 2;
ec->f_OpenChip.ulSoftBufferPlayoutEventsBufSize = 2048;
ec->f_OpenChip.fEnableChannelRecording = TRUE;
#if defined(ENABLE_ACOUSTICECHO)
ec->f_OpenChip.fEnableAcousticEcho = TRUE;
#endif
#if defined(ENABLE_PRODBIST)
/* Enable production bist mode */
ec->f_OpenChip.fEnableProductionBist = TRUE;
ec->f_OpenChip.ulNumProductionBistLoops = 0x1;
#endif
ec->f_OpenChip.ulMaxPlayoutBuffers = WANEC_MAC_PLAYOUT_BUFFERS;
ec->f_OpenChip.pbyImageFile = ec->pImageData;
ec->f_OpenChip.ulImageSize = ec->ImageSize;
/* Assign board index (0). */
ec->f_Context.ulBoardId = ec->chip_no;
/* Handle to driver */
ec->f_Context.ec_dev = ec_dev;
/* Interface name to driver */
wp_strlcpy(ec->f_Context.devname, devname, WAN_DRVNAME_SZ);
ulResult = Oct6100GetInstanceSize(&ec->f_OpenChip, &InstanceSize);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to get EC chip instance size (err=0x%X)!\n",
ec->name, ulResult);
return -EINVAL;
}
/* Allocate memory needed for API instance. */
ec->pChipInstance =
(tPOCT6100_INSTANCE_API)wan_vmalloc(InstanceSize.ulApiInstanceSize);
if (ec->pChipInstance == NULL){
DEBUG_ERROR(
"ERROR: %s: Failed to allocate memory for EC chip (%d bytes)!\n",
ec->name,InstanceSize.ulApiInstanceSize);
return -EINVAL;
}
/* Open the OCT6100 on the evaluation board. */
ec->f_OpenChip.pProcessContext = (PVOID)&ec->f_Context;
/* parse advanced params (global custom configuration) */
if (ec->custom_conf.param_no){
wanec_ChipParam(ec, &ec->f_OpenChip, &ec->custom_conf, verbose);
}
/* parse advanced params (command line custom configuration) */
if (config->custom_conf.param_no){
wanec_ChipParam(ec, &ec->f_OpenChip, &config->custom_conf, verbose);
}
ec->ulDebugChannelHndl = cOCT6100_INVALID_HANDLE;
ec->ulDebugDataMode = config->debug_data_mode;
return 0;
}
int wanec_ChipOpen(wan_ec_dev_t *ec_dev, int verbose)
{
wan_ec_t *ec;
UINT32 ulResult, i = 0;
INT ec_chan = 0;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
PRINT2(verbose,
"%s: Opening Echo Canceller Chip ...\n",
ec->name);
if (ec->f_OpenChip.pbyImageFile == NULL){
DEBUG_ERROR(
"ERROR: %s: Invalid EC image pointer\n",
ec->name);
return -EINVAL;
}
ulResult = Oct6100ChipOpen(
ec->pChipInstance, /* API instance memory. */
&ec->f_OpenChip ); /* Open chip structure. */
if ( ulResult != cOCT6100_ERR_OK ){
if (ec->imageLast == WANOPT_YES ||
ulResult != cOCT6100_ERR_OPEN_INVALID_FIRMWARE_OR_CAPACITY_PINS){
DEBUG_ERROR(
"ERROR: %s: Failed to open Echo Canceller Chip (err=0x%X)\n",
ec->name, ulResult);
}
return -EINVAL;
}
if (wanec_ChipImage(ec_dev, NULL, verbose)){
DEBUG_ERROR(
"ERROR: %s: Failed to read EC chip statistics!\n",
ec->name);
wanec_ChipClose(ec_dev, verbose);
return EINVAL;
}
ec->pToneBufferIndexes =
wan_malloc(sizeof(UINT32) * ec->f_OpenChip.ulMaxPlayoutBuffers);
if (ec->pToneBufferIndexes == NULL){
DEBUG_ERROR(
"ERROR: %s: Failed allocate memory for playout handles!\n",
ec->name);
wanec_ChipClose(ec_dev, verbose);
return EINVAL;
}
i = 0;
while(i < ec->f_OpenChip.ulMaxPlayoutBuffers){
ec->pToneBufferIndexes[i++] = cOCT6100_INVALID_VALUE;
}
ec->pEchoChannelHndl =
wan_malloc(sizeof(UINT32) * MAX_EC_CHANS);
if (ec->pEchoChannelHndl == NULL){
DEBUG_ERROR(
"ERROR: %s: Failed allocate memory for channel handle!\n",
ec->name);
wan_free(ec->pToneBufferIndexes);
wanec_ChipClose(ec_dev, verbose);
return EINVAL;
}
ec->pEcDevMap = wan_malloc(sizeof(wan_ec_dev_t*) * MAX_EC_CHANS);
if (ec->pEcDevMap == NULL){
DEBUG_ERROR(
"ERROR: %s: Failed allocate memory for ec channel map!\n",
ec->name);
wan_free(ec->pToneBufferIndexes);
wan_free(ec->pEchoChannelHndl);
wanec_ChipClose(ec_dev, verbose);
return -EINVAL;
}
for(ec_chan = 0; ec_chan < MAX_EC_CHANS; ec_chan++){
ec->pEchoChannelHndl[ec_chan] = cOCT6100_INVALID_HANDLE;
ec->pEcDevMap[ec_chan] = NULL;
}
return 0;
}
int wanec_ChipClose(wan_ec_dev_t *ec_dev, int verbose)
{
wan_ec_t *ec;
tOCT6100_CHIP_CLOSE f_CloseChip;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
PRINT2(verbose,
"%s: Closing Echo Canceller Chip ...\n",
ec->name);
Oct6100ChipCloseDef( &f_CloseChip );
ulResult = Oct6100ChipClose(
ec->pChipInstance,
&f_CloseChip );
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to close Echo Canceller chip (err=0x%X)!\n",
ec->name, ulResult);
return -EINVAL;
}
if (ec->pChipInstance){
wan_vfree(ec->pChipInstance);
ec->pChipInstance = NULL;
}
if (ec->pToneBufferIndexes){
wan_free(ec->pToneBufferIndexes);
ec->pToneBufferIndexes = NULL;
}
if (ec->pEchoChannelHndl){
wan_free(ec->pEchoChannelHndl);
ec->pEchoChannelHndl = NULL;
}
if (ec->pEcDevMap){
wan_free(ec->pEcDevMap);
ec->pEcDevMap = NULL;
}
return 0;
}
int wanec_ChannelOpen(wan_ec_dev_t *ec_dev, INT ec_chan, int verbose)
{
tOCT6100_CHANNEL_OPEN EchoChannelOpen;
wan_ec_t *ec;
sdla_t *card;
UINT32 ulResult;
UINT32 stream = 0,timeslot=0;
INT pcm_law_type;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
WAN_ASSERT(ec_dev->card == NULL);
ec = ec_dev->ec;
card = (sdla_t*)ec_dev->card;
pcm_law_type = (WAN_FE_TDMV_LAW(&card->fe) == WAN_TDMV_MULAW) ?
cOCT6100_PCM_U_LAW : cOCT6100_PCM_A_LAW;
PRINT2(verbose,
"%s: Openning Echo Canceller channel %d (%s)...\n",
ec->name, ec_chan,
(pcm_law_type == cOCT6100_PCM_U_LAW) ?
"MULAW":"ALAW");
Oct6100ChannelOpenDef( &EchoChannelOpen );
/* Assign the handle memory.*/
EchoChannelOpen.pulChannelHndl = &ec->pEchoChannelHndl[ec_chan];
/* Make sure the channel does not perform echo cancellation */
#if defined(WANEC_BYDEFAULT_NORMAL)
EchoChannelOpen.ulEchoOperationMode =
cOCT6100_ECHO_OP_MODE_NORMAL;
#else
/* purposely fail the compile */
#error "No supported mode"
EchoChannelOpen.ulEchoOperationMode =
cOCT6100_ECHO_OP_MODE_POWER_DOWN;
#endif
EchoChannelOpen.fEnableToneDisabler = TRUE;
stream = (ec_chan % 2 == 1) ? 4 : 0;
timeslot = ec_chan / 2;
/* Configure the TDM interface.*/
EchoChannelOpen.TdmConfig.ulRinPcmLaw = pcm_law_type;
EchoChannelOpen.TdmConfig.ulRoutPcmLaw = pcm_law_type;
EchoChannelOpen.TdmConfig.ulSinPcmLaw = pcm_law_type;
EchoChannelOpen.TdmConfig.ulSoutPcmLaw = pcm_law_type;
EchoChannelOpen.TdmConfig.ulRinStream = stream + 0;
EchoChannelOpen.TdmConfig.ulRinTimeslot = timeslot;
EchoChannelOpen.TdmConfig.ulRoutStream = stream + 1;
EchoChannelOpen.TdmConfig.ulRoutTimeslot = timeslot;
EchoChannelOpen.TdmConfig.ulSinStream = stream + 2;
EchoChannelOpen.TdmConfig.ulSinTimeslot = timeslot;
EchoChannelOpen.TdmConfig.ulSoutStream = stream + 3;
EchoChannelOpen.TdmConfig.ulSoutTimeslot = timeslot;
/* Set the desired VQE features (TRUE/FALSE).*/
EchoChannelOpen.VqeConfig.fEnableNlp = TRUE;
EchoChannelOpen.VqeConfig.fRinDcOffsetRemoval = TRUE;
EchoChannelOpen.VqeConfig.fSinDcOffsetRemoval = TRUE;
if (card->hwec_conf.acustic_echo) {
EchoChannelOpen.VqeConfig.fAcousticEcho = TRUE;
} else {
EchoChannelOpen.VqeConfig.fAcousticEcho = FALSE;
}
if (card->hwec_conf.nlp_disable) {
EchoChannelOpen.VqeConfig.fEnableNlp = FALSE;
} else {
EchoChannelOpen.VqeConfig.fEnableNlp = TRUE;
}
if (card->hwec_conf.operation_mode) {
switch (card->hwec_conf.operation_mode) {
case WANOPT_OCT_CHAN_OPERMODE_SPEECH:
EchoChannelOpen.ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_SPEECH_RECOGNITION;
break;
default:
EchoChannelOpen.ulEchoOperationMode=cOCT6100_ECHO_OP_MODE_NORMAL;
break;
}
} else {
EchoChannelOpen.ulEchoOperationMode=cOCT6100_ECHO_OP_MODE_NORMAL;
}
if (card->tdmv_conf.hw_dtmf && card->hwec_conf.dtmf_removal) {
EchoChannelOpen.VqeConfig.fDtmfToneRemoval = TRUE;
ec_dev->fe_dtmf_removal_map = 0xFFFFFFFF;
} else {
EchoChannelOpen.VqeConfig.fDtmfToneRemoval = FALSE;
ec_dev->fe_dtmf_removal_map = 0;
}
if (card->hwec_conf.tone_disabler_delay) {
UINT32 delay = card->hwec_conf.tone_disabler_delay;
delay = ((delay / 512) + 1) * 512 + 300;
EchoChannelOpen.VqeConfig.ulToneDisablerVqeActivationDelay = delay;
PRINT1(verbose,
"%s: Enable special fax detection option on channel %d (%d)\n",
ec->name, ec_chan,
EchoChannelOpen.VqeConfig.ulToneDisablerVqeActivationDelay);
}
if (card->hwec_conf.noise_reduction) {
EchoChannelOpen.VqeConfig.fSoutAdaptiveNoiseReduction = TRUE;
} else {
EchoChannelOpen.VqeConfig.fSoutAdaptiveNoiseReduction = FALSE;
}
if (card->hwec_conf.rx_gain) {
EchoChannelOpen.VqeConfig.fSoutLevelControl = TRUE;
EchoChannelOpen.VqeConfig.lSoutLevelControlGainDb = card->hwec_conf.rx_gain;
} else {
if (card->hwec_conf.rx_auto_gain) {
EchoChannelOpen.VqeConfig.fSoutAutomaticLevelControl = TRUE;
EchoChannelOpen.VqeConfig.lSoutAutomaticLevelControlTargetDb = card->hwec_conf.rx_auto_gain;
} else {
EchoChannelOpen.VqeConfig.fSoutAutomaticLevelControl = FALSE;
}
}
if (card->hwec_conf.tx_gain) {
EchoChannelOpen.VqeConfig.fRinLevelControl = TRUE;
EchoChannelOpen.VqeConfig.lRinLevelControlGainDb = card->hwec_conf.tx_gain;
} else {
if (card->hwec_conf.tx_auto_gain) {
EchoChannelOpen.VqeConfig.fRinAutomaticLevelControl = TRUE;
EchoChannelOpen.VqeConfig.lRinAutomaticLevelControlTargetDb = card->hwec_conf.tx_auto_gain;
} else {
EchoChannelOpen.VqeConfig.fRinAutomaticLevelControl = FALSE;
}
}
EchoChannelOpen.VqeConfig.ulToneDisablerVqeActivationDelay = ((UINT16)(1500 / 512) + 1) * 512 + 300; /*300;*/
DEBUG_EVENT("%s: Opening HW Echo: [Mode=%s NoiseRed=%s VQE=%i DtmfRmv=%s Acust=%s NLP=%s ]\n",
ec->name,
EchoChannelOpen.ulEchoOperationMode==cOCT6100_ECHO_OP_MODE_NORMAL?"Normal":"Speech",
(EchoChannelOpen.VqeConfig.fSoutAdaptiveNoiseReduction == TRUE)?"On":"Off",
EchoChannelOpen.VqeConfig.ulToneDisablerVqeActivationDelay,
EchoChannelOpen.VqeConfig.fDtmfToneRemoval==TRUE?"On":"Off",
EchoChannelOpen.VqeConfig.fAcousticEcho==TRUE?"On":"Off",
EchoChannelOpen.VqeConfig.fEnableNlp== TRUE?"On":"Off");
EchoChannelOpen.VqeConfig.ulComfortNoiseMode =
cOCT6100_COMFORT_NOISE_NORMAL;
/* cOCT6100_COMFORT_NOISE_NORMAL
** cOCT6100_COMFORT_NOISE_EXTENDED,
** cOCT6100_COMFORT_NOISE_OFF,
** cOCT6100_COMFORT_NOISE_FAST_LATCH */
PRINT2(verbose,
"%s: Openning Echo Canceller channel %d (%s)...\n",
ec->name,
ec_chan,
(pcm_law_type == cOCT6100_PCM_U_LAW) ?
"MULAW":"ALAW");
/* Open the channel.*/
ulResult = Oct6100ChannelOpen( ec->pChipInstance,
&EchoChannelOpen );
if (ulResult != cOCT6100_ERR_OK){
DEBUG_ERROR(
"ERROR: %s: Failed to open Echo Canceller channel %d (err=0x%X)!\n",
ec->name,
ec_chan,
ulResult);
return ulResult;
}
/* Init debug channel handle */
ec->ulDebugChannelHndl = cOCT6100_INVALID_HANDLE;
return 0;
}
int wanec_ChannelClose(wan_ec_dev_t *ec_dev, INT ec_chan, int verbose)
{
wan_ec_t *ec;
tOCT6100_CHANNEL_CLOSE EchoChannelClose;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
PRINT2(verbose,
"%s: Closing Echo Canceller channel %d ...\n",
ec->name, ec_chan);
Oct6100ChannelCloseDef( &EchoChannelClose );
EchoChannelClose.ulChannelHndl =
ec->pEchoChannelHndl[ec_chan];
ulResult = Oct6100ChannelClose( ec->pChipInstance,
&EchoChannelClose );
if (ulResult != cOCT6100_ERR_OK){
DEBUG_ERROR(
"ERROR: %s: Failed to close Echo Canceller channel %d (err=0x%X)!\n",
ec->name,
ec_chan,
ulResult);
return -EINVAL;
}
ec->pEchoChannelHndl[ec_chan] = cOCT6100_INVALID_HANDLE;
return 0;
}
int wanec_ChannelModifyOpmode( wan_ec_dev_t *ec_dev,
INT channel,
UINT32 opmode,
int verbose)
{
wan_ec_t *ec;
tOCT6100_CHANNEL_MODIFY EchoChannelModify;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
PRINT2(verbose, "%s: Modifing EC Channel OPMODE to %d on ec_chan:%d...\n",
ec->name, opmode, channel);
Oct6100ChannelModifyDef( &EchoChannelModify );
/* Assign the handle memory.*/
EchoChannelModify.ulChannelHndl = ec->pEchoChannelHndl[channel];
/* Echo Channel Operation Mode */
EchoChannelModify.ulEchoOperationMode = opmode;
/* Open the channel.*/
ulResult = Oct6100ChannelModify(
ec->pChipInstance,
&EchoChannelModify );
if (ulResult != cOCT6100_ERR_OK){
DEBUG_EVENT(
"%s: Failed to modify EC Channel OPMOde for ec_chan:%d (err=0x%X)\n",
ec->name, channel, ulResult);
return EINVAL;
}
return 0;
}
int wanec_DtmfRemoval(wan_ec_dev_t *ec_dev, INT channel, int enable, int verbose)
{
wan_ec_t *ec;
tOCT6100_CHANNEL_MODIFY EchoChannelModify;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
if (enable) {
if (ec_dev->fe_dtmf_removal_map & (1 << channel)) {
return 0;
}
ec_dev->fe_dtmf_removal_map |= (1 << channel);
} else { /* Disable */
if (!(ec_dev->fe_dtmf_removal_map & (1 << channel))) {
return 0;
}
ec_dev->fe_dtmf_removal_map &= ~(1 << channel);
}
PRINT2(verbose, "%s: %s EC Channel DTMF Removal ec_chan:%d...\n",
enable ? "Enable" : "Disable", ec->name, channel);
Oct6100ChannelModifyDef(&EchoChannelModify);
/* Assign the handle memory.*/
EchoChannelModify.ulChannelHndl = ec->pEchoChannelHndl[channel];
EchoChannelModify.fVqeConfigModified = TRUE;
EchoChannelModify.VqeConfig.fDtmfToneRemoval = enable ? TRUE : FALSE;
/* Open the channel.*/
ulResult = Oct6100ChannelModify(ec->pChipInstance, &EchoChannelModify);
if (ulResult != cOCT6100_ERR_OK){
DEBUG_EVENT("%s: Failed to %s EC Channel DTMF Removal for ec_chan:%d (err=0x%X)\n",
ec->name, enable ? "Enable" : "Disable", channel, ulResult);
return EINVAL;
}
return 0;
}
int wanec_ChannelModifyCustom( wan_ec_dev_t *ec_dev,
INT channel,
wanec_chan_custom_t *chan_custom,
int verbose)
{
wan_ec_t *ec;
tOCT6100_CHANNEL_MODIFY EchoChannelModify;
UINT32 ulResult;
int err;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
WAN_ASSERT(chan_custom == NULL);
WAN_ASSERT(chan_custom->custom_conf.param_no == 0);
ec = ec_dev->ec;
PRINT2(verbose, "%s: Modifing EC Channel Config parameters for ec_chan:%d...\n",
ec->name, channel);
Oct6100ChannelModifyDef( &EchoChannelModify );
/* Assign the handle memory.*/
EchoChannelModify.ulChannelHndl = ec->pEchoChannelHndl[channel];
/* parse advianced params */
err = wanec_ChanParam(ec, &EchoChannelModify, &chan_custom->custom_conf, verbose);
if (err){
DEBUG_EVENT(
"%s: WARNING: Unsupported parameter for channel %d!\n",
ec->name, channel);
return -EINVAL;
}
/* Open the channel.*/
ulResult = Oct6100ChannelModify(
ec->pChipInstance,
&EchoChannelModify );
if (ulResult != cOCT6100_ERR_OK){
DEBUG_EVENT(
"%s: Failed to modify EC channel config parameters for ec_chan:%d (err=0x%X)\n",
ec->name, channel, ulResult);
return EINVAL;
}
return 0;
}
/******************************************************************************
** CONFERENCE BRIDGE FUNCTIONS
******************************************************************************/
int wanec_ChannelMute(wan_ec_dev_t* ec_dev, INT ec_chan, wanec_chan_mute_t *mute, int verbose)
{
wan_ec_t *ec;
tOCT6100_CHANNEL_MUTE f_ChannelMute;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
Oct6100ChannelMuteDef( &f_ChannelMute );
f_ChannelMute.ulChannelHndl = ec->pEchoChannelHndl[ec_chan];
f_ChannelMute.ulPortMask = cOCT6100_CHANNEL_MUTE_PORT_NONE;
if (mute == NULL || mute->port_map & WAN_EC_CHANNEL_PORT_SOUT)
f_ChannelMute.ulPortMask |= cOCT6100_CHANNEL_MUTE_PORT_SOUT;
if (mute == NULL || mute->port_map & WAN_EC_CHANNEL_PORT_SIN)
f_ChannelMute.ulPortMask |= cOCT6100_CHANNEL_MUTE_PORT_SIN;
if (mute == NULL || mute->port_map & WAN_EC_CHANNEL_PORT_ROUT)
f_ChannelMute.ulPortMask |= cOCT6100_CHANNEL_MUTE_PORT_ROUT;
if (mute == NULL || mute->port_map & WAN_EC_CHANNEL_PORT_RIN)
f_ChannelMute.ulPortMask |= cOCT6100_CHANNEL_MUTE_PORT_RIN;
PRINT2(verbose, "%s: Muting EC Channel %d on port:%X...\n",
ec->name, ec_chan, f_ChannelMute.ulPortMask);
ulResult = Oct6100ChannelMute(
ec->pChipInstance,
&f_ChannelMute);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to mute EC channel %d on port %X (%08X)!\n",
ec->name, ec_chan, f_ChannelMute.ulPortMask, ulResult);
return EINVAL;
}
return 0;
}
int wanec_ChannelUnMute(wan_ec_dev_t *ec_dev, INT ec_chan, wanec_chan_mute_t *mute, int verbose)
{
wan_ec_t *ec;
tOCT6100_CHANNEL_UNMUTE f_ChannelUnMute;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
Oct6100ChannelUnMuteDef( &f_ChannelUnMute );
f_ChannelUnMute.ulChannelHndl = ec->pEchoChannelHndl[ec_chan];
f_ChannelUnMute.ulPortMask = cOCT6100_CHANNEL_MUTE_PORT_NONE;
if (mute == NULL || mute->port_map & WAN_EC_CHANNEL_PORT_SOUT)
f_ChannelUnMute.ulPortMask |= cOCT6100_CHANNEL_MUTE_PORT_SOUT;
if (mute == NULL || mute->port_map & WAN_EC_CHANNEL_PORT_SIN)
f_ChannelUnMute.ulPortMask |= cOCT6100_CHANNEL_MUTE_PORT_SIN;
if (mute == NULL || mute->port_map & WAN_EC_CHANNEL_PORT_ROUT)
f_ChannelUnMute.ulPortMask |= cOCT6100_CHANNEL_MUTE_PORT_ROUT;
if (mute == NULL || mute->port_map & WAN_EC_CHANNEL_PORT_RIN)
f_ChannelUnMute.ulPortMask |= cOCT6100_CHANNEL_MUTE_PORT_RIN;
PRINT2(verbose, "%s: Un-Muting EC channel %d on port:%X...\n",
ec->name, ec_chan, f_ChannelUnMute.ulPortMask);
ulResult = Oct6100ChannelUnMute(
ec->pChipInstance,
&f_ChannelUnMute);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to un-mute channel %d on port %X (%08X)!\n",
ec->name, ec_chan, f_ChannelUnMute.ulPortMask, ulResult);
return EINVAL;
}
return 0;
}
int wanec_ChannelStats(wan_ec_dev_t *ec_dev, INT channel, wanec_chan_stats_t *chan_stats, int verbose)
{
wan_ec_t *ec;
tOCT6100_CHANNEL_STATS f_ChannelStats;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
PRINT2(verbose, "%s: Reading EC statistics for channel %d...\n",
ec->name, channel);
Oct6100ChannelGetStatsDef( &f_ChannelStats );
f_ChannelStats.ulChannelHndl = ec->pEchoChannelHndl[channel];
f_ChannelStats.fResetStats = chan_stats->reset;
ulResult = Oct6100ChannelGetStats(
ec->pChipInstance,
&f_ChannelStats);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to read EC stats for channel %d (%08X)!\n",
ec->name, channel, ulResult);
return EINVAL;
}
if (chan_stats){
memcpy( &chan_stats->f_ChannelStats,
&f_ChannelStats,
sizeof(tOCT6100_CHANNEL_STATS));
}
return 0;
}
int wanec_TonesCtrl(wan_ec_t *ec, int cmd, int ec_chan, wanec_tone_config_t *tone, int verbose)
{
UINT32 *tones=NULL;
int tone_no = 0, i = 0, err = 0;
uint8_t port_map = (tone) ? tone->port_map : (WAN_EC_CHANNEL_PORT_ROUT|WAN_EC_CHANNEL_PORT_SOUT);
if (tone->id == WP_API_EVENT_TONE_DTMF){
tones = WanEcToneListDTMF;
tone_no = sizeof(WanEcToneListDTMF)/sizeof(UINT32);
}else if (tone->id == WP_API_EVENT_TONE_FAXCALLING){
tones = WanEcToneListFaxCalling;
tone_no = sizeof(WanEcToneListFaxCalling)/sizeof(UINT32);
}else if (tone->id == WP_API_EVENT_TONE_FAXCALLED){
tones = WanEcToneListFaxCalled;
tone_no = sizeof(WanEcToneListFaxCalled)/sizeof(UINT32);
}else{
return -EINVAL;
}
for(i = 0; i < tone_no; i++){
if (((port_map & WAN_EC_CHANNEL_PORT_ROUT) && (tones[i] & WANEC_TONE_ROUT_MASK)) ||
((port_map & WAN_EC_CHANNEL_PORT_SOUT) && (tones[i] & WANEC_TONE_SOUT_MASK)) ){
if (cmd == WAN_TRUE){
err = wanec_ToneEnable(ec, ec_chan, tones[i], verbose);
}else{
err = wanec_ToneDisable(ec, ec_chan, tones[i], verbose);
}
}
if (err) return -EINVAL;
}
return 0;
}
static int wanec_ToneEnable(wan_ec_t *ec, int ec_chan, UINT32 tone_id, int verbose)
{
tOCT6100_TONE_DETECTION_ENABLE f_ToneDetectionEnable;
UINT32 ulResult;
PRINT2(verbose, "%s: Enable EC tone (0x%08X) detection on chan %d ...\n",
ec->name, tone_id, ec_chan);
Oct6100ToneDetectionEnableDef( &f_ToneDetectionEnable );
f_ToneDetectionEnable.ulChannelHndl = ec->pEchoChannelHndl[ec_chan];
f_ToneDetectionEnable.ulToneNumber = tone_id;
ulResult = Oct6100ToneDetectionEnable (
ec->pChipInstance,
&f_ToneDetectionEnable);
if ( ulResult != cOCT6100_ERR_OK ){
if (ulResult != cOCT6100_ERR_TONE_DETECTION_TONE_ACTIVATED){
DEBUG_ERROR(
"ERROR: %s: Failed to enable EC Tone (0x%08X) detection on ec chan %d (err=0x%08X)!\n",
ec->name, tone_id, ec_chan, (unsigned int)ulResult);
return -EINVAL;
}
PRINT2(verbose,
"%s: EC Tone (0x%08X) detection is already enabled on channel %d!\n",
ec->name, tone_id, ec_chan);
}
return 0;
}
static int wanec_ToneDisable(wan_ec_t *ec, int ec_chan, UINT32 tone_id, int verbose)
{
tOCT6100_TONE_DETECTION_DISABLE f_ToneDetectionDisable;
UINT32 ulResult;
PRINT2(verbose, "%s: Disable EC tone (0x%08X) detection on chan %d ...\n",
ec->name, tone_id, ec_chan);
Oct6100ToneDetectionDisableDef( &f_ToneDetectionDisable );
f_ToneDetectionDisable.ulChannelHndl = ec->pEchoChannelHndl[ec_chan];
if (ec_chan >= 0){
f_ToneDetectionDisable.ulToneNumber = tone_id;
}else{
f_ToneDetectionDisable.fDisableAll = TRUE;
}
ulResult = Oct6100ToneDetectionDisable (
ec->pChipInstance,
&f_ToneDetectionDisable);
if ( ulResult != cOCT6100_ERR_OK ){
if (ulResult != cOCT6100_ERR_TONE_DETECTION_TONE_NOT_ACTIVATED){
DEBUG_ERROR(
"ERROR: %s: Failed to disable EC Tone (0x%08X) detection on ec chan %d (err=0x%08X)!\n",
ec->name, tone_id, ec_chan, (unsigned int)ulResult);
return -EINVAL;
}
}
return 0;
}
static CHAR* wanec_ToneId2Str(UINT32 f_ulToneId)
{
switch (f_ulToneId){
/* DTMF Section */
case ROUT_DTMF_0: return "ROUT_DTMF_0";
case ROUT_DTMF_1: return "ROUT_DTMF_1";
case ROUT_DTMF_2: return "ROUT_DTMF_2";
case ROUT_DTMF_3: return "ROUT_DTMF_3";
case ROUT_DTMF_4: return "ROUT_DTMF_4";
case ROUT_DTMF_5: return "ROUT_DTMF_5";
case ROUT_DTMF_6: return "ROUT_DTMF_6";
case ROUT_DTMF_7: return "ROUT_DTMF_7";
case ROUT_DTMF_8: return "ROUT_DTMF_8";
case ROUT_DTMF_9: return "ROUT_DTMF_9";
case ROUT_DTMF_A: return "ROUT_DTMF_A";
case ROUT_DTMF_B: return "ROUT_DTMF_B";
case ROUT_DTMF_C: return "ROUT_DTMF_C";
case ROUT_DTMF_D: return "ROUT_DTMF_D";
case ROUT_DTMF_STAR: return "ROUT_DTMF_STAR";
case ROUT_DTMF_POUND: return "ROUT_DTMF_POUND";
case SOUT_DTMF_0: return "SOUT_DTMF_0";
case SOUT_DTMF_1: return "SOUT_DTMF_1";
case SOUT_DTMF_2: return "SOUT_DTMF_2";
case SOUT_DTMF_3: return "SOUT_DTMF_3";
case SOUT_DTMF_4: return "SOUT_DTMF_4";
case SOUT_DTMF_5: return "SOUT_DTMF_5";
case SOUT_DTMF_6: return "SOUT_DTMF_6";
case SOUT_DTMF_7: return "SOUT_DTMF_7";
case SOUT_DTMF_8: return "SOUT_DTMF_8";
case SOUT_DTMF_9: return "SOUT_DTMF_9";
case SOUT_DTMF_A: return "SOUT_DTMF_A";
case SOUT_DTMF_B: return "SOUT_DTMF_B";
case SOUT_DTMF_C: return "SOUT_DTMF_C";
case SOUT_DTMF_D: return "SOUT_DTMF_D";
case SOUT_DTMF_STAR: return "SOUT_DTMF_STAR";
case SOUT_DTMF_POUND: return "SOUT_DTMF_POUND";
/* System 5/6/7 Section */
case SIN_SYSTEM5_2400: return "SIN_SYSTEM5_2400";
case SIN_SYSTEM5_2600: return "SIN_SYSTEM5_2600";
case SIN_SYSTEM5_2400_2600: return "SIN_SYSTEM5_2400_2600";
case SIN_SYSTEM7_2000: return "SIN_SYSTEM7_2000";
case SIN_SYSTEM7_1780: return "SIN_SYSTEM7_1780";
case SOUT_G168_2100GB_ON: return "SOUT_G168_2100GB_ON";
case SOUT_G168_2100GB_WSPR: return "SOUT_G168_2100GB_WSPR";
case ROUT_G168_2100GB_ON: return "ROUT_G168_2100GB_ON";
case ROUT_G168_2100GB_WSPR: return "ROUT_G168_2100GB_WSPR";
case SOUT_G168_1100GB_ON: return "SOUT_G168_1100GB_ON";
case ROUT_G168_1100GB_ON: return "ROUT_G168_1100GB_ON";
case ROUT_SOUT_G168_2100HB_END: return "ROUT_SOUT_G168_2100HB_END";
default: return "INVALID TONE ID!";
}
}
static int wanec_ConvertToneId(UINT32 f_ulToneId, unsigned char *ec_tone_port, unsigned char *digit, u_int16_t *type)
{
int err=0;
switch (f_ulToneId){
/* DTMF Section */
case ROUT_DTMF_0:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='0';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_1:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='1';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_2:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='2';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_3:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='3';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_4:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='4';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_5:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='5';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_6:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='6';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_7:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='7';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_8:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='8';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_9:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='9';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_A:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='A';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_B:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='B';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_C:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='C';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_D:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='D';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_STAR:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='*';
*type = WAN_EVENT_EC_DTMF;
break;
case ROUT_DTMF_POUND:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='#';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_0:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='0';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_1:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='1';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_2:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='2';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_3:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='3';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_4:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='4';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_5:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='5';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_6:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='6';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_7:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='7';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_8:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='8';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_9:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='9';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_A:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='A';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_B:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='B';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_C:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='C';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_D:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='D';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_STAR:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='*';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_DTMF_POUND:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='#';
*type = WAN_EVENT_EC_DTMF;
break;
case SOUT_G168_2100GB_ON:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='f';
*type = WAN_EVENT_EC_FAX_2100;
break;
case SOUT_G168_2100GB_WSPR:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='f';
*type = WAN_EVENT_EC_FAX_2100_WSPR;
break;
case ROUT_G168_2100GB_ON:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='f';
*type = WAN_EVENT_EC_FAX_2100;
break;
case ROUT_G168_2100GB_WSPR:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='f';
*type = WAN_EVENT_EC_FAX_2100_WSPR;
break;
case SOUT_G168_1100GB_ON:
*ec_tone_port = WAN_EC_CHANNEL_PORT_SOUT;
*digit ='f';
*type = WAN_EVENT_EC_FAX_1100;
break;
case ROUT_G168_1100GB_ON:
*ec_tone_port = WAN_EC_CHANNEL_PORT_ROUT;
*digit ='f';
*type = WAN_EVENT_EC_FAX_1100;
break;
default:
err=-1;
}
return err;
}
#if 1
//#if defined(WAN_DEBUG_HWEC)
static CHAR* wanec_ToneType2Str(UINT32 f_ulToneType)
{
switch (f_ulToneType){
case cOCT6100_TONE_PRESENT: return "cOCT6100_TONE_PRESENT";
case cOCT6100_TONE_STOP: return "cOCT6100_TONE_STOP";
default: return "INVALID TONE TYPE!";
}
}
#endif
static unsigned char wanec_ConvertToneType(UINT32 f_ulToneType)
{
switch (f_ulToneType){
case cOCT6100_TONE_PRESENT: return WAN_EC_TONE_PRESENT;
case cOCT6100_TONE_STOP: return WAN_EC_TONE_STOP;
}
return 0x00;
}
static CHAR* wanec_BufferPlayoutType2Str(UINT32 f_ulBufferPlayoutType)
{
switch (f_ulBufferPlayoutType){
case cOCT6100_BUFFER_PLAYOUT_EVENT_STOP: return "PLAYOUT_EVENT_STOP";
#if 0
case cOCT6100_BUFFER_PLAYOUT_EVENT_CALLER_ID_STOP: return "PLAYOUT_EVENT_CALLER_ID_STOP";
case cOCT6100_BUFFER_PLAYOUT_EVENT_CALLER_ID_AS_STOP: return "PLAYOUT_EVENT_CALLER_ID_AS_STOP";
#endif
default: return "INVALID BUFFER_PLAYOUT TYPE!";
}
}
#if 0
/* Implemented fax debouncing but
decieded not to use it. Code is here in case
we change our mind */
static int wanec_fax_detect_debounce(wan_ec_dev_t *ec_dev, wan_event_t *event)
{
sdla_t *card = (sdla_t*)ec_dev->card;
if (event->digit == 'f') {
if (card->tdmv_conf.hw_fax_detect == WANOPT_NO) {
} else if (card->tdmv_conf.hw_fax_detect == WANOPT_YES) {
card->tdmv_conf.hw_fax_detect=4; /* number of sec between events */
}
if (!card->hwec_conf.hw_fax_detect_cnt) {
card->hwec_conf.hw_fax_detect_cnt=4; /* number of events PRESENT & STOP */
}
if (SYSTEM_TICKS - ec_dev->fax_detect_timeout >= card->tdmv_conf.hw_fax_detect*HZ) {
ec_dev->fax_detect_timeout=SYSTEM_TICKS;
ec_dev->fax_detect_cnt=1;
DEBUG_EVENT("%s: Ignore fax tone cnt=%i, waiting for another one [fax type=%s]\n",
ec_dev->devname,ec_dev->fax_detect_cnt,event->tone_type == WAN_EC_TONE_PRESENT?"PRESENT":"STOP");
return 1;
} else {
ec_dev->fax_detect_timeout=SYSTEM_TICKS;
ec_dev->fax_detect_cnt++;
if (ec_dev->fax_detect_cnt <= card->hwec_conf.hw_fax_detect_cnt) {
DEBUG_EVENT("%s: Ignore fax tone cnt=%i, waiting for another one [fax type=%s]\n",
ec_dev->devname,ec_dev->fax_detect_cnt,event->tone_type == WAN_EC_TONE_PRESENT?"PRESENT":"STOP");
return 1;
}
}
}
DEBUG_EVENT("%s: Pass on the tone [fax type=%s]\n",
ec_dev->devname,event->tone_type == WAN_EC_TONE_PRESENT?"PRESENT":"STOP");
return 0;
}
#endif
/*
** wanec_ToneEvent()
**
** Return: 0 - on success
** <0 - on error
** 1 - pending tone events
**/
int wanec_ToneEvent(wan_ec_t *ec, int verbose)
{
tOCT6100_EVENT_GET_TONE f_GetToneEvent;
tOCT6100_TONE_EVENT ToneEvent[32];
wan_event_t event;
UINT32 ulResult;
wan_ec_dev_t *ec_dev;
sdla_t *card;
UINT32 i;
int ec_chan;
u8 fe_chan;
PRINT2(verbose, "%s: Getting Tone events ...\n",
ec->name);
Oct6100EventGetToneDef( &f_GetToneEvent );
f_GetToneEvent.fResetBufs = FALSE;
f_GetToneEvent.ulMaxToneEvent = WANEC_MAX_TONEEVENTS;
f_GetToneEvent.pToneEvent = ToneEvent;
ulResult = Oct6100EventGetTone(
ec->pChipInstance,
&f_GetToneEvent);
if ( ulResult != cOCT6100_ERR_OK ){
if ( ulResult != cOCT6100_ERR_EVENTS_TONE_BUF_EMPTY ){
PRINT2(verbose, "%s: There are not tone events!\n",
ec->name);
return 0;
}
DEBUG_ERROR(
"ERROR: %s: Failed to get tone events (err=0x%X)!\n",
ec->name, ulResult);
return -EINVAL;
}
/* No tone tone event returned */
if (!f_GetToneEvent.ulNumValidToneEvent) return 0;
for(i = 0; i < f_GetToneEvent.ulNumValidToneEvent; i++){
ec_chan = wanec_hndl2ec_channel(ec, ToneEvent[i].ulChannelHndl);
ec_dev = ec->pEcDevMap[ec_chan];
fe_chan = (u8)wanec_ec2fe_channel(ec, ec_chan, &ec_dev);
if (ec_dev == NULL || ec_dev->card == NULL){
DEBUG_ERROR(
"%s: Internal Error: Failed to find fe channel (ec_chan=%d)\n",
ec->name, ec_chan);
continue;
}
PRINT2(verbose,
"%s: Tone event %s %s on fe_chan=%d ec_chan=%d\n",
ec_dev->devname,
wanec_ToneId2Str(ToneEvent[i].ulToneDetected),
wanec_ToneType2Str(f_GetToneEvent.pToneEvent[i].ulEventType),
fe_chan, ec_chan);
card = (sdla_t*)ec_dev->card;
if (card->wandev.event_callback.tone){
int err;
event.channel = fe_chan;
event.tone_type = wanec_ConvertToneType(ToneEvent[i].ulEventType);
err=wanec_ConvertToneId(
ToneEvent[i].ulToneDetected,
&event.tone_port, &event.digit, &event.type);
if (err != 0) {
DEBUG_ERROR("%s: Error: Unsupported Tone Detected: chan=%i tone=0x%X\n",
ec->name, fe_chan, ToneEvent[i].ulToneDetected);
goto ignore_tone;
}
#if 0
/* Implemented fax debouncing but
decieded not to use it. Code is here in case
we change our mind */
if (wanec_fax_detect_debounce(ec_dev, &event)) {
goto ignore_tone;
}
#endif
card->wandev.event_callback.tone(card, &event);
ignore_tone:
;
}
}
/* Return 1 if more tone event are present, otherwise - 0 */
return (f_GetToneEvent.fMoreEvents == TRUE) ? 1 : 0;
}
/*
** wanec_PlayoutEvent()
**
** Return: 0 - on success
** <0 - on error
** 1 - pending tone events
**/
int wanec_PlayoutEvent(wan_ec_t *ec, int verbose)
{
tOCT6100_BUFFER_PLAYOUT_GET_EVENT f_BufferPlayoutGetEvent;
tOCT6100_BUFFER_PLAYOUT_EVENT PlayoutEvent[32];
UINT32 ulResult;
wan_ec_dev_t *ec_dev;
UINT32 i;
int ec_chan,fe_chan;
PRINT2(verbose, "%s: Getting EC Buffer Playout events ...\n",
ec->name);
Oct6100BufferPlayoutGetEventDef( &f_BufferPlayoutGetEvent );
f_BufferPlayoutGetEvent.pBufferPlayoutEvent = PlayoutEvent;
f_BufferPlayoutGetEvent.ulMaxEvent = WANEC_MAX_PLAYOUTEVENTS;
f_BufferPlayoutGetEvent.fResetBufs = FALSE;
ulResult = Oct6100BufferPlayoutGetEvent(
ec->pChipInstance,
&f_BufferPlayoutGetEvent);
if ( ulResult != cOCT6100_ERR_OK ){
if ( ulResult != cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_BUF_EMPTY ){
PRINT2(verbose, "%s: There are not buffer playout events!\n",
ec->name);
return 0;
}
DEBUG_ERROR(
"ERROR: %s: Failed to get buffer playout events (err=0x%X)!\n",
ec->name, ulResult);
return -EINVAL;
}
/* No dtmf tone event returned */
if (!f_BufferPlayoutGetEvent.ulNumValidEvent) return 0;
for(i = 0; i < f_BufferPlayoutGetEvent.ulNumValidEvent; i++){
ec_chan = wanec_hndl2ec_channel(ec, PlayoutEvent[i].ulChannelHndl);
ec_dev = ec->pEcDevMap[ec_chan];
fe_chan = wanec_ec2fe_channel(ec, ec_chan, &ec_dev);
if (ec_dev == NULL || ec_dev->card == NULL){
DEBUG_ERROR(
"%s: Internal Error: Failed to find fe channel (ec_chan=%d)\n",
ec->name, ec_chan);
continue;
}
PRINT2(verbose,
"%s: EC Buffer Playout event id %d %s on fe_chan=%d ec_chan=%d port=%s\n",
ec_dev->devname,
PlayoutEvent[i].ulUserEventId,
wanec_BufferPlayoutType2Str(PlayoutEvent[i].ulEventType),
fe_chan, ec_chan,
(PlayoutEvent[i].ulChannelPort==cOCT6100_CHANNEL_PORT_ROUT) ? "ROUT" : "SOUT");
#if 0
card = (sdla_t*)ec_dev->card;
if (card->wandev.event_callback.playout){
}
#endif
}
/* Return 1 if more playout event are present, otherwise - 0 */
return (f_BufferPlayoutGetEvent.fMoreEvents == TRUE) ? 1 : 0;
}
#define wan_ec_isr_error_print(_format, _message, ...) if (!wan_test_and_set_bit(1,&silent)) { DEBUG_ERROR(_format, _message, ## __VA_ARGS__) };
/*
** wanec_ISR()
**
** Return: 0 - on success
** <0 - on error
** 1 - pending tone events
**/
int wanec_ISR(wan_ec_t *ec, int verbose)
{
UINT32 ulResult;
int ret = 0;
unsigned int silent=0;
WAN_ASSERT(ec == NULL);
PRINT2(verbose, "%s: Executing EC interrupt routine ...\n",
ec->name);
Oct6100InterruptServiceRoutineDef(&ec->f_InterruptFlag);
ulResult = Oct6100InterruptServiceRoutine(
ec->pChipInstance,
&ec->f_InterruptFlag );
if ( ulResult != cOCT6100_ERR_OK ){
/* The 0x001DFF02D does not mean that the EC is dead.
It means that a problem has occurred while doing a read burst to get the detected tones */
if (ulResult != 0x001DF02D) {
wan_ec_isr_error_print(
"ERROR: %s: Failed to execute interrupt Service Routine (err=%08X)!\n",
ec->name,
ulResult);
}
return -EINVAL;
}
/* Critical errors */
if (ec->f_InterruptFlag.fFatalGeneral == TRUE){
/* Ignore cOCT6100_FATAL_GENERAL_ERROR_TYPE_5 timeout errors */
if (ec->f_InterruptFlag.ulFatalGeneralFlags != cOCT6100_FATAL_GENERAL_ERROR_TYPE_5) {
wan_ec_isr_error_print(
"%s: An internal fatal chip error detected (0x%X)!\n",
ec->name,
ec->f_InterruptFlag.ulFatalGeneralFlags);
}
}
if (ec->f_InterruptFlag.fFatalReadTimeout == TRUE){
wan_ec_isr_error_print(
"%s: A read to the external memory has failed!\n %s",
ec->name, " ");
}
if (ec->f_InterruptFlag.fErrorRefreshTooLate == TRUE){
wan_ec_isr_error_print(
"%s: Error Refresh Too Late!\n %s",
ec->name, " ");
}
if (ec->f_InterruptFlag.fErrorPllJitter == TRUE){
wan_ec_isr_error_print(
"%s: Error Pll Jitter\n %s",
ec->name, " ");
}
if (ec->f_InterruptFlag.fErrorH100OutOfSync == TRUE && !ec->ignore_H100){
wan_ec_isr_error_print(
"%s: The H100 slave has lost its framing on the bus!\n %s",
ec->name, " ");
}
if (ec->f_InterruptFlag.fErrorH100ClkA == TRUE){
wan_ec_isr_error_print(
"%s: The CT_C8_A clock behavior does not conform to the H.100 spec!\n %s",
ec->name, " ");
}
if (ec->f_InterruptFlag.fErrorH100FrameA == TRUE){
wan_ec_isr_error_print(
"%s: The CT_FRAME_A clock behavior does not comform to the H.100 spec!\n %s",
ec->name, " ");
}
if (ec->f_InterruptFlag.fErrorH100ClkB == TRUE){
wan_ec_isr_error_print(
"%s: The CT_C8_B clock is not running a 16.384 MHz!\n %s",
ec->name, " ");
}
if (ec->f_InterruptFlag.fErrorOverflowToneEvents == TRUE){
wan_ec_isr_error_print(
"%s: Error: Tone Event buffer has overflowed\n %s",
ec->name, " ");
}
if (ec->f_InterruptFlag.fToneEventsPending == TRUE){
PRINT2(verbose, "%s: Tone Event pending....\n",
ec->name);
ret = wanec_ToneEvent(ec, ec->tone_verbose);
}
if (ec->f_InterruptFlag.fBufferPlayoutEventsPending == TRUE){
PRINT2(verbose,
"%s: Buffer Playout Events Pending\n",
ec->name);
ret = wanec_PlayoutEvent(ec, ec->playout_verbose);
}
if (ec->f_InterruptFlag.fApiSynch == TRUE){
PRINT2(verbose,
"%s: The chip interrupted the API for purpose of maintaining sync!\n",
ec->name);
}
return ret;
}
int wanec_DebugChannel(wan_ec_dev_t *ec_dev, INT channel, int verbose)
{
wan_ec_t *ec = NULL;
tOCT6100_DEBUG_SELECT_CHANNEL DebugSelectChannel;
wanec_chan_stats_t chan_stats;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
/* Verify Echo Canceller Channel operation mode */
memset(&chan_stats, 0, sizeof(wanec_chan_stats_t));
ulResult = wanec_ChannelStats(ec_dev, channel, &chan_stats, 0);
if (chan_stats.f_ChannelStats.ulEchoOperationMode == cOCT6100_ECHO_OP_MODE_POWER_DOWN){
DEBUG_EVENT(
"ERROR: %s: Invalid Echo Channel %d operation mode (POWER DOWN)!\n",
ec_dev->name, channel);
return -EINVAL;
}
if (ec_dev->ec->ulDebugChannelHndl != cOCT6100_INVALID_HANDLE){
DEBUG_ERROR(
"ERROR: %s: Echo Canceller daemon can monitor only one ec channel (%d)!\n",
ec_dev->name, channel);
return -EINVAL;
}
Oct6100DebugSelectChannelDef( &DebugSelectChannel );
PRINT2(verbose, "%s: Select ec channel %d for monitoring...\n",
ec_dev->name,
channel);
/* Set selected debug channel */
ec->DebugChannel = channel;
ec->ulDebugChannelHndl = ec->pEchoChannelHndl[channel];
DebugSelectChannel.ulChannelHndl= ec->pEchoChannelHndl[channel];
/* Select Debug channel */
ulResult = Oct6100DebugSelectChannel(
ec->pChipInstance,
&DebugSelectChannel );
if (ulResult != cOCT6100_ERR_OK){
DEBUG_ERROR(
"ERROR: %s: Failed to select debug ec channel %d for monitoring (err=0x%X)\n",
ec->name,
channel,
ulResult);
return -EINVAL;
}
return 0;
}
int wanec_DebugGetData(wan_ec_dev_t *ec_dev, wanec_chan_monitor_t *chan_monitor, int verbose)
{
wan_ec_t *ec = NULL;
tOCT6100_DEBUG_GET_DATA fDebugGetData;
UINT32 ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
if (ec->ulDebugChannelHndl == cOCT6100_INVALID_HANDLE){
DEBUG_ERROR(
"ERROR: %s: No Debug channel was selected!\n",
ec->name);
return -EINVAL;
}
Oct6100DebugGetDataDef( &fDebugGetData );
if (!chan_monitor->remain_len){
PRINT1(verbose,
"%s: Retrieves debug data for ec channel %d (%s)...\n",
ec->name,
ec->DebugChannel,
(chan_monitor->data_mode == cOCT6100_DEBUG_GET_DATA_MODE_120S) ? "120s" :
(chan_monitor->data_mode == cOCT6100_DEBUG_GET_DATA_MODE_120S_LITE) ? "120s-lite" :
(chan_monitor->data_mode == cOCT6100_DEBUG_GET_DATA_MODE_16S) ? "16s" :
(chan_monitor->data_mode == cOCT6100_DEBUG_GET_DATA_MODE_16S_LITE) ? "16s-lite" :
"unknown");
}else{
PRINT2(verbose,
"%s: Retrieves remain debug data (%d bytes) for ec channel %d...\n",
ec->name,
chan_monitor->remain_len, ec->DebugChannel);
}
memset(&chan_monitor->data[0], 0,
sizeof(UINT8) * (MAX_MONITOR_DATA_LEN+1));
/* Set selected debug channel */
fDebugGetData.ulGetDataMode = chan_monitor->data_mode; //ec->ulDebugDataMode;
fDebugGetData.ulMaxBytes = chan_monitor->max_len;
fDebugGetData.pbyData = &chan_monitor->data[0];
/* Select Debug channel */
ulResult = Oct6100DebugGetData(
ec->pChipInstance,
&fDebugGetData );
if (ulResult != cOCT6100_ERR_OK){
DEBUG_ERROR(
"ERROR: %s: Failed to get debug data for ec channel %d (err=0x%X)\n",
ec->name,
ec->DebugChannel,
ulResult);
return -EINVAL;
}
chan_monitor->data_len = fDebugGetData.ulValidNumBytes;
chan_monitor->remain_len= fDebugGetData.ulRemainingNumBytes;
//chan_monitor->fe_chan = ec->DebugChannel;
chan_monitor->fe_chan = wanec_ec2fe_channel(ec, ec->DebugChannel, NULL);
if (fDebugGetData.ulRemainingNumBytes == 0){
/* Last read */
ec->ulDebugChannelHndl = cOCT6100_INVALID_HANDLE;
}
return 0;
}
static PUINT32 wanec_search_bufferindex(wan_ec_t *ec, UINT32 index)
{
UINT32 i = 0;
while(i < ec->f_OpenChip.ulMaxPlayoutBuffers){
if (ec->pToneBufferIndexes[i] == index){
return &ec->pToneBufferIndexes[i];
}
i++;
}
return NULL;
}
int wanec_BufferLoad(wan_ec_dev_t *ec_dev, wanec_buffer_config_t *buffer_config, int verbose)
{
wan_ec_t *ec;
tOCT6100_BUFFER_LOAD BufferLoad;
UINT32 size, ulResult, pcmlaw = WAN_EC_PCM_U_LAW;
PUINT8 pData = NULL;
int err;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
pcmlaw = (buffer_config->pcmlaw) ? buffer_config->pcmlaw : WAN_EC_PCM_U_LAW;
PRINT2(verbose,
"%s: Loading Tone buffer (%s) law=%s into Echo Canceller Chip ...\n",
ec->name,
buffer_config->buffer,
WAN_EC_DECODE_PCM_LAW(pcmlaw));
size = buffer_config->size * sizeof(INT8);
pData = wan_vmalloc(size);
if (pData == NULL){
DEBUG_ERROR(
"ERROR: %s: Failed to allocate memory for buffer!\n",
ec->name);
return -EINVAL;
}
err = WAN_COPY_FROM_USER(pData, buffer_config->data, size);
if (err){
DEBUG_ERROR(
"ERROR: %s: Failed to copy EC buffer from user space [%s:%d]!\n",
ec->name,
__FUNCTION__,__LINE__);
wan_vfree(pData);
return -EINVAL;
}
Oct6100BufferPlayoutLoadDef( &BufferLoad );
BufferLoad.pulBufferIndex = wanec_search_bufferindex(ec, cOCT6100_INVALID_VALUE);
/* FIXME: Can be alaw/mulaw */
BufferLoad.ulBufferPcmLaw = (pcmlaw == WAN_EC_PCM_U_LAW) ?
cOCT6100_PCM_U_LAW : cOCT6100_PCM_A_LAW;
BufferLoad.pbyBufferPattern = pData;
BufferLoad.ulBufferSize = size;
ulResult = Oct6100BufferPlayoutLoad (
ec->pChipInstance,
&BufferLoad);
if ( ulResult != cOCT6100_ERR_OK ){
if (ulResult == cOCT6100_ERR_BUFFER_PLAYOUT_ALL_BUFFERS_OPEN){
goto buffer_load_done;
}
DEBUG_ERROR(
"%s: ERROR: Failed to load buffer into EC Chip (err=0x%X)\n",
ec->name, ulResult);
wan_vfree(pData);
return -EINVAL;
}
buffer_load_done:
wan_vfree(pData);
buffer_config->buffer_index = *BufferLoad.pulBufferIndex;
PRINT2(verbose,
"%s: Current buffer index is %d\n",
ec->name, buffer_config->buffer_index);
return 0;
}
int wanec_BufferUnload(wan_ec_dev_t *ec_dev, wanec_buffer_config_t *buffer_config, int verbose)
{
wan_ec_t *ec;
tOCT6100_BUFFER_UNLOAD BufferUnload;
PUINT32 pBufferIndex = NULL;
UINT32 index = 0, ulResult;
WAN_ASSERT(ec_dev == NULL);
WAN_ASSERT(ec_dev->ec == NULL);
ec = ec_dev->ec;
PRINT2(verbose,
"%s: Unloading buffer from EC chip ...\n",
ec->name);
try_next_index:
Oct6100BufferPlayoutUnloadDef( &BufferUnload );
if (buffer_config->buffer_index != cOCT6100_INVALID_VALUE){
pBufferIndex = wanec_search_bufferindex(ec, buffer_config->buffer_index);
if (pBufferIndex == NULL){
DEBUG_ERROR(
"ERROR: %s: Invalid buffer index %X!\n",
ec->name, buffer_config->buffer_index);
return EINVAL;
}
}else{
if (index > ec->f_OpenChip.ulMaxPlayoutBuffers){
goto buffer_unload_done;
}
if (ec->pToneBufferIndexes[index] == cOCT6100_INVALID_VALUE){
index++;
goto try_next_index;
}
pBufferIndex = &ec->pToneBufferIndexes[index];
}
BufferUnload.ulBufferIndex = *pBufferIndex;
ulResult = Oct6100BufferPlayoutUnload (
ec->pChipInstance,
&BufferUnload);
if ( ulResult != cOCT6100_ERR_OK ){
if (ulResult == cOCT6100_ERR_BUFFER_PLAYOUT_NOT_OPEN){
goto buffer_unload_done;
}
DEBUG_ERROR(
"ERROR: %s: Failed to unload buffer from EC Chip (err=0x%X)!\n",
ec->name, (unsigned int)ulResult);
return EINVAL;
}
*pBufferIndex = cOCT6100_INVALID_VALUE;
if (!buffer_config->buffer_index){
index++;
goto try_next_index;
}
buffer_unload_done:
return 0;
}
int wanec_BufferPlayoutAdd(wan_ec_t *ec, int channel, wanec_playout_t *playout, int verbose)
{
tOCT6100_BUFFER_PLAYOUT_ADD BufferPlayoutAdd;
UINT32 ulResult;
PRINT2(verbose,
"%s: Add Tone buffer to ec channel %d port %s duration %d:%d...\n",
ec->name,
channel,
WAN_EC_DECODE_CHANNEL_PORT(playout->port),
playout->duration,
playout->repeat_cnt);
if (playout->index == cOCT6100_INVALID_VALUE||
wanec_search_bufferindex(ec, playout->index) == NULL){
DEBUG_ERROR(
"ERROR: %s: Invalid playout buffer index for ec channel %d!\n",
ec->name, channel);
return -EINVAL;
}
Oct6100BufferPlayoutAddDef( &BufferPlayoutAdd );
if (playout->repeat_cnt == 1){
BufferPlayoutAdd.fRepeat = FALSE;
}else{
BufferPlayoutAdd.fRepeat = TRUE;
}
BufferPlayoutAdd.ulPlayoutPort =
(playout->port == WAN_EC_CHANNEL_PORT_ROUT) ?
cOCT6100_CHANNEL_PORT_ROUT :
cOCT6100_CHANNEL_PORT_SOUT;
BufferPlayoutAdd.ulMixingMode = cOCT6100_MIXING_MUTE;
BufferPlayoutAdd.ulChannelHndl = ec->pEchoChannelHndl[channel];
BufferPlayoutAdd.ulBufferIndex = playout->index;
BufferPlayoutAdd.fRepeat = (playout->repeat_cnt) ? TRUE : FALSE;
BufferPlayoutAdd.ulRepeatCount = playout->repeat_cnt;
BufferPlayoutAdd.ulDuration = (playout->duration) ?
playout->duration : cOCT6100_INVALID_VALUE;
BufferPlayoutAdd.ulBufferLength = (playout->buffer_length) ?
playout->buffer_length :
cOCT6100_AUTO_SELECT;
ulResult = Oct6100BufferPlayoutAdd(
ec->pChipInstance,
&BufferPlayoutAdd);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to add playout buffer to ec channel %d (err=%08X)\n",
ec->name, channel, ulResult);
return -EINVAL;
}
return 0;
}
int wanec_BufferPlayoutStart(wan_ec_t *ec, int channel, wanec_playout_t *playout, int verbose)
{
tOCT6100_BUFFER_PLAYOUT_START BufferPlayoutStart;
UINT32 ulResult;
PRINT2(verbose,
"%s: Active playout buffer on ec channel %d port %s ...\n",
ec->name,
channel,
WAN_EC_DECODE_CHANNEL_PORT(playout->port));
Oct6100BufferPlayoutStartDef( &BufferPlayoutStart );
BufferPlayoutStart.ulChannelHndl = ec->pEchoChannelHndl[channel];
BufferPlayoutStart.ulPlayoutPort =
(playout->port == WAN_EC_CHANNEL_PORT_ROUT) ?
cOCT6100_CHANNEL_PORT_ROUT :
cOCT6100_CHANNEL_PORT_SOUT;
BufferPlayoutStart.fNotifyOnPlayoutStop = playout->notifyonstop;
BufferPlayoutStart.ulUserEventId = playout->user_event_id;
ulResult = Oct6100BufferPlayoutStart(
ec->pChipInstance,
&BufferPlayoutStart);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to active playout buffer on ec channel %d (err=%08X)\n",
ec->name,
channel,
ulResult);
return -EINVAL;
}
return 0;
}
int wanec_BufferPlayoutStop(wan_ec_t *ec, int channel, wanec_playout_t *playout, int verbose)
{
tOCT6100_BUFFER_PLAYOUT_STOP BufferPlayoutStop;
UINT32 ulResult;
PRINT2(verbose,
"%s: Deactive playout buffer on ec channel %d port %s...\n",
ec->name,
channel,
WAN_EC_DECODE_CHANNEL_PORT(playout->port));
Oct6100BufferPlayoutStopDef( &BufferPlayoutStop );/* set default values */
BufferPlayoutStop.fStopCleanly = FALSE; /* DavidR: set to FALSE, following advice from Sebastien Trottier,
* bug 6353, February 28, 2011. */
BufferPlayoutStop.ulChannelHndl = ec->pEchoChannelHndl[channel];
BufferPlayoutStop.ulPlayoutPort =
(playout->port == WAN_EC_CHANNEL_PORT_ROUT) ?
cOCT6100_CHANNEL_PORT_ROUT :
cOCT6100_CHANNEL_PORT_SOUT;
ulResult = Oct6100BufferPlayoutStop(
ec->pChipInstance,
&BufferPlayoutStop);
if ( ulResult != cOCT6100_ERR_OK ){
if (ulResult != cOCT6100_ERR_BUFFER_PLAYOUT_NOT_STARTED){
DEBUG_ERROR(
"ERROR: %s: Failed to deactive playout buffer on ec channel %d (err=%08X)\n",
ec->name,
channel,
ulResult);
return -EINVAL;
}
}
return 0;
}
/******************************************************************************
** CONFERENCE BRIDGE FUNCTIONS
******************************************************************************/
int wanec_ConfBridgeOpen(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int verbose)
{
tOCT6100_CONF_BRIDGE_OPEN ConfBridgeOpen;
UINT32 ulResult;
PRINT2(verbose,
"%s: Opening Conference Bridge...\n", ec->name);
if ((unsigned int)ec->confbridges_no >= ec->f_OpenChip.ulMaxConfBridges){
DEBUG_ERROR(
"ERROR: %s: Trying to open too many conference bridges (%d:%d)\n",
ec->name,
ec->confbridges_no,
ec->f_OpenChip.ulMaxConfBridges);
return -EINVAL;
}
Oct6100ConfBridgeOpenDef( &ConfBridgeOpen );
ConfBridgeOpen.pulConfBridgeHndl = &confbridge->ulHndl;
ConfBridgeOpen.fFlexibleConferencing = FALSE;
ulResult = Oct6100ConfBridgeOpen(
ec->pChipInstance,
&ConfBridgeOpen);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to open new conference bridge (err=%08X)\n",
ec->name,
ulResult);
return -EINVAL;
}
return 0;
}
int wanec_ConfBridgeClose(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int verbose)
{
tOCT6100_CONF_BRIDGE_CLOSE ConfBridgeClose;
UINT32 ulResult;
PRINT2(verbose,
"%s: Closing Conference Bridge...\n", ec->name);
Oct6100ConfBridgeCloseDef( &ConfBridgeClose );
ConfBridgeClose.ulConfBridgeHndl = confbridge->ulHndl;
ulResult = Oct6100ConfBridgeClose(
ec->pChipInstance,
&ConfBridgeClose);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to close conference bridge (%X, err=%08X)\n",
ec->name,
confbridge->ulHndl,
ulResult);
return -EINVAL;
}
return 0;
}
int wanec_ConfBridgeChanAdd(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, int verbose)
{
tOCT6100_CONF_BRIDGE_CHAN_ADD ConfBridgeChanAdd;
UINT32 ulResult;
PRINT2(verbose,
"%s: Add channel %d to Conference Bridge %X...\n",
ec->name, channel, confbridge->ulHndl);
Oct6100ConfBridgeChanAddDef( &ConfBridgeChanAdd );
ConfBridgeChanAdd.ulConfBridgeHndl = confbridge->ulHndl;
ConfBridgeChanAdd.ulChannelHndl = ec->pEchoChannelHndl[channel];
ulResult = Oct6100ConfBridgeChanAdd(
ec->pChipInstance,
&ConfBridgeChanAdd);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to add channel %d to conference bridge (%X, err=%08X)\n",
ec->name, channel,
confbridge->ulHndl,
ulResult);
return -EINVAL;
}
return 0;
}
int wanec_ConfBridgeChanRemove(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, int verbose)
{
tOCT6100_CONF_BRIDGE_CHAN_REMOVE ConfBridgeChanRemove;
UINT32 ulResult;
PRINT2(verbose,
"%s: Remove channel %d from Conference Bridge %X...\n",
ec->name, channel, confbridge->ulHndl);
Oct6100ConfBridgeChanRemoveDef( &ConfBridgeChanRemove );
ConfBridgeChanRemove.ulConfBridgeHndl = confbridge->ulHndl;
ConfBridgeChanRemove.ulChannelHndl = ec->pEchoChannelHndl[channel];
ulResult = Oct6100ConfBridgeChanRemove(
ec->pChipInstance,
&ConfBridgeChanRemove);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to remove channel %d from conference bridge (%X, err=%08X)\n",
ec->name, channel,
confbridge->ulHndl,
ulResult);
return -EINVAL;
}
return 0;
}
int wanec_ConfBridgeChanMute(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, int verbose)
{
tOCT6100_CONF_BRIDGE_CHAN_MUTE ConfBridgeChanMute;
UINT32 ulResult;
PRINT2(verbose,
"%s: Mute channel %d on a conference bridge %X...\n",
ec->name, channel, confbridge->ulHndl);
Oct6100ConfBridgeChanMuteDef( &ConfBridgeChanMute );
ConfBridgeChanMute.ulChannelHndl = ec->pEchoChannelHndl[channel];
ulResult = Oct6100ConfBridgeChanMute(
ec->pChipInstance,
&ConfBridgeChanMute);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to mute channel %d on a conference bridge (%X, err=%08X)\n",
ec->name, channel,
confbridge->ulHndl,
ulResult);
return -EINVAL;
}
return 0;
}
int wanec_ConfBridgeChanUnMute(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, int verbose)
{
tOCT6100_CONF_BRIDGE_CHAN_UNMUTE ConfBridgeChanUnMute;
UINT32 ulResult;
PRINT2(verbose,
"%s: UnMute channel %d on a Conference Bridge %X...\n",
ec->name, channel, confbridge->ulHndl);
Oct6100ConfBridgeChanUnMuteDef( &ConfBridgeChanUnMute );
ConfBridgeChanUnMute.ulChannelHndl = ec->pEchoChannelHndl[channel];
ulResult = Oct6100ConfBridgeChanUnMute(
ec->pChipInstance,
&ConfBridgeChanUnMute);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to unmute channel %d from conference bridge (%X, err=%08X)\n",
ec->name, channel,
confbridge->ulHndl,
ulResult);
return -EINVAL;
}
return 0;
}
int wanec_ConfBridgeDominantSpeakerSet(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, int enable, int verbose)
{
tOCT6100_CONF_BRIDGE_DOMINANT_SPEAKER_SET ConfBridgeDominantSpeaker;
UINT32 ulResult;
PRINT2(verbose,
"%s: %s Dominant speaker (channel %d) to a Conference Bridge %X...\n",
ec->name,
(enable) ? "Enable":"Disable",
channel,
confbridge->ulHndl);
Oct6100ConfBridgeDominantSpeakerSetDef( &ConfBridgeDominantSpeaker );
ConfBridgeDominantSpeaker.ulConfBridgeHndl = confbridge->ulHndl;
if (enable){
ConfBridgeDominantSpeaker.ulChannelHndl = ec->pEchoChannelHndl[channel];
}else{
ConfBridgeDominantSpeaker.ulChannelHndl = cOCT6100_CONF_NO_DOMINANT_SPEAKER_HNDL;
}
ulResult = Oct6100ConfBridgeDominantSpeakerSet(
ec->pChipInstance,
&ConfBridgeDominantSpeaker);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to %s dominant speaker to conference bridge (%X, err=%08X)\n",
ec->name,
(enable) ? "enable" : "disable",
confbridge->ulHndl,
ulResult);
return -EINVAL;
}
return 0;
}
int wanec_ConfBridgeMaskChange(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int channel, UINT32 mask, int verbose)
{
tOCT6100_CONF_BRIDGE_MASK_CHANGE ConfBridgeMaskChange;
UINT32 ulResult;
PRINT2(verbose,
"%s: Changing the listener (channel=%d) mask of bridge participant (%d)...\n",
ec->name,
channel, confbridge->ulHndl);
Oct6100ConfBridgeMaskChangeDef( &ConfBridgeMaskChange );
ConfBridgeMaskChange.ulChannelHndl = ec->pEchoChannelHndl[channel];
ConfBridgeMaskChange.ulNewListenerMask = mask;
ulResult = Oct6100ConfBridgeMaskChange(
ec->pChipInstance,
&ConfBridgeMaskChange);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to change the listener mask of bridge participant %d (err=%X)!\n",
ec->name,
channel,
ulResult);
return -EINVAL;
}
return 0;
}
int wanec_ConfBridgeGetStats(wan_ec_t *ec, wan_ec_confbridge_t *confbridge, int verbose)
{
tOCT6100_CONF_BRIDGE_STATS ConfBridgeStats;
UINT32 ulResult;
PRINT2(verbose,
"%s: Getting bridge statistics %X...\n",
ec->name, confbridge->ulHndl);
Oct6100ConfBridgeGetStatsDef( &ConfBridgeStats );
ConfBridgeStats.ulConfBridgeHndl = confbridge->ulHndl;
ulResult = Oct6100ConfBridgeGetStats(
ec->pChipInstance,
&ConfBridgeStats);
if ( ulResult != cOCT6100_ERR_OK ){
DEBUG_ERROR(
"ERROR: %s: Failed to get conference bridge statistics (err=%X)!\n",
ec->name,
ulResult);
return -EINVAL;
}
return 0;
}
/*===========================================================================*\
Oct6100Read
\*===========================================================================*/
static int
wan_ec_read(wan_ec_dev_t *ec_dev, u32 read_addr, u16 *read_data)
{
u32 data;
wan_ec_read_internal_dword(ec_dev, read_addr, &data);
*read_data = (u16)(data & 0xFFFF);
return 0;
}
/*===========================================================================*\
Oct6100Write
\*===========================================================================*/
static int
wan_ec_write(wan_ec_dev_t *ec_dev, u32 write_addr, u32 write_data)
{
return wan_ec_write_internal_dword(ec_dev, write_addr, write_data);
}
/*===========================================================================*\
Oct6100WriteSequenceSub
\*===========================================================================*/
static u32
wan_ec_write_seq(wan_ec_dev_t *ec_dev, u32 write_addr, u16 write_data)
{
u32 ulResult;
u32 ulData;
u16 usData;
u32 ulWordAddress;
u32 i;
/* Create the word address from the provided byte address. */
ulWordAddress = write_addr >> 1;
/* 16-bit indirect access. */
/* First write to the address indirection registers. */
ulData = ( ulWordAddress >> 19 ) & 0x1FFF;
ulResult = wan_ec_write( ec_dev, 0x8, ulData );
if (ulResult)
return ulResult;
ulData = ( ulWordAddress >> 3 ) & 0xFFFF;
ulResult = wan_ec_write( ec_dev, 0xA, ulData );
if (ulResult)
return ulResult;
/* Next, write data word to read/write data registers. */
ulData = write_data & 0xFFFF;
ulResult = wan_ec_write( ec_dev, 0x4, ulData );
if ( ulResult )
return ulResult;
/* Write the parities and write enables, as well as last three bits
** of wadd and request the write access. */
ulData = ( ( 0x0 & 0x3 ) << 14 ) | ( ( 0x3 & 0x3 ) << 12 ) | ( ( ulWordAddress & 0x7 ) << 9 ) | 0x0100;
ulResult = wan_ec_write( ec_dev, 0x0, ulData );
if ( ulResult )
return ulResult;
/* Keep polling register contol0 for the access_req bit to go low. */
for ( i = 0; i < WANEC_READ_LIMIT; i++ )
{
ulResult = wan_ec_read( ec_dev, 0, &usData );
if ( ulResult )
return ulResult;
if ( ( ( usData >> 8 ) & 0x1 ) == 0x0 )
break;
}
if ( i == WANEC_READ_LIMIT ){
DEBUG_ERROR("%s: Error: EC write command reached re-try limit!\n",
ec_dev->name);
return WAN_EC_RC_CPU_INTERFACE_NO_RESPONSE;
}
return 0;
}
/*===========================================================================*\
HandleReqWriteOct6100
\*===========================================================================*/
u32 wanec_req_write(void *arg, u32 write_addr, u16 write_data)
{
wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg;
u32 ulResult;
DEBUG_TEST("%s: EC WRITE API addr=%X data=%X\n",
ec_dev->ec->name, write_addr, write_data);
ulResult = wan_ec_write_seq(ec_dev, write_addr, write_data);
if (ulResult){
DEBUG_ERROR("%s: Error: Failed to write %04X to addr %08X\n",
ec_dev->name,
write_addr,
write_data);
}
return ulResult;
}
/*===========================================================================*\
HandleReqWriteSmearOct6100
\*===========================================================================*/
u32 wanec_req_write_smear(void *arg, u32 addr, u16 data, u32 len)
{
wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg;
u32 i, ulResult = WAN_EC_RC_OK;
WAN_ASSERT(ec_dev == NULL);
for ( i = 0; i < len; i++ ){
ulResult = wan_ec_write_seq(ec_dev, addr + (i*2), data);
if (ulResult){
DEBUG_ERROR("%s: Error: Failed to write %04X to addr %08X\n",
ec_dev->name,
addr + (i*2),
data);
break;
}
}
return ulResult;
}
/*===========================================================================*\
HandleReqWriteBurstOct6100
\*===========================================================================*/
u32 wanec_req_write_burst(void *arg, u32 addr, u16 *data, u32 len)
{
wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg;
u32 i, ulResult = WAN_EC_RC_OK;
WAN_ASSERT(ec_dev == NULL);
for ( i = 0; i < len; i++ ){
ulResult = wan_ec_write_seq(ec_dev, addr + (i * 2), data[i]);
if (ulResult){
DEBUG_ERROR("%s: Error: Failed to write %04X to addr %08X\n",
ec_dev->name,
addr + (i*2),
data[i]);
break;
}
}
return ulResult;
}
/*===========================================================================*\
Oct6100ReadSequenceSub
\*===========================================================================*/
static u32
wan_ec_read_seq(wan_ec_dev_t *ec_dev, u32 read_addr, u16 *read_data, u32 read_len)
{
u32 ulResult;
u32 ulData;
u32 ulWordAddress;
u32 ulReadBurstLength;
u16 usData;
u32 i;
/* Create the word address from the provided byte address. */
ulWordAddress = read_addr >> 1;
/* Indirect accesses. */
/* First write to the address indirection registers. */
ulData = ( ulWordAddress >> 19 ) & 0x1FFF;
ulResult = wan_ec_write( ec_dev, 0x8, ulData );
if (ulResult)
return ulResult;
ulData = ( ulWordAddress >> 3 ) & 0xFFFF;
ulResult = wan_ec_write( ec_dev, 0xA, ulData );
if (ulResult)
return ulResult;
/* Request access. */
if ( read_len >= 128 )
{
ulData = 0x100 | ( ( ulWordAddress & 0x7 ) << 9);
ulReadBurstLength = 0;
}
else
{
ulData = 0x100 | ( ( ulWordAddress & 0x7 ) << 9) | read_len;
ulReadBurstLength = read_len;
}
ulResult = wan_ec_write( ec_dev, 0x0, ulData );
if (ulResult)
return ulResult;
/* Keep polling register contol0 for the access_req bit to go low. */
for ( i = 0; i < WANEC_READ_LIMIT; i++ )
{
ulResult = wan_ec_read( ec_dev, 0x0, &usData );
if (ulResult)
return ulResult;
if ( ( ( usData >> 8 ) & 0x1 ) == 0x0 )
break;
}
if ( i == WANEC_READ_LIMIT ){
DEBUG_ERROR("%s: Error: EC read command reached re-try limit!\n",
ec_dev->name);
return WAN_EC_RC_CPU_INTERFACE_NO_RESPONSE;
}
if ( ( usData & 0xFF ) == 0x1 )
{
i = 0;
}
/* Retrieve read data. */
ulResult = wan_ec_read( ec_dev, 0x4, &usData );
if (ulResult)
return ulResult;
if ( ( usData & 0xFF ) == 0x1 )
{
i = 0;
}
*read_data = usData;
return 0;
}
u32 wanec_req_read(void *arg, u32 addr, u16 *data)
{
wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg;
u32 ulResult;
WAN_ASSERT(ec_dev == NULL);
DEBUG_TEST("%s: EC READ API addr=%X data=????\n",
ec_dev->ec->name, addr);
ulResult = wan_ec_read_seq(
ec_dev,
addr,
data,
1);
if (ulResult){
DEBUG_ERROR("%s: Error: Failed to read data from addr %08X\n",
ec_dev->name,
addr);
if (ec_dev->ec){
wan_set_bit(WAN_EC_BIT_CRIT_ERROR, &ec_dev->ec->critical);
}
}
DEBUG_TEST("%s: EC READ API addr=%X data=%X\n",
ec_dev->ec->name,
addr, *data);
return ulResult;
}
u32 wanec_req_read_burst(void *arg, u32 addr, u16 *data, u32 len)
{
wan_ec_dev_t *ec_dev = (wan_ec_dev_t*)arg;
u32 i, ulResult = WAN_EC_RC_OK;
u16 read_data;
for ( i = 0; i < len; i++ ){
ulResult = wan_ec_read_seq(ec_dev, addr, &read_data, 1);
if (ulResult){
DEBUG_EVENT("%s: Failed to read from addr %X\n",
ec_dev->name,
addr);
if (ec_dev->ec){
wan_set_bit(WAN_EC_BIT_CRIT_ERROR, &ec_dev->ec->critical);
}
break;
}
data[i] = (u16)read_data;
addr += 2;
}
return ulResult;
}