wanpipe/patches/kdrivers/src/net/sdla_remora_tdmv.c

1703 lines
47 KiB
C

/***************************************************************************
* sdla_remora_tdmv.c WANPIPE(tm) Multiprotocol WAN Link Driver.
* AFT REMORA and FXO/FXS support module.
*
* Author: Alex Feldman <al.feldman@sangoma.com>
*
* Copyright: (c) 2005 Sangoma Technologies Inc.
*
* 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.
* ============================================================================
* Oct 6, 2005 Alex Feldman Initial version.
* Sep 06, 2008 Moises Silva DAHDI support.
******************************************************************************
*/
/*******************************************************************************
** INCLUDE FILES
*******************************************************************************/
# include "wanpipe_includes.h"
# include "wanpipe_defines.h"
# include "wanpipe_debug.h"
# include "wanpipe_abstr.h"
# include "wanpipe_common.h"
# include "wanpipe_events.h"
# include "wanpipe.h"
# include "wanpipe_events.h"
# include "if_wanpipe_common.h" /* for 'wanpipe_common_t' used in 'aft_core.h'*/
# include "sdla_remora.h"
# include "sdla_remora_analog.h"
# include "sdla_remora_tdmv.h"
#if !defined (__WINDOWS__)
# include "zapcompat.h" /* Map of Zaptel -> DAHDI definitions */
# include "wanpipe_dahdi_abstr.h" /* Map of Zaptel -> DAHDI definitions */
#endif
#if 0
#ifdef DEBUG_TEST
#undef DEBUG_TEST
#define DEBUG_TEST DEBUG_EVENT
#endif
#endif
/*******************************************************************************
** DEFINES AND MACROS
*******************************************************************************/
#if 0
# define SPI2STEP
#endif
/* The constants below control the 'debounce' periods enforced by the
** check_hook routines; these routines are called once every 4 interrupts
** (the interrupt cycles around the four modules), so the periods are
** specified in _4 millisecond_ increments
*/
#define RING_DEBOUNCE 16 /* Ringer Debounce (64 ms) */
/* Interrupt flag enable */
#if 0
# define WAN_REMORA_FXS_LCIP
#endif
#if 0
# define WAN_REMORA_FXS_DTMF
#endif
/* flags bits */
#define WP_TDMV_REGISTER 1 /*0x01*/
#define WP_TDMV_RUNNING 2 /*0x02*/
#define WP_TDMV_UP 3 /*0x04*/
#define IS_TDMV_RUNNING(wr) wan_test_bit(WP_TDMV_RUNNING, &(wr)->flags)
#define IS_TDMV_UP(wr) wan_test_bit(WP_TDMV_UP, &(wr)->flags)
#define IS_TDMV_UP_RUNNING(wr) (IS_TDMV_UP(wr) && IS_TDMV_RUNNING(wr))
#define wp_fax_tone_timeout_set(wr,chan) do { DEBUG_TEST("%s:%d: s%dc%d fax timeout set\n", \
__FUNCTION__,__LINE__, \
wr->spanno+1,chan+1); \
wr->ec_fax_detect_timeout[chan]=SYSTEM_TICKS; } while(0);
/*******************************************************************************
** GLOBAL VARIABLES
*******************************************************************************/
static int wp_remora_no = 0;
extern WAN_LIST_HEAD(, wan_tdmv_) wan_tdmv_head;
/*******************************************************************************
** FUNCTION PROTOTYPES
*******************************************************************************/
static int wp_tdmv_remora_check_mtu(void* pcard, unsigned long timeslot_map, int *mtu);
static int wp_tdmv_remora_create(void* pcard, wan_tdmv_conf_t*);
static int wp_tdmv_remora_remove(void* pcard);
static int wp_tdmv_remora_reg(void* pcard, wan_tdmv_if_conf_t*, unsigned int, unsigned char,netdevice_t*);
static int wp_tdmv_remora_unreg(void* pcard, unsigned long ts_map);
static int wp_tdmv_remora_software_init(wan_tdmv_t *wan_tdmv);
static int wp_tdmv_remora_state(void* pcard, int state);
static int wp_tdmv_remora_running(void* pcard);
static int wp_tdmv_remora_is_rbsbits(wan_tdmv_t *wan_tdmv);
static int wp_tdmv_remora_rx_tx_span(void *pcard);
static int wp_tdmv_remora_rx_chan(wan_tdmv_t*, int,unsigned char*,unsigned char*);
static int wp_tdmv_remora_ec_span(void *pcard);
#ifdef DAHDI_25
static int wp_remora_chanconfig(struct file *file, struct zt_chan *chan, int sigtype);
#else
static int wp_remora_chanconfig(struct zt_chan *chan, int sigtype);
#endif
static int wp_remora_zap_open(struct zt_chan *chan);
static int wp_remora_zap_close(struct zt_chan *chan);
static int wp_remora_zap_hooksig(struct zt_chan *chan, zt_txsig_t txsig);
static int wp_remora_zap_watchdog(struct zt_span *span, int event);
#if defined(__FreeBSD__) || defined(__OpenBSD__)
static int wp_remora_zap_ioctl(struct zt_chan *chan, unsigned int cmd, caddr_t data);
#else
static int wp_remora_zap_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data);
#endif
static void wp_tdmv_remora_tone (void* card_id, wan_event_t *event);
#ifdef DAHDI_22
static int wp_tdmv_remora_hwec_create(struct dahdi_chan *chan,
struct dahdi_echocanparams *ecp,
struct dahdi_echocanparam *p,
struct dahdi_echocan_state **ec);
static void wp_tdmv_remora_hwec_free(struct dahdi_chan *chan,
struct dahdi_echocan_state *ec);
#endif
#ifdef DAHDI_25
static const char *wp_tdmv_remora_hwec_name(const struct zt_chan *chan);
#endif
#if 0
#define WAN_SYNC_RX_TX_TEST 1
#warning "WAN_SYNC_RX_TX_TEST: Test option Enabled"
static int wp_tdmv_remora_rx_chan_sync_test(sdla_t *card, wp_tdmv_remora_t *wr, int channo,
unsigned char *rxbuf,
unsigned char *txbuf);
#else
#undef WAN_SYNC_RX_TX_TEST
#endif
#if defined(DAHDI_24) || defined(DAHDI_25)
static const struct dahdi_span_ops wp_tdm_span_ops = {
.owner = THIS_MODULE,
.chanconfig = wp_remora_chanconfig,
.open = wp_remora_zap_open,
.close = wp_remora_zap_close,
.ioctl = wp_remora_zap_ioctl,
.hooksig = wp_remora_zap_hooksig,
.watchdog = wp_remora_zap_watchdog,
#if 0
/* FIXME: Add native bridging */
.dacs = ,
#endif
.echocan_create = wp_tdmv_remora_hwec_create,
#ifdef DAHDI_25
.echocan_name = wp_tdmv_remora_hwec_name,
#endif
};
#endif
#ifdef DAHDI_22
/*
*******************************************************************************
** DAHDI HWEC STRUCTURES
*******************************************************************************
*/
static const struct dahdi_echocan_features wp_tdmv_remora_ec_features = {
.NLP_automatic = 1,
.CED_tx_detect = 1,
.CED_rx_detect = 1,
};
static const struct dahdi_echocan_ops wp_tdmv_remora_ec_ops = {
#ifndef DAHDI_25
/* This option is used on dahdi 2.4 or lower */
.name = "WANPIPE_HWEC",
#endif
.echocan_free = wp_tdmv_remora_hwec_free,
};
#endif
/*******************************************************************************
** FUNCTION DEFINITIONS
*******************************************************************************/
#if defined(__FreeBSD__) || defined(__OpenBSD__)
static int wp_remora_zap_ioctl(struct zt_chan *chan, unsigned int cmd, caddr_t data)
#else
static int wp_remora_zap_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
#endif
{
wp_tdmv_remora_t *wr;
sdla_t *card = NULL;
sdla_fe_t *fe = NULL;
wan_event_ctrl_t *event_ctrl = NULL;
int x, err;
wr = WP_PRIV_FROM_CHAN(chan,wp_tdmv_remora_t);
WAN_ASSERT2(wr == NULL, -ENODEV);
WAN_ASSERT(wr->card == NULL);
card = wr->card;
fe = &card->fe;
switch (cmd) {
case ZT_ONHOOKTRANSFER:
if (fe->rm_param.mod[chan->chanpos - 1].type != MOD_TYPE_FXS) {
return -EINVAL;
}
err = WAN_COPY_FROM_USER(&x, (int*)data, sizeof(int));
/*err = get_user(x, (int *)data);*/
if (err) return -EFAULT;
wr->mod[chan->chanpos - 1].fxs.ohttimer = x << 3;
if (fe->fe_cfg.cfg.remora.reversepolarity){
/* OHT mode when idle */
fe->rm_param.mod[chan->chanpos - 1].u.fxs.idletxhookstate = 0x6;
}else{
fe->rm_param.mod[chan->chanpos - 1].u.fxs.idletxhookstate = 0x2;
}
if (wr->mod[chan->chanpos - 1].fxs.lasttxhook == 0x1) {
/* Apply the change if appropriate */
if (fe->fe_cfg.cfg.remora.reversepolarity){
wr->mod[chan->chanpos - 1].fxs.lasttxhook = 0x6;
}else{
wr->mod[chan->chanpos - 1].fxs.lasttxhook = 0x2;
}
#if defined(REG_WRITE_SHADOW)
wr->mod[chan->chanpos-1].fxs.lasttxhook_update = 1;
#else
WRITE_RM_REG(chan->chanpos - 1, 64, wr->mod[chan->chanpos - 1].fxs.lasttxhook);
#endif
}
break;
case ZT_SETPOLARITY:
err = WAN_COPY_FROM_USER(&x, (int*)data, sizeof(int));
/*err = get_user(x, (int *)data);*/
if (err) return -EFAULT;
if (fe->rm_param.mod[chan->chanpos - 1].type != MOD_TYPE_FXS) {
return -EINVAL;
}
/* Can't change polarity while ringing or when open */
if ((wr->mod[chan->chanpos - 1].fxs.lasttxhook == 0x04) ||
(wr->mod[chan->chanpos - 1 ].fxs.lasttxhook == 0x00)){
return -EINVAL;
}
if ((x && !fe->fe_cfg.cfg.remora.reversepolarity) || (!x && fe->fe_cfg.cfg.remora.reversepolarity)){
wr->mod[chan->chanpos - 1].fxs.lasttxhook |= 0x04;
}else{
wr->mod[chan->chanpos - 1].fxs.lasttxhook &= ~0x04;
}
#if defined(REG_WRITE_SHADOW)
wr->mod[chan->chanpos-1].fxs.lasttxhook_update = 1;
#else
WRITE_RM_REG(chan->chanpos - 1, 64, wr->mod[chan->chanpos - 1].fxs.lasttxhook);
#endif
break;
case WAN_RM_SET_ECHOTUNE:
if (fe->rm_param.mod[chan->chanpos - 1].type == MOD_TYPE_FXO) {
err = WAN_COPY_FROM_USER(
&wr->mod[chan->chanpos-1].fxo.echoregs,
(struct wan_rm_echo_coefs*)data,
sizeof(struct wan_rm_echo_coefs));
if (err) return -EFAULT;
#if 1
wr->mod[chan->chanpos-1].fxo.echotune = 1;
#else
DEBUG_EVENT("%s: Module %d: Setting echo registers: \n",
wr->devname, chan->chanpos-1);
/* Set the ACIM register */
WRITE_RM_REG(chan->chanpos - 1, 30, echoregs.acim);
/* Set the digital echo canceller registers */
WRITE_RM_REG(chan->chanpos - 1, 45, echoregs.coef1);
WRITE_RM_REG(chan->chanpos - 1, 46, echoregs.coef2);
WRITE_RM_REG(chan->chanpos - 1, 47, echoregs.coef3);
WRITE_RM_REG(chan->chanpos - 1, 48, echoregs.coef4);
WRITE_RM_REG(chan->chanpos - 1, 49, echoregs.coef5);
WRITE_RM_REG(chan->chanpos - 1, 50, echoregs.coef6);
WRITE_RM_REG(chan->chanpos - 1, 51, echoregs.coef7);
WRITE_RM_REG(chan->chanpos - 1, 52, echoregs.coef8);
DEBUG_EVENT("%s: Module %d: Set echo registers successfully\n",
wr->devname, chan->chanpos-1);
#endif
break;
} else {
return -EINVAL;
}
break;
case ZT_TONEDETECT:
if (WAN_COPY_FROM_USER(&x, (int*)data, sizeof(int))){
return -EFAULT;
}
if (wr->tonesupport != WANOPT_YES || card->wandev.ec_dev == NULL){
return -ENOSYS;
}
DEBUG_TDMV("[TDMV_RM]: %s: HW Tone Detection %s on channel %d (%s)!\n",
wr->devname,
(x & ZT_TONEDETECT_ON) ? "ON" : "OFF", chan->chanpos - 1,
(x & ZT_TONEDETECT_MUTE) ? "Mute ON" : "Mute OFF");
if (x & ZT_TONEDETECT_ON){
wr->tonemask |= (1 << (chan->chanpos - 1));
}else{
wr->tonemask &= ~(1 << (chan->chanpos - 1));
}
if (x & ZT_TONEDETECT_MUTE){
wr->tonemutemask |= (1 << (chan->chanpos - 1));
}else{
wr->tonemutemask &= ~(1 << (chan->chanpos - 1));
}
#if defined(CONFIG_WANPIPE_HWEC)
event_ctrl = wan_malloc(sizeof(wan_event_ctrl_t));
if (event_ctrl==NULL){
DEBUG_EVENT(
"%s: Failed to allocate memory for event ctrl!\n",
wr->devname);
return -EFAULT;
}
event_ctrl->type = WAN_EVENT_EC_CHAN_MODIFY;
event_ctrl->channel = chan->chanpos-1;
event_ctrl->mode = (x & ZT_TONEDETECT_MUTE) ? WAN_EVENT_ENABLE : WAN_EVENT_DISABLE;
if (wanpipe_ec_event_ctrl(card->wandev.ec_dev, card, event_ctrl)){
wan_free(event_ctrl);
}
err = 0;
#else
err = -EINVAL;
#endif
break;
default:
return -ENOTTY;
break;
}
return 0;
}
static int wp_remora_zap_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
{
wp_tdmv_remora_t *wr;
sdla_t *card = NULL;
sdla_fe_t *fe = NULL;
wr = WP_PRIV_FROM_CHAN(chan,wp_tdmv_remora_t);
WAN_ASSERT2(wr == NULL, -ENODEV);
WAN_ASSERT(wr->card == NULL);
card = wr->card;
fe = &card->fe;
if (fe->rm_param.mod[chan->chanpos - 1].type == MOD_TYPE_FXO) {
/* XXX Enable hooksig for FXO XXX */
switch(txsig) {
case ZT_TXSIG_OFFHOOK:
wp_fax_tone_timeout_set(wr,(chan->chanpos-1));
/* Drop down */
case ZT_TXSIG_START:
DEBUG_TDMV("%s: Module %d: goes off-hook (txsig %d)\n",
wr->devname, chan->chanpos, txsig);
wr->mod[chan->chanpos - 1].fxo.offhook = 1;
#if defined(REG_WRITE_SHADOW)
fe->rm_param.reg0shadow[chan->chanpos-1] = 0x09;
fe->rm_param.reg0shadow_update[chan->chanpos-1] = 1;
#else
WRITE_RM_REG(chan->chanpos - 1, 5, 0x9);
#endif
break;
case ZT_TXSIG_ONHOOK:
DEBUG_TDMV("%s: Module %d: goes on-hook (txsig %d)\n",
wr->devname, chan->chanpos, txsig);
wr->mod[chan->chanpos - 1].fxo.offhook = 0;
#if defined(REG_WRITE_SHADOW)
fe->rm_param.reg0shadow[chan->chanpos-1] = 0x08;
fe->rm_param.reg0shadow_update[chan->chanpos-1] = 1;
#else
WRITE_RM_REG(chan->chanpos - 1, 5, 0x8);
#endif
break;
default:
DEBUG_TDMV("%s: Can't set tx state to %d (chan %d)\n",
wr->devname, txsig, chan->chanpos);
}
}else if (fe->rm_param.mod[chan->chanpos - 1].type == MOD_TYPE_FXS) {
switch(txsig) {
case ZT_TXSIG_ONHOOK:
DEBUG_TDMV("%s: Module %d: goes on-hook (txsig %d).\n",
wr->devname, chan->chanpos, txsig);
switch(chan->sig) {
case ZT_SIG_EM:
case ZT_SIG_FXOKS:
case ZT_SIG_FXOLS:
wr->mod[chan->chanpos-1].fxs.lasttxhook =
fe->rm_param.mod[chan->chanpos-1].u.fxs.idletxhookstate;
break;
case ZT_SIG_FXOGS:
wr->mod[chan->chanpos-1].fxs.lasttxhook = 3;
break;
}
break;
case ZT_TXSIG_OFFHOOK:
wp_fax_tone_timeout_set(wr,(chan->chanpos-1));
DEBUG_TDMV("%s: Module %d: goes off-hook (txsig %d).\n",
wr->devname, chan->chanpos, txsig);
switch(chan->sig) {
case ZT_SIG_EM:
wr->mod[chan->chanpos-1].fxs.lasttxhook = 5;
break;
default:
wr->mod[chan->chanpos-1].fxs.lasttxhook =
fe->rm_param.mod[chan->chanpos-1].u.fxs.idletxhookstate;
break;
}
break;
case ZT_TXSIG_START:
DEBUG_TDMV("%s: Module %d: txsig START (txsig %d).\n",
wr->devname, chan->chanpos, txsig);
wr->mod[chan->chanpos-1].fxs.lasttxhook = 4;
break;
case ZT_TXSIG_KEWL:
wr->mod[chan->chanpos-1].fxs.lasttxhook = 0;
break;
default:
DEBUG_EVENT("%s: Can't set tx state to %d\n",
wr->devname, txsig);
return 0;
break;
}
#if defined(REG_WRITE_SHADOW)
wr->mod[chan->chanpos-1].fxs.lasttxhook_update = 1;
#else
WRITE_RM_REG(chan->chanpos - 1, 64, wr->mod[chan->chanpos-1].fxs.lasttxhook);
#endif
}
return 0;
}
static int wp_remora_zap_open(struct zt_chan *chan)
{
wp_tdmv_remora_t *wr = NULL;
sdla_t *card = NULL;
WAN_ASSERT2(chan == NULL, -ENODEV);
wr = WP_PRIV_FROM_CHAN(chan,wp_tdmv_remora_t);
WAN_ASSERT2(wr == NULL, -ENODEV);
WAN_ASSERT2(wr->card == NULL, -ENODEV);
card = wr->card;
wr->usecount++;
wan_set_bit(WP_TDMV_RUNNING, &wr->flags);
wanpipe_open(card);
DEBUG_EVENT("%s: Open (usecount=%d, channo=%d, chanpos=%d)...\n",
wr->devname,
wr->usecount,
chan->channo,
chan->chanpos);
return 0;
}
static int wp_remora_zap_close(struct zt_chan *chan)
{
sdla_t *card = NULL;
wp_tdmv_remora_t* wr = NULL;
sdla_fe_t *fe = NULL;
WAN_ASSERT2(chan == NULL, -ENODEV);
wr = WP_PRIV_FROM_CHAN(chan,wp_tdmv_remora_t);
WAN_ASSERT2(wr == NULL, -ENODEV);
card = wr->card;
fe = &card->fe;
wr->usecount--;
wanpipe_close(card);
wan_clear_bit(WP_TDMV_RUNNING, &wr->flags);
#if 1
if (fe->rm_param.mod[chan->chanpos - 1].type == MOD_TYPE_FXS) {
if (fe->fe_cfg.cfg.remora.reversepolarity)
fe->rm_param.mod[chan->chanpos - 1].u.fxs.idletxhookstate = 5;
else
fe->rm_param.mod[chan->chanpos - 1].u.fxs.idletxhookstate = 1;
}
#endif
return 0;
}
static int wp_remora_zap_watchdog(struct zt_span *span, int event)
{
#if 0
printk("TDM: Restarting DMA\n");
wctdm_restart_dma(span->pvt);
#endif
return 0;
}
#ifdef DAHDI_25
/* This funciton is used for dahdi 2.5 or higher */
static const char *wp_tdmv_remora_hwec_name(const struct zt_chan *chan)
{
wp_tdmv_remora_t *wr = NULL;
sdla_t *card = NULL;
WAN_ASSERT2(chan == NULL, NULL);
wr = WP_PRIV_FROM_CHAN(chan,wp_tdmv_remora_t);
WAN_ASSERT2(wr == NULL, NULL);
WAN_ASSERT2(wr->card == NULL, NULL);
card = wr->card;
if (card->wandev.ec_enable && wr->hwec == WANOPT_YES){
return "WANPIPE_HWEC";
}
return NULL;
}
#endif
#ifdef DAHDI_22
/******************************************************************************
** wp_remora_zap_hwec() -
**
** OK
*/
static int wp_tdmv_remora_hwec_create(struct dahdi_chan *chan,
struct dahdi_echocanparams *ecp,
struct dahdi_echocanparam *p,
struct dahdi_echocan_state **ec)
{
wp_tdmv_remora_t *wr = NULL;
sdla_t *card = NULL;
int err = -ENODEV;
WAN_ASSERT2(chan == NULL, -ENODEV);
wr = WP_PRIV_FROM_CHAN(chan,wp_tdmv_remora_t);
WAN_ASSERT2(wr == NULL, -ENODEV);
WAN_ASSERT2(wr->card == NULL, -ENODEV);
card = wr->card;
if (ecp->param_count > 0) {
DEBUG_TDMV("[TDMV] Wanpipe echo canceller does not support parameters; failing request\n");
return -EINVAL;
}
*ec = &wr->ec[chan->chanpos - 1];
(*ec)->ops = &wp_tdmv_remora_ec_ops;
(*ec)->features = wp_tdmv_remora_ec_features;
wan_set_bit(chan->chanpos-1,&card->wandev.rtp_tap_call_map);
wp_fax_tone_timeout_set(wr,(chan->chanpos-1));
if (card->wandev.ec_enable && wr->hwec == WANOPT_YES){
/* The ec persist flag enables and disables
* persistent echo control. In persist mode
* echo cancellation is enabled regardless of
* asterisk. In persist mode off asterisk
* controls hardware echo cancellation */
if (card->hwec_conf.persist_disable) {
/* ec enable expects values starting from 1, zero is not
allowed, therefore we must use chan->chanpos because it
starts from 1 */
err = card->wandev.ec_enable(card, 1, chan->chanpos);
} else {
err = 0;
}
DEBUG_TDMV("[TDMV_RM]: %s: %s HW echo canceller on channel %d\n",
wr->devname,
/*(enable) ? "Enable" : "Disable",*/
(err==0) ? "Enable" : "Disable",
chan->chanpos);
}
return err;
}
/******************************************************************************
** wp_tdmv_remora_hwec_free() -
**
** OK
*/
static void wp_tdmv_remora_hwec_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec)
{
wp_tdmv_remora_t *wr = NULL;
sdla_t *card = NULL;
memset(ec, 0, sizeof(*ec));
if(chan == NULL) return;
wr = WP_PRIV_FROM_CHAN(chan,wp_tdmv_remora_t);
WAN_ASSERT_VOID(wr == NULL);
if(wr->card == NULL) return;
card = wr->card;
wan_clear_bit(chan->chanpos-1, &card->wandev.rtp_tap_call_map);
if (card->wandev.ec_enable && wr->hwec == WANOPT_YES) {
/* The ec persist flag enables and disables
* persistent echo control. In persist mode
* echo cancellation is enabled regardless of
* asterisk. In persist mode off asterisk
* controls hardware echo cancellation */
if (wr->ec_off_on_fax) {
DEBUG_EVENT("%s: Re-enabling hwec after fax chan=%i \n",card->devname,chan->chanpos);
card->wandev.ec_enable(card, 1, chan->chanpos);
wr->ec_off_on_fax=0;
} else {
if (card->hwec_conf.persist_disable) {
/* ec enable expects values starting from 1, zero is not
allowed, therefore we must use chan->chanpos because it
starts from 1 */
card->wandev.ec_enable(card, 0, chan->chanpos);
}
DEBUG_TDMV("[TDMV] %s: Disable HW echo canceller on channel %d\n",
wr->devname, chan->chanpos);
}
}
}
#else
/******************************************************************************
** wp_remora_zap_hwec() -
**
** OK
*/
static int wp_remora_zap_hwec(struct zt_chan *chan, int enable)
{
wp_tdmv_remora_t *wr = NULL;
sdla_t *card = NULL;
int err = -ENODEV;
WAN_ASSERT2(chan == NULL, -ENODEV);
wr = WP_PRIV_FROM_CHAN(chan,wp_tdmv_remora_t);
WAN_ASSERT2(wr == NULL, -ENODEV);
WAN_ASSERT2(wr->card == NULL, -ENODEV);
card = wr->card;
if (enable) {
wan_set_bit(chan->chanpos-1,&card->wandev.rtp_tap_call_map);
wp_fax_tone_timeout_set(wr,(chan->chanpos-1));
} else {
wan_clear_bit(chan->chanpos-1,&card->wandev.rtp_tap_call_map);
}
if (card->wandev.ec_enable && wr->hwec == WANOPT_YES){
/* The ec persist flag enables and disables
* persistent echo control. In persist mode
* echo cancellation is enabled regardless of
* asterisk. In persist mode off asterisk
* controls hardware echo cancellation */
if (!enable && wr->ec_off_on_fax) {
DEBUG_EVENT("%s: Re-enabling hwec after fax chan=%i \n",card->devname,chan->chanpos);
card->wandev.ec_enable(card, 1, chan->chanpos);
wr->ec_off_on_fax=0;
err=0;
} else {
if (card->hwec_conf.persist_disable) {
/* ec enable expects values starting from 1, zero is not
allowed, therefore we must use chan->chanpos because it
starts from 1 */
err = card->wandev.ec_enable(card, enable, chan->chanpos);
} else {
err = 0;
}
DEBUG_TDMV("[TDMV_RM]: %s: %s HW echo canceller on channel %d\n",
wr->devname,
(enable) ? "Enable" : "Disable",
chan->chanpos);
}
}
return err;
}
#endif
static int wp_tdmv_remora_hook(sdla_fe_t *fe, int mod_no, int off_hook)
{
sdla_t *card = fe->card;
wan_tdmv_t *wan_tdmv = NULL;
wp_tdmv_remora_t *wr = NULL;
wan_tdmv = &card->wan_tdmv;
WAN_ASSERT(wan_tdmv->sc == NULL);
wr = wan_tdmv->sc;
if (off_hook){
zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_OFFHOOK);
}else{
zt_hooksig(&wr->chans[mod_no], ZT_RXSIG_ONHOOK);
}
wr->mod[mod_no].fxs.lastrxhook = off_hook;
return 0;
}
/******************************************************************************
** wp_tdmv_remora_init() -
**
** OK
*/
int wp_tdmv_remora_init(wan_tdmv_iface_t *iface)
{
WAN_ASSERT(iface == NULL);
memset(iface, 0, sizeof(wan_tdmv_iface_t));
iface->check_mtu = wp_tdmv_remora_check_mtu;
iface->create = wp_tdmv_remora_create;
iface->remove = wp_tdmv_remora_remove;
iface->reg = wp_tdmv_remora_reg;
iface->unreg = wp_tdmv_remora_unreg;
iface->software_init = wp_tdmv_remora_software_init;
iface->state = wp_tdmv_remora_state;
iface->running = wp_tdmv_remora_running;
iface->is_rbsbits = wp_tdmv_remora_is_rbsbits;
iface->rx_tx_span = wp_tdmv_remora_rx_tx_span;
iface->rx_chan = wp_tdmv_remora_rx_chan;
iface->ec_span = wp_tdmv_remora_ec_span;
return 0;
}
#ifdef DAHDI_25
static int wp_remora_chanconfig(struct file *file, struct zt_chan *chan, int sigtype)
#else
static int wp_remora_chanconfig(struct zt_chan *chan, int sigtype)
#endif
{
wp_tdmv_remora_t *wr = NULL;
sdla_t *card = NULL;
WAN_ASSERT2(chan == NULL, -ENODEV);
wr = WP_PRIV_FROM_CHAN(chan,wp_tdmv_remora_t);
WAN_ASSERT2(wr == NULL, -ENODEV);
card = wr->card;
DEBUG_TDMV("%s: Configuring chan %d SigType %i..\n", wr->devname, chan->chanpos, sigtype);
#ifdef ZT_POLICY_WHEN_FULL
if (WAN_FE_NETWORK_SYNC(&card->fe)) {
chan->txbufpolicy = ZT_POLICY_WHEN_FULL;
chan->txdisable = 1;
}
#endif
return 0;
}
static int wp_tdmv_remora_software_init(wan_tdmv_t *wan_tdmv)
{
sdla_t *card = NULL;
sdla_fe_t *fe = NULL;
wp_tdmv_remora_t *wr = wan_tdmv->sc;
int x = 0, num = 0;
WAN_ASSERT(wr == NULL);
WAN_ASSERT(wr->card == NULL);
card = wr->card;
fe = &card->fe;
if (wan_test_bit(WP_TDMV_REGISTER, &wr->flags)){
DEBUG_EVENT(
"%s: Wanpipe device is already registered to Zaptel span # %d!\n",
wr->devname, wr->span.spanno);
return 0;
}
/* Zapata stuff */
sprintf(wr->span.name, "WRTDM/%d", wr->num);
sprintf(wr->span.desc, "wrtdm Board %d", wr->num + 1);
switch(fe->fe_cfg.tdmv_law){
case WAN_TDMV_ALAW:
DEBUG_EVENT(
"%s: ALAW override parameter detected. Device will be operating in ALAW\n",
wr->devname);
wr->span.deflaw = ZT_LAW_ALAW;
break;
case WAN_TDMV_MULAW:
wr->span.deflaw = ZT_LAW_MULAW;
break;
}
wr->tonesupport = card->u.aft.tdmv_hw_tone;
for (x = 0; x < MAX_REMORA_MODULES; x++) {
if (wan_test_bit(x, &fe->rm_param.module_map)){
sprintf(wr->chans[x].name, "WRTDM/%d/%d", wr->num, x);
DEBUG_TDMV("%s: Configure Module %d for voice (%s, type %s)!\n",
wr->devname,
x + 1,
wr->chans[x].name,
WP_REMORA_DECODE_TYPE(fe->rm_param.mod[x].type));
if (fe->rm_param.mod[x].type == MOD_TYPE_FXO){
wr->chans[x].sigcap = ZT_SIG_FXSKS |
ZT_SIG_FXSLS |
ZT_SIG_SF |
ZT_SIG_CLEAR;
}else if (fe->rm_param.mod[x].type == MOD_TYPE_FXS){
wr->chans[x].sigcap = ZT_SIG_FXOKS |
ZT_SIG_FXOLS |
ZT_SIG_FXOGS |
ZT_SIG_SF |
ZT_SIG_EM |
ZT_SIG_CLEAR;
}
wr->chans[x].chanpos = x+1;
wr->chans[x].pvt = wr;
num++;
}else{
sprintf(wr->chans[x].name, "WRTDM/%d/%d", wr->num, x);
DEBUG_TEST("%s: Not used module %d!\n",
wr->devname,
x + 1);
wr->chans[x].sigcap = ZT_SIG_CLEAR;
wr->chans[x].chanpos = x+1;
wr->chans[x].pvt = wr;
num++;
}
}
#if defined(DAHDI_24) || defined(DAHDI_25)
wr->span.ops = &wp_tdm_span_ops;
#else
wr->span.pvt = wr;
#if defined(DAHDI_23)
wr->span.owner = THIS_MODULE;
#endif
wr->span.hooksig = wp_remora_zap_hooksig;
wr->span.open = wp_remora_zap_open;
wr->span.close = wp_remora_zap_close;
wr->span.ioctl = wp_remora_zap_ioctl;
wr->span.watchdog = wp_remora_zap_watchdog;
wr->span.chanconfig = wp_remora_chanconfig;
/* Set this pointer only if card has hw echo canceller module */
if (wr->hwec == WANOPT_YES && card->wandev.ec_dev){
#ifdef DAHDI_22
wr->span.echocan_create = wp_tdmv_remora_hwec_create;
#else
wr->span.echocan = wp_remora_zap_hwec;
#endif
}
#endif
#ifdef DAHDI_ISSUES
wr->span.chans = wr->chans_ptrs;
#else
wr->span.chans = wr->chans;
#endif
wr->span.flags = ZT_FLAG_RBS;
wr->span.channels = num/*wr->max_timeslots*/;
#if defined(__LINUX__)
#ifndef DAHDI_25
init_waitqueue_head(&wr->span.maintq);
#endif
#endif
if (wp_dahdi_register_device(wr)) {
DEBUG_EVENT("%s: Unable to register span with zaptel\n",
wr->devname);
return -EINVAL;
}
if (wr->span.spanno != wr->spanno +1){
DEBUG_EVENT("\n");
DEBUG_EVENT("WARNING: Span number %d is already used by another device!\n",
wr->spanno + 1);
DEBUG_EVENT(" Possible cause: Another TDM driver already loaded!\n");
DEBUG_EVENT(" Solution: Unload wanpipe and check currently\n");
DEBUG_EVENT(" used spans in /proc/zaptel directory.\n");
DEBUG_EVENT(" Reconfiguring device %s to new span number # %d\n",
wr->devname,wr->span.spanno);
DEBUG_EVENT("\n");
wr->spanno = wr->span.spanno-1;
}else{
DEBUG_EVENT("%s: Wanpipe device is registered to Zaptel span # %d!\n",
wr->devname, wr->span.spanno);
}
wp_tdmv_remora_check_mtu(card, wr->reg_module_map, &wr->max_rxtx_len);
wan_set_bit(WP_TDMV_REGISTER, &wr->flags);
/* Initialize Callback event function pointers */
if (wr->tonesupport == WANOPT_YES){
DEBUG_EVENT("%s: Enable HW Tone detection!\n", wr->devname);
card->wandev.event_callback.tone = wp_tdmv_remora_tone;
}
if (fe->fe_cfg.cfg.remora.fxs_pulsedialing == WANOPT_YES){
DEBUG_EVENT("%s: Enable Pulse Dialing mode\n",
wr->devname);
}
fe->rm_param.wp_rm_chunk_size = ZT_CHUNKSIZE;
return 0;
}
/******************************************************************************
** wp_tdmv_release() -
**
** OK
*/
static void wp_tdmv_release(wp_tdmv_remora_t *wr)
{
WAN_ASSERT1(wr == NULL);
if (wan_test_bit(WP_TDMV_REGISTER, &wr->flags)){
DEBUG_EVENT("%s: Unregister WAN FXS/FXO device from Zaptel!\n",
wr->devname);
wan_clear_bit(WP_TDMV_REGISTER, &wr->flags);
wp_dahdi_unregister_device(wr);
wan_clear_bit(WP_TDMV_REGISTER, &wr->flags);
}
wp_dahdi_free_device(wr);
wan_free(wr);
return;
}
static wp_tdmv_remora_t *wan_remora_search(sdla_t * card)
{
return NULL;
}
/******************************************************************************
** wp_tdmv_remora_check_mtu() -
**
** OK
*/
static int wp_tdmv_remora_check_mtu(void* pcard, unsigned long timeslot_map, int *mtu)
{
sdla_t *card = (sdla_t*)pcard;
int x, num_of_channels = 0, max_channels;
max_channels = WAN_FE_MAX_CHANNELS(&card->fe);
for (x = 0; x < max_channels; x++) {
if (wan_test_bit(x,&timeslot_map)){
num_of_channels++;
}
}
*mtu = ZT_CHUNKSIZE * num_of_channels;
return 0;
}
/******************************************************************************
** wp_tdmv_remora_create() -
*tdmv_*
** OK
*/
static int wp_tdmv_remora_create(void* pcard, wan_tdmv_conf_t *tdmv_conf)
{
sdla_t *card = (sdla_t*)pcard;
wp_tdmv_remora_t *wr = NULL;
wan_tdmv_t *tmp = NULL;
#ifdef DAHDI_ISSUES
int i;
#endif
WAN_ASSERT(card == NULL);
WAN_ASSERT(tdmv_conf->span_no == 0);
wr = wan_remora_search(card);
if (wr){
DEBUG_EVENT("%s: AFT remora FXO/FXS card already configured!\n",
card->devname);
return -EINVAL;
}
/* We are forcing to register wanpipe devices at the same sequence
* that it defines in /etc/zaptel.conf */
WAN_LIST_FOREACH(tmp, &wan_tdmv_head, next){
if (tmp->spanno == tdmv_conf->span_no){
DEBUG_EVENT("%s: Registering device with an incorrect span number!\n",
card->devname);
DEBUG_EVENT("%s: Another wanpipe device already configured to span #%d!\n",
card->devname, tdmv_conf->span_no);
return -EINVAL;
}
if (!WAN_LIST_NEXT(tmp, next)){
break;
}
}
memset(&card->wan_tdmv, 0x0, sizeof(wan_tdmv_t));
card->wan_tdmv.max_timeslots = card->fe.rm_param.max_fe_channels;
card->wan_tdmv.spanno = tdmv_conf->span_no;
card->wandev.fe_notify_iface.hook_state = wp_tdmv_remora_hook;
card->wandev.fe_notify_iface.check_hook_state = wp_tdmv_remora_check_hook;
wr = wan_malloc(sizeof(wp_tdmv_remora_t));
if (wr == NULL){
return -ENOMEM;
}
memset(wr, 0x0, sizeof(wp_tdmv_remora_t));
card->wan_tdmv.sc = wr;
wr->spanno = tdmv_conf->span_no-1;
#ifdef DAHDI_ISSUES
if (wp_dahdi_create_device(card,wr)) {
wan_free(wr);
return -ENOMEM;
}
WP_DAHDI_SET_STR_INFO(wr,manufacturer,"Sangoma Technologies");
switch(card->adptr_type){
case A200_ADPTR_ANALOG:
WP_DAHDI_SET_STR_INFO(wr,devicetype, "A200");
break;
case A400_ADPTR_ANALOG:
WP_DAHDI_SET_STR_INFO(wr,devicetype, "A400");
break;
case AFT_ADPTR_B800:
WP_DAHDI_SET_STR_INFO(wr,devicetype, "B800");
break;
case AFT_ADPTR_A600:
WP_DAHDI_SET_STR_INFO(wr,devicetype, "B600");
break;
case AFT_ADPTR_B601:
WP_DAHDI_SET_STR_INFO(wr,devicetype, "B601");
break;
case AFT_ADPTR_FLEXBRI:
WP_DAHDI_SET_STR_INFO(wr,devicetype, "B700");
break;
case U100_ADPTR:
WP_DAHDI_SET_STR_INFO(wr,devicetype, "U100");
break;
}
WP_DAHDI_SET_STR_INFO(wr,location,"SLOT=%d, BUS=%d", card->wandev.S514_slot_no, card->wandev.S514_bus_no);
#ifndef DAHDI_26
wr->span.irq = card->wandev.irq;
#endif
#endif
wr->num = wp_remora_no++;
wr->card = card;
wr->devname = card->devname;
wr->max_timeslots = card->fe.rm_param.max_fe_channels;
wr->max_rxtx_len = 0;
wan_spin_lock_irq_init(&wr->lockirq, "wan_rmtdmv_lock");
wan_spin_lock_irq_init(&wr->tx_rx_lockirq, "wan_rmtdmv_txrx_lock");
#ifdef DAHDI_ISSUES
for (i = 0; i < sizeof(wr->chans)/sizeof(wr->chans[0]); i++) {
wr->chans_ptrs[i] = &wr->chans[i];
}
#endif
if (tmp){
WAN_LIST_INSERT_AFTER(tmp, &card->wan_tdmv, next);
}else{
WAN_LIST_INSERT_HEAD(&wan_tdmv_head, &card->wan_tdmv, next);
}
return 0;
}
/******************************************************************************
** wp_tdmv_reg() -
**
** Returns: 0-31 - Return TDM Voice channel number.
** -EINVAL - otherwise
** OK
*/
static int wp_tdmv_remora_reg( void *pcard,
wan_tdmv_if_conf_t *tdmv_conf,
unsigned int active_ch,
unsigned char ec_enable,
netdevice_t *dev)
{
sdla_t *card = (sdla_t*)pcard;
sdla_fe_t *fe = &card->fe;
wan_tdmv_t *wan_tdmv = &card->wan_tdmv;
wp_tdmv_remora_t *wr = NULL;
int i, channo = 0;
WAN_ASSERT(wan_tdmv->sc == NULL);
wr = wan_tdmv->sc;
if (wan_test_bit(WP_TDMV_REGISTER, &wr->flags)){
DEBUG_EVENT(
"%s: Error: Master device has already been configured!\n",
card->devname);
return -EINVAL;
}
for(i = 0; i < wr->max_timeslots; i++){
if (wan_test_bit(i, &active_ch) &&
wan_test_bit(i, &fe->rm_param.module_map)){
if (tdmv_conf->tdmv_echo_off){
wan_set_bit(i, &wr->echo_off_map);
}
channo = i;
break;
}
}
if (i == wr->max_timeslots){
DEBUG_EVENT(
"%s: Error: TDMV iface %s failed to configure for %08X timeslots!\n",
card->devname,
wan_netif_name(dev),
active_ch);
return -EINVAL;
}
DEBUG_EVENT(
"%s: Registering TDMV %s iface to module %d!\n",
card->devname,
WP_REMORA_DECODE_TYPE(fe->rm_param.mod[channo].type),
channo+1);
wan_set_bit(channo, &wr->reg_module_map);
if (tdmv_conf->tdmv_echo_off){
DEBUG_EVENT("%s: TDMV Echo Ctrl:Off\n",
wr->devname);
}
memset(wr->chans[channo].sreadchunk, WAN_TDMV_IDLE_FLAG, ZT_CHUNKSIZE);
memset(wr->chans[channo].swritechunk, WAN_TDMV_IDLE_FLAG, ZT_CHUNKSIZE);
wr->chans[channo].readchunk = wr->chans[channo].sreadchunk;
wr->chans[channo].writechunk = wr->chans[channo].swritechunk;
wr->channelized = WAN_TRUE;
wr->hwec = ec_enable;
wp_tdmv_remora_check_mtu(card, active_ch, &wr->max_rxtx_len);
return channo;
}
/******************************************************************************
** wp_tdmv_unreg() -
**
** OK
*/
static int wp_tdmv_remora_unreg(void* pcard, unsigned long ts_map)
{
sdla_t *card = (sdla_t*)pcard;
sdla_fe_t *fe = &card->fe;
wan_tdmv_t *wan_tdmv = &card->wan_tdmv;
wp_tdmv_remora_t *wr = NULL;
int channo = 0;
WAN_ASSERT(wan_tdmv->sc == NULL);
wr = wan_tdmv->sc;
for(channo = 0; channo < wr->max_timeslots; channo++){
if (wan_test_bit(channo, &wr->reg_module_map)){
DEBUG_EVENT(
"%s: Unregistering TDMV %s iface from module %d!\n",
card->devname,
WP_REMORA_DECODE_TYPE(fe->rm_param.mod[channo].type),
channo+1);
wan_clear_bit(channo, &wr->reg_module_map);
wan_clear_bit(channo, &wr->echo_off_map);
memset(wr->chans[channo].sreadchunk,
WAN_TDMV_IDLE_FLAG,
ZT_CHUNKSIZE);
memset(wr->chans[channo].swritechunk,
WAN_TDMV_IDLE_FLAG,
ZT_CHUNKSIZE);
wr->chans[channo].readchunk =
wr->chans[channo].sreadchunk;
wr->chans[channo].writechunk =
wr->chans[channo].swritechunk;
}
}
return 0;
}
/******************************************************************************
** wp_tdmv_remove() -
**
** OK
*/
static int wp_tdmv_remora_remove(void* pcard)
{
sdla_t *card = (sdla_t*)pcard;
wan_tdmv_t *wan_tdmv = &card->wan_tdmv;
wp_tdmv_remora_t *wr = NULL;
if (!card->wan_tdmv.sc){
return 0;
}
wr = wan_tdmv->sc;
/* Release span, possibly delayed */
if (wr && wr->reg_module_map){
DEBUG_EVENT(
"%s: Some interfaces are not unregistered (%08lX)!\n",
card->devname,
wr->reg_module_map);
return -EINVAL;
}
if (wr && wr->usecount){
DEBUG_ERROR("%s: ERROR: Wanpipe is still used by Asterisk!\n",
card->devname);
return -EINVAL;
}
if (wr){
wan_clear_bit(WP_TDMV_RUNNING, &wr->flags);
wan_clear_bit(WP_TDMV_UP, &wr->flags);
wan_tdmv->sc = NULL;
WAN_LIST_REMOVE(wan_tdmv, next);
wp_tdmv_release(wr);
}else{
wan_tdmv->sc = NULL;
}
return 0;
}
static int wp_tdmv_remora_state(void* pcard, int state)
{
sdla_t *card = (sdla_t*)pcard;
wan_tdmv_t *wan_tdmv = &card->wan_tdmv;
wp_tdmv_remora_t *wr = NULL;
WAN_ASSERT(wan_tdmv->sc == NULL);
wr = (wp_tdmv_remora_t*)wan_tdmv->sc;
switch(state){
case WAN_CONNECTED:
DEBUG_TDMV("%s: TDMV Remora state is CONNECTED!\n",
wr->devname);
wan_set_bit(WP_TDMV_UP, &wr->flags);
break;
case WAN_DISCONNECTED:
DEBUG_TDMV("%s: TDMV Remora state is DISCONNECTED!\n",
wr->devname);
wan_clear_bit(WP_TDMV_UP, &wr->flags);
break;
}
return 0;
}
/******************************************************************************
** wp_tdmv_running() -
**
** OK
*/
static int wp_tdmv_remora_running(void* pcard)
{
sdla_t *card = (sdla_t*)pcard;
wan_tdmv_t *wan_tdmv = &card->wan_tdmv;
wp_tdmv_remora_t *wr = NULL;
wr = wan_tdmv->sc;
if (wr && wr->usecount){
DEBUG_EVENT("%s: WARNING: Wanpipe is still used by Asterisk!\n",
card->devname);
return -EINVAL;
}
return 0;
}
/******************************************************************************
** wp_tdmv_remora_is_rbsbits() -
**
** OK
*/
static int wp_tdmv_remora_is_rbsbits(wan_tdmv_t *wan_tdmv)
{
return 0;
}
static inline void wp_tdmv_dtmfcheck_fakepolarity(wp_tdmv_remora_t *wr, int channo, unsigned char *rxbuf)
{
sdla_t *card = wr->card;
sdla_fe_t *fe = &card->fe;
int sample;
int dtmf=1;
if (!card->fe.fe_cfg.cfg.remora.fake_polarity_thres) {
card->fe.fe_cfg.cfg.remora.fake_polarity_thres=1600;
}
if (!card->fe.fe_cfg.cfg.remora.fake_polarity_cid_timer) {
card->fe.fe_cfg.cfg.remora.fake_polarity_cid_timer=400;
}
if (!card->fe.fe_cfg.cfg.remora.fake_polarity_cid_timeout) {
card->fe.fe_cfg.cfg.remora.fake_polarity_cid_timeout=4000;
}
/* only look for sound on the line if dtmf flag is on, it is an fxo card and line is onhook */
if (!dtmf || !(fe->rm_param.mod[channo].type == MOD_TYPE_FXO) || wr->mod[channo].fxo.offhook) {
return;
}
/* don't look for noise if we're already processing it, or there is a ringing tone */
if(!wr->mod[channo].fxo.readcid && !wr->mod[channo].fxo.wasringing &&
fe->rm_param.intcount > wr->mod[channo].fxo.cidtimer + card->fe.fe_cfg.cfg.remora.fake_polarity_cid_timer) {
sample = ZT_XLAW((*rxbuf), (&(wr->chans[channo])));
if (sample > card->fe.fe_cfg.cfg.remora.fake_polarity_thres || sample < -card->fe.fe_cfg.cfg.remora.fake_polarity_thres) {
wr->mod[channo].fxo.readcid = 1;
wr->mod[channo].fxo.ring_skip = 1;
wr->mod[channo].fxo.cidtimer = fe->rm_param.intcount;
DEBUG_TDMV("DTMF CLIP on %i\n",channo+1);
zt_qevent_lock(&wr->chans[channo], ZT_EVENT_POLARITY);
}
} else if(wr->mod[channo].fxo.readcid && fe->rm_param.intcount > wr->mod[channo].fxo.cidtimer + card->fe.fe_cfg.cfg.remora.fake_polarity_cid_timeout) {
/* reset flags if it's been a while */
wr->mod[channo].fxo.cidtimer = fe->rm_param.intcount;
wr->mod[channo].fxo.readcid = 0;
}
}
/******************************************************************************
** wp_tdmv_rx_chan() -
**
** OK
*/
static int wp_tdmv_remora_rx_chan(wan_tdmv_t *wan_tdmv, int channo,
unsigned char *rxbuf,
unsigned char *txbuf)
{
wp_tdmv_remora_t *wr = wan_tdmv->sc;
#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER
wan_tdmv_rxtx_pwr_t *pwr_rxtx = NULL;
#endif
sdla_t *card;
WAN_ASSERT2(wr == NULL, -EINVAL);
WAN_ASSERT2(channo < 0, -EINVAL);
WAN_ASSERT2(channo > 31, -EINVAL);
if (!IS_TDMV_UP(wr)){
return -EINVAL;
}
card = wr->card;
#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER
pwr_rxtx = &wan_tdmv->chan_pwr[channo];
#endif
#if 0
if (channo == 1){
DEBUG_EVENT("Module %d: RX: %02X %02X %02X %02X %02X %02X %02X %02X\n",
channo,
rxbuf[0],
rxbuf[1],
rxbuf[2],
rxbuf[3],
rxbuf[4],
rxbuf[5],
rxbuf[6],
rxbuf[7]
);
}
#endif
#ifdef ZT_POLICY_WHEN_FULL
/* This feature is used to change zaptel buffering that improves
faxing between analog & SMG. Enable this feature ONLY when
network sync is ON */
if (WAN_FE_NETWORK_SYNC(&card->fe) == WANOPT_YES &&
wr->chans[channo].txbufpolicy != ZT_POLICY_WHEN_FULL) {
DEBUG_EVENT("%s: RX CHAN %i Setting FULL POLICY\n",
card->devname,channo);
wr->chans[channo].txbufpolicy = ZT_POLICY_WHEN_FULL;
}
#endif
#ifdef WAN_SYNC_RX_TX_TEST
/* This feature should be used with HWDTMF enabled, otherwise
* analog will not be able to dial. This is a debugging feature
* should NEVER be used in production only for testing */
wp_tdmv_remora_rx_chan_sync_test(card,wr,channo,rxbuf,txbuf);
#endif
wr->chans[channo].readchunk = rxbuf;
wr->chans[channo].writechunk = txbuf;
if (card->fe.fe_cfg.cfg.remora.fake_polarity == WANOPT_YES){
wp_tdmv_dtmfcheck_fakepolarity(wr,channo,rxbuf);
}
#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER
wp_tdmv_echo_check(wan_tdmv, &wr->chans[channo], channo);
#endif
if ((!card->wandev.ec_enable || card->wandev.ec_enable_map == 0) &&
!wan_test_bit(channo, &wr->echo_off_map)) {
/*Echo spike starts at 25bytes*/
#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER
if(pwr_rxtx->current_state != ECHO_ABSENT){
#endif
if (wan_test_bit(AFT_TDM_SW_RING_BUF,&card->u.aft.chip_cfg_status)) {
/* Updated for SWRING buffer
* Sets up the spike at 3 bytes */
zt_ec_chunk(
&wr->chans[channo],
wr->chans[channo].readchunk,
wr->chans[channo].writechunk);
} else {
/* This should be used without SWRING Echo spike starts at 9 bytes*/
zt_ec_chunk(
&wr->chans[channo],
wr->chans[channo].readchunk,
wr->ec_chunk1[channo]);
memcpy(
wr->ec_chunk1[channo],
wr->chans[channo].writechunk,
ZT_CHUNKSIZE);
}
#if 0
/*Echo spike starts at bytes*/
zt_ec_chunk(
&wr->chans[channo],
wr->chans[channo].readchunk,
wr->ec_chunk1[channo]);
memcpy(
wr->ec_chunk1[channo],
wr->ec_chunk2[channo],
ZT_CHUNKSIZE);
memcpy(
wr->ec_chunk2[channo],
wr->chans[channo].writechunk,
ZT_CHUNKSIZE);
#endif
#ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_ECHOMASTER
} /*if(pwr_rxtx->current_state != ECHO_ABSENT) */
#endif
} /* if (!wan_test_bit(channo, &wr->echo_off_map)) */
return 0;
}
static int wp_tdmv_remora_rx_tx_span(void *pcard)
{
sdla_t *card = (sdla_t*)pcard;
sdla_fe_t *fe = &card->fe;
wan_tdmv_t *wan_tdmv = &card->wan_tdmv;
wp_tdmv_remora_t *wr = NULL;
WAN_ASSERT(wan_tdmv->sc == NULL);
wr = wan_tdmv->sc;
fe->rm_param.intcount++;
wp_tdmv_remora_rx_tx_span_common(pcard);
zt_receive(&wr->span);
zt_transmit(&wr->span);
return 0;
}
static int wp_tdmv_remora_ec_span(void *pcard)
{
sdla_t *card = (sdla_t*)pcard;
wan_tdmv_t *wan_tdmv = &card->wan_tdmv;
wp_tdmv_remora_t *wr = NULL;
WAN_ASSERT(wan_tdmv->sc == NULL);
wr = wan_tdmv->sc;
zt_ec_span(&wr->span);
return 0;
}
static void wp_tdmv_remora_tone (void* card_id, wan_event_t *event)
{
sdla_t *card = (sdla_t*)card_id;
wan_tdmv_t *wan_tdmv = &card->wan_tdmv;
wp_tdmv_remora_t *wr = NULL;
int fechan;
WAN_ASSERT1(wan_tdmv->sc == NULL);
wr = wan_tdmv->sc;
if (event->channel <= 0) {
DEBUG_ERROR("%s: Error: wp_tdmv_remora_tone() Invalid Event Channel = %i\n",
card->devname, event->channel);
return;
}
fechan = event->channel-1;
switch(event->type) {
case WAN_EVENT_EC_DTMF:
case WAN_EVENT_EC_FAX_1100:
DEBUG_TDMV(
"[TDMV] %s: Received EC Tone (%s) Event at TDM (chan=%d digit=%c port=%s type=%s)!\n",
card->devname,
WAN_EVENT_TYPE_DECODE(event->type),
event->channel,
event->digit,
(event->tone_port == WAN_EC_CHANNEL_PORT_ROUT)?"ROUT":"SOUT",
(event->tone_type == WAN_EC_TONE_PRESENT)?"PRESENT":"STOP");
break;
case WAN_EVENT_RM_DTMF:
DEBUG_TDMV(
"[TDMV_RM]: %s: Received RM DTMF Event at TDM (%d:%c)!\n",
card->devname,
event->channel,
event->digit);
break;
default:
DEBUG_ERROR("%s: %s() Error Invalid event type %X (%s)!\n",
card->devname, __FUNCTION__, event->type, WAN_EVENT_TYPE_DECODE(event->type));
return;
}
if (!(wr->tonemask & (1 << (event->channel-1)))){
DEBUG_TDMV(
"[TDMV] %s: Tone detection is not enabled for the channel %d\n",
card->devname,
event->channel);
return;
}
if (event->digit == 'f' && fechan >= 0) {
if (!card->tdmv_conf.hw_fax_detect) {
DEBUG_TDMV("%s: Received Fax Detect event while hw fax disabled !\n",card->devname);
return;
}
if (card->tdmv_conf.hw_fax_detect == WANOPT_YES) {
card->tdmv_conf.hw_fax_detect=8;
}
if (wr->ec_fax_detect_timeout[fechan] == 0) {
DEBUG_TDMV("%s: FAX DETECT TIMEOUT --- Not initialized!\n",card->devname);
return;
} else if (card->tdmv_conf.hw_fax_detect &&
(SYSTEM_TICKS - wr->ec_fax_detect_timeout[fechan]) >= card->tdmv_conf.hw_fax_detect*HZ) {
#ifdef WAN_DEBUG_TDMAPI
if (WAN_NET_RATELIMIT()) {
DEBUG_WARNING("%s: Warning: Ignoring Fax detect during call (s%dc%d) - Call Time: %ld Max: %d!\n",
card->devname,
wr->spanno+1,
event->channel,
(SYSTEM_TICKS - wr->ec_fax_detect_timeout[fechan])/HZ,
card->tdmv_conf.hw_fax_detect);
}
#endif
return;
} else {
DEBUG_TDMV("%s: FAX DETECT OK --- Ticks=%lu Timeout=%lu Diff=%lu! s%dc%d\n",
card->devname,SYSTEM_TICKS,wr->ec_fax_detect_timeout[fechan],
(SYSTEM_TICKS - wr->ec_fax_detect_timeout[fechan])/HZ,
card->wan_tdmv.spanno,fechan);
}
}
if (event->tone_type == WAN_EC_TONE_PRESENT){
wr->toneactive |= (1 << (event->channel-1));
#ifdef DAHDI_ISSUES
zt_qevent_lock(
wr->span.chans[event->channel-1],
(ZT_EVENT_DTMFDOWN | event->digit));
#else
zt_qevent_lock(
&wr->span.chans[event->channel-1],
(ZT_EVENT_DTMFDOWN | event->digit));
#endif
if (wr->hwec == WANOPT_YES && card->wandev.ec_dev && card->wandev.ec_enable && card->tdmv_conf.ec_off_on_fax) {
/* Disable hwec on fax event if configuration option is enabled
Disable hwec only if persist disalbe is not enabled, since in that mode asterisk controls hwec.
Disable hwec only once even though there might be many fax events */
if (!card->hwec_conf.persist_disable && !wr->ec_off_on_fax) {
DEBUG_EVENT("%s: Disabling hwec on fax event chan=%i\n",card->devname,event->channel);
card->wandev.ec_enable(card, 0, event->channel);
wr->ec_off_on_fax=1;
}
}
}else{
wr->toneactive &= ~(1 << (event->channel-1));
#ifdef DAHDI_ISSUES
zt_qevent_lock(
wr->span.chans[event->channel-1],
(ZT_EVENT_DTMFUP | event->digit));
#else
zt_qevent_lock(
&wr->span.chans[event->channel-1],
(ZT_EVENT_DTMFUP | event->digit));
#endif
}
return;
}
#ifdef WAN_SYNC_RX_TX_TEST
#warning "WAN_SYNC_RX_TX_TEST: Test option Enabled"
static unsigned char gstat_rx_chan[1024];
static unsigned char gstat_tx_chan[1024];
static unsigned char gstat_sync[1024];
static unsigned char gstat_sync_stat[1024];
static int wp_tdmv_remora_rx_chan_sync_test(sdla_t *card, wp_tdmv_remora_t *wr, int channo,
unsigned char *rxbuf,
unsigned char *txbuf)
{
/* This feature should be used with HWDTMF enabled, otherwise
* analog will not be able to dial. This is a debugging feature
* should NEVER be used in production only for testing */
if (1 || wan_test_bit(channo,&card->wandev.rtp_tap_call_map)) {
#if 0
if (*(unsigned int*)&wr->chans[channo].writechunk[0] == 0xD5D5D5D5 &&
*(unsigned int*)&wr->chans[channo].writechunk[4] == 0xD5D5D5D5) {
DEBUG_EVENT("%s: Chan %i Rx Frame Slip!\n",
card->devname,channo);
}
#endif
int i;
/* Pass up a sequence */
for (i=0;i<8;i++) {
rxbuf[i]=++gstat_rx_chan[channo];
}
/* Check for incoming sequence */
if (gstat_sync_stat[channo] == 0) {
DEBUG_EVENT("%s: Starting to hunt for sync on %i map=0x%lX\n",
card->devname,channo, card->wandev.rtp_tap_call_map);
gstat_sync_stat[channo]++;
}
for (i=0;i<8;i++) {
if (gstat_sync[channo] == 0) {
if (wr->chans[channo].writechunk[i] == 0x01) {
gstat_sync[channo] = 1;
gstat_tx_chan[channo]=wr->chans[channo].writechunk[i];
DEBUG_EVENT("%s: Chan=%i Sync got=%i offset=%i\n",
card->devname,channo,wr->chans[channo].writechunk[i],i);
}
} else {
gstat_tx_chan[channo]++;
if (gstat_tx_chan[channo] != wr->chans[channo].writechunk[i]) {
int x;
DEBUG_EVENT("%s: Chan=%i Out of Sync expecting=%i got=%i offset=%i\n",
card->devname,channo,
gstat_tx_chan[channo],wr->chans[channo].writechunk[i],i);
gstat_tx_chan[channo] = wr->chans[channo].writechunk[i];
gstat_sync[channo] = 0;
for (x=0;x<8;x++){
DEBUG_EVENT("chan=%i off=%i data=%i\n",channo,x,wr->chans[channo].writechunk[x]);
}
}
}
}
}
return 0;
}
#endif