commit 9129e40b7328be1d7d81ff4131a99a58d2b62b45
Author: David Yat Sin <dyatsin@sangoma.com>
Date:   Mon Dec 17 16:32:43 2012 -0500

    Support for DTMF removal enable/disable via API

diff --git a/include/wanpipe_api_iface.h b/include/wanpipe_api_iface.h
index f7ce669..fe74719 100644
--- a/include/wanpipe_api_iface.h
+++ b/include/wanpipe_api_iface.h
@@ -95,6 +95,8 @@ typedef int sng_fd_t;
 #define WP_API_FEATURE_LED_CTRL     1
 #define WP_API_FEATURE_SS7_FORCE_RX 1
 #define WP_API_FEATURE_SS7_CFG_STATUS 1
+#define WP_API_FEATURE_LIBSNG_HWEC_DTMF_REMOVAL 1
+
 
 /*!
   \enum WANPIPE_IOCTL_CODE
diff --git a/wanec/wanec_cmd.c b/wanec/wanec_cmd.c
index eb92509..a90af59 100644
--- a/wanec/wanec_cmd.c
+++ b/wanec/wanec_cmd.c
@@ -112,6 +112,7 @@ 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);
@@ -121,6 +122,8 @@ int wanec_ChannelStats(wan_ec_dev_t*, INT channel, wanec_chan_stats_t *chan_stat
 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);
@@ -762,8 +765,10 @@ int wanec_ChannelOpen(wan_ec_dev_t *ec_dev, INT ec_chan, int verbose)
 
 	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) {
@@ -914,6 +919,49 @@ int wanec_ChannelModifyOpmode(	wan_ec_dev_t		*ec_dev,
 	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,
diff --git a/wanec/wanec_iface.c b/wanec/wanec_iface.c
index bf1fc79..ffb4e39 100644
--- a/wanec/wanec_iface.c
+++ b/wanec/wanec_iface.c
@@ -108,6 +108,8 @@ extern int wanec_ChannelUnMute(wan_ec_dev_t*, INT ec_chan, wanec_chan_mute_t*, i
 
 extern int wanec_TonesCtrl(wan_ec_t*, int, int, wanec_tone_config_t*, int);
 
+extern int wanec_DtmfRemoval(wan_ec_dev_t *ec_dev, int channel, int enable, int verbose);
+
 extern int wanec_DebugChannel(wan_ec_dev_t*, INT, int);
 extern int wanec_DebugGetData(wan_ec_dev_t*, wanec_chan_monitor_t*, int);
 
@@ -138,6 +140,7 @@ static int wanec_api_stats_image(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api);
 static int wanec_api_buffer(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api);
 static int wanec_api_playout(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api);
 static int wanec_api_monitor(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api);
+static int wanec_api_chan_dtmf_removal(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api);
 
 static wan_ec_dev_t *wanec_search(char *devname);
 
@@ -1210,6 +1213,7 @@ static int wanec_api_channel_mute(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api)
 				WAN_EC_STATE_DECODE(ec->state));
 		return WAN_EC_API_RC_INVALID_STATE;
 	}
+	
 	if (ec_api->fe_chan_map == 0xFFFFFFFF){
 		/* All channels selected */
 		ec_api->fe_chan_map = ec_dev->fe_channel_map;
@@ -1236,6 +1240,50 @@ static int wanec_api_channel_mute(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api)
 	return err;
 }
 
+static int wanec_api_chan_dtmf_removal(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api)
+{
+	wan_ec_t	*ec = NULL;
+	int		fe_chan, ec_chan;
+	int		err = WAN_EC_API_RC_OK;
+
+	WAN_ASSERT(ec_dev == NULL);
+	WAN_ASSERT(ec_dev->ec == NULL);
+	ec = ec_dev->ec;
+
+	if (ec_dev->state != WAN_EC_STATE_CHAN_READY){
+		DEBUG_EVENT("ERROR: %s: Invalid Echo Canceller %s API state (%s)\n",
+					ec_dev->devname,
+					ec->name,
+					WAN_EC_STATE_DECODE(ec->state));
+
+		return WAN_EC_API_RC_INVALID_STATE;
+	}
+	
+	if (ec_api->fe_chan_map == 0xFFFFFFFF){
+		/* All channels selected */
+		ec_api->fe_chan_map = ec_dev->fe_channel_map;
+	}
+
+	if (!ec_api->fe_chan_map){
+		return WAN_EC_API_RC_NOACTION;
+	}
+	for(fe_chan = ec_dev->fe_start_chan; fe_chan <= ec_dev->fe_stop_chan; fe_chan++){
+		if (!(ec_api->fe_chan_map & (1 << fe_chan))){
+			continue;
+		}
+		if (ec_dev->fe_media == WAN_MEDIA_E1 && fe_chan == 0) continue;
+
+		ec_chan = wanec_fe2ec_channel(ec_dev, fe_chan);
+
+		err = wanec_DtmfRemoval(ec_dev, ec_chan, (ec_api->cmd == WAN_EC_API_CMD_HWDTMF_REMOVAL_ENABLE) ? 1 : 0, ec_api->verbose);
+		if (err){
+			return WAN_EC_API_RC_FAILED;
+		}
+	}
+	return err;
+}
+
+		
 static int wanec_api_tone(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api)
 {
 	wan_ec_t	*ec = NULL;
@@ -1678,6 +1726,10 @@ static void __wanec_ioctl(wan_ec_dev_t *ec_dev, wan_ec_api_t *ec_api)
 		break;
 	case WAN_EC_API_CMD_RELEASE_ALL:
 		break;
+	case WAN_EC_API_CMD_HWDTMF_REMOVAL_ENABLE:
+	case WAN_EC_API_CMD_HWDTMF_REMOVAL_DISABLE:
+		err = wanec_api_chan_dtmf_removal(ec_dev, ec_api);
+		break;
 	}
 	
 	if (err){
diff --git a/wanec/wanec_iface.h b/wanec/wanec_iface.h
index f870d0e..7f78ac2 100644
--- a/wanec/wanec_iface.h
+++ b/wanec/wanec_iface.h
@@ -265,6 +265,7 @@ typedef struct wan_ec_dev_
 	int			fe_start_chan, fe_stop_chan;
 	int			fe_max_chans;
 	u_int32_t	fe_channel_map;
+	u_int32_t   fe_dtmf_removal_map; /* Bitmap of channels that have dtmf removal enabled already */
 	u_int32_t	fe_ec_map;
 	u_int32_t	fe_tdmv_law;
 	u_int32_t	channel;
diff --git a/wanec/wanec_iface_api.h b/wanec/wanec_iface_api.h
index 8d421f9..59079b2 100644
--- a/wanec/wanec_iface_api.h
+++ b/wanec/wanec_iface_api.h
@@ -98,6 +98,8 @@
 # define WAN_EC_API_CMD_CONFIG_POLL		22
 # define WAN_EC_API_CMD_CHANNEL_MUTE		23
 # define WAN_EC_API_CMD_CHANNEL_UNMUTE		24
+# define WAN_EC_API_CMD_HWDTMF_REMOVAL_ENABLE	25
+# define WAN_EC_API_CMD_HWDTMF_REMOVAL_DISABLE	26
 #else
 # define WAN_EC_API_CMD_NONE			_IOWR('E', 0, struct wan_ec_api_)
 # define WAN_EC_API_CMD_GETINFO			_IOWR('E', 1, wan_ec_api_t)
@@ -124,6 +126,8 @@
 # define WAN_EC_API_CMD_CONFIG_POLL		_IOWR('E', 22, struct wan_ec_api_)
 # define WAN_EC_API_CMD_CHANNEL_MUTE		_IOWR('E', 23, struct wan_ec_api_)
 # define WAN_EC_API_CMD_CHANNEL_UNMUTE		_IOWR('E', 24, struct wan_ec_api_)
+# define WAN_EC_API_CMD_HWDTMF_REMOVAL_ENABLE	_IOWR('E', 25, struct wan_ec_api_)
+# define WAN_EC_API_CMD_HWDTMF_REMOVAL_DISABLE	_IOWR('E', 26, struct wan_ec_api_)
 #endif
 
 # define WAN_EC_API_CMD_DECODE(cmd)					\
@@ -151,6 +155,8 @@
 	(cmd == WAN_EC_API_CMD_TONE_DISABLE)		? "Disable TONE" :	\
 	(cmd == WAN_EC_API_CMD_CHANNEL_MUTE)	? "Channel Mute" :	\
 	(cmd == WAN_EC_API_CMD_CHANNEL_UNMUTE)	? "Channel Un-mute" :	\
+	(cmd == WAN_EC_API_CMD_HWDTMF_REMOVAL_ENABLE)	? "DTMF Removal enable" :	\
+	(cmd == WAN_EC_API_CMD_HWDTMF_REMOVAL_DISABLE)	? "DTMF Removal disable" :	\
 					"Unknown"
 
 #define WAN_
diff --git a/wantools/libsangoma/libsangoma.h b/wantools/libsangoma/libsangoma.h
index e32932f..e9a3329 100644
--- a/wantools/libsangoma/libsangoma.h
+++ b/wantools/libsangoma/libsangoma.h
@@ -2270,6 +2270,27 @@ sangoma_status_t _LIBSNG_CALL sangoma_hwec_get_global_chip_statistics(sng_fd_t f
 sangoma_status_t _LIBSNG_CALL sangoma_hwec_get_chip_image_info(sng_fd_t fd,
 			int *hwec_api_return_code, wanec_chip_image_t *wanec_chip_image, int verbose);
 
+/*!
+  \fn sangoma_status_t _LIBSNG_CALL sangoma_hwec_set_hwdtmf_removal(sng_fd_t fd, unsigned int fe_chan,
+		int *hwec_api_return_code, int enable)
+
+  \brief Enable/Disable HW DTMF removal. 
+
+  \param fd device file descriptor
+
+  \param fe_chan Channel number (a timeslot for Digital, a line for Analog) where 
+		the call will read statistics. Valid values are from 1 to 31.
+
+  \param hwec_api_return_code	will contain one of WAN_EC_API_RC_x codes which are defined in wanec_iface_api.h
+
+  \param verbose Flag indicating to the Driver to print additional information about the command into Wanpipe Log file.
+
+  \param enable Flag to remove DTMF tones, if set to 1.
+
+  \return SANG_STATUS_SUCCESS: success, or error status of IOCTL
+ */
+sangoma_status_t _LIBSNG_CALL sangoma_hwec_set_hwdtmf_removal(sng_fd_t fd, unsigned int fe_chan,
+		int *hwec_api_return_code, int enable, int verbose);
 #endif /* WP_API_FEATURE_LIBSNG_HWEC */
 
 
diff --git a/wantools/libsangoma/libsangoma_hwec.c b/wantools/libsangoma/libsangoma_hwec.c
index aa612a5..c39a10d 100644
--- a/wantools/libsangoma/libsangoma_hwec.c
+++ b/wantools/libsangoma/libsangoma_hwec.c
@@ -866,4 +866,54 @@ sangoma_status_t _LIBSNG_CALL sangoma_hwec_get_chip_image_info(sng_fd_t fd,
 	return SANG_STATUS_SUCCESS;
 }
 
+
+/*!
+  \fn sangoma_status_t _LIBSNG_CALL sangoma_hwec_set_hwdtmf_removal(sng_fd_t fd, unsigned int fe_chan,
+		int *hwec_api_return_code, int enable)
+
+  \brief Enable/Disable HW DTMF removal. 
+
+  \param fd device file descriptor
+
+  \param fe_chan Channel number (a timeslot for Digital, a line for Analog) where 
+		the call will read statistics. Valid values are from 1 to 31.
+
+  \param hwec_api_return_code	will contain one of WAN_EC_API_RC_x codes which are defined in wanec_iface_api.h
+
+  \param verbose Flag indicating to the Driver to print additional information about the command into Wanpipe Log file.
+
+  \param enable Flag to remove DTMF tones, if set to 1.
+
+  \return SANG_STATUS_SUCCESS: success, or error status of IOCTL
+ */
+sangoma_status_t _LIBSNG_CALL sangoma_hwec_set_hwdtmf_removal(sng_fd_t fd, unsigned int fe_chan,
+		int *hwec_api_return_code, int enable, int verbose)
+{
+	sangoma_status_t err;
+	wan_ec_api_t ec_api;
+
+	memset(&ec_api, 0x00, sizeof(ec_api));
+
+	if (enable) {
+		ec_api.cmd = WAN_EC_API_CMD_HWDTMF_REMOVAL_ENABLE;
+	} else {
+		ec_api.cmd = WAN_EC_API_CMD_HWDTMF_REMOVAL_DISABLE;
+	}
+
+	ec_api.verbose = verbose;
+
+	/* translate channel number into "single bit" bitmap */
+	ec_api.fe_chan_map = (1 << fe_chan);
+
+	err = sangoma_hwec_ioctl(fd, &ec_api);
+	if (err) {
+		/* error in IOCTL */
+		return err;
+	}
+
+	*hwec_api_return_code = ec_api.err;
+
+	return SANG_STATUS_SUCCESS;
+}
+
 #endif /* WP_API_FEATURE_LIBSNG_HWEC */
