diff --git a/libs/freetdm/src/include/openzap.h b/libs/freetdm/src/include/openzap.h
index ae95e34021..e0974326ca 100644
--- a/libs/freetdm/src/include/openzap.h
+++ b/libs/freetdm/src/include/openzap.h
@@ -448,6 +448,7 @@ struct zap_channel {
 	struct zap_span *span;
 	struct zap_io_interface *zio;
 	zap_hash_t *variable_hash;
+	unsigned char cas_bits;
 };
 
 
diff --git a/libs/freetdm/src/include/zap_config.h b/libs/freetdm/src/include/zap_config.h
index 0b37208666..f550029388 100644
--- a/libs/freetdm/src/include/zap_config.h
+++ b/libs/freetdm/src/include/zap_config.h
@@ -116,6 +116,13 @@ void zap_config_close_file(zap_config_t * cfg);
 */
 int zap_config_next_pair(zap_config_t * cfg, char **var, char **val);
 
+/*!
+  \brief Retrieve the CAS bits from a configuration string value
+  \param strvalue pointer to the configuration string value (expected to be in format whatever:xxxx)
+  \param outbits pointer to aim at the CAS bits
+*/
+int zap_config_get_cas_bits(char *strvalue, unsigned char *outbits);
+
 
 /** @} */
 #endif
diff --git a/libs/freetdm/src/include/zap_types.h b/libs/freetdm/src/include/zap_types.h
index f8ec1ff698..1998465bbb 100644
--- a/libs/freetdm/src/include/zap_types.h
+++ b/libs/freetdm/src/include/zap_types.h
@@ -150,9 +150,10 @@ typedef enum {
 	ZAP_OOB_ALARM_TRAP,
 	ZAP_OOB_ALARM_CLEAR,
 	ZAP_OOB_NOOP,
+	ZAP_OOB_CAS_BITS_CHANGE,
 	ZAP_OOB_INVALID
 } zap_oob_event_t;
-#define OOB_STRINGS "DTMF", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "INVALID"
+#define OOB_STRINGS "DTMF", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "CAS_BITS_CHANGE", "INVALID"
 ZAP_STR2ENUM_P(zap_str2zap_oob_event, zap_oob_event2str, zap_oob_event_t)
 
 typedef enum {
@@ -270,6 +271,8 @@ typedef enum {
 	ZAP_COMMAND_DISABLE_ECHOCANCEL,
 	ZAP_COMMAND_ENABLE_ECHOTRAIN,
 	ZAP_COMMAND_DISABLE_ECHOTRAIN,
+	ZAP_COMMAND_SET_CAS_BITS,
+	ZAP_COMMAND_GET_CAS_BITS,
 	ZAP_COMMAND_COUNT
 } zap_command_t;
 
@@ -287,10 +290,11 @@ typedef enum {
 	ZAP_CHAN_TYPE_FXS,
 	ZAP_CHAN_TYPE_FXO,
 	ZAP_CHAN_TYPE_EM,
+	ZAP_CHAN_TYPE_CAS,
 	ZAP_CHAN_TYPE_COUNT
 } zap_chan_type_t;
 
-#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "INVALID"
+#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "CAS", "INVALID"
 ZAP_STR2ENUM_P(zap_str2zap_chan_type, zap_chan_type2str, zap_chan_type_t)
 
 typedef enum {
diff --git a/libs/freetdm/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c b/libs/freetdm/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
index acf9ab28c0..3be93f2e01 100644
--- a/libs/freetdm/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
+++ b/libs/freetdm/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
@@ -346,10 +346,31 @@ static zap_status_t wp_tdm_cmd_exec(zap_channel_t *zchan, wanpipe_tdm_api_t *tdm
 	return ZAP_SUCCESS;
 }
 
-static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number)
+static unsigned char wanpipe_swap_bits(unsigned char cas_bits)
+{
+	unsigned char swapped_bits = 0x0;
+	if (cas_bits & 0x8) {
+		swapped_bits |= 0x1;
+	}
+	if (cas_bits & 0x4) {
+		swapped_bits |= 0x2;
+	}
+	if (cas_bits & 0x2) {
+		swapped_bits |= 0x4;
+	}
+	if (cas_bits & 0x1) {
+		swapped_bits |= 0x8;
+	}
+	return swapped_bits;
+}
+
+static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number, unsigned char cas_bits)
 {
 	unsigned configured = 0, x;
 
+	if (type == ZAP_CHAN_TYPE_CAS) {
+		zap_log(ZAP_LOG_DEBUG, "Configuring CAS channels with abcd == 0x%X\n", cas_bits);
+	}	
 	for(x = start; x < end; x++) {
 		zap_channel_t *chan;
 		zap_socket_t sockfd = WP_INVALID_SOCKET;
@@ -401,6 +422,12 @@ static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start,
 					chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
 				}
 			}
+
+			if (type == ZAP_CHAN_TYPE_CAS) {
+				tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_WRITE_RBS_BITS;
+				tdm_api.wp_tdm_cmd.rbs_tx_bits = wanpipe_swap_bits(cas_bits);
+				wp_tdm_cmd_exec(chan, &tdm_api);
+			}
 			
 			if (!zap_strlen_zero(name)) {
 				zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
@@ -452,8 +479,9 @@ static ZIO_CONFIGURE_FUNCTION(wanpipe_configure)
 static ZIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
 {
 	int items, i;
-    char *mydata, *item_list[10];
+	char *mydata, *item_list[10];
 	char *sp, *ch, *mx;
+	unsigned char cas_bits = 0;
 	int channo;
 	int spanno;
 	int top = 0;
@@ -506,8 +534,11 @@ static ZIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
 			zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
 			continue;
 		}
-
-		configured += wp_open_range(span, spanno, channo, top, type, name, number);
+		if (ZAP_CHAN_TYPE_CAS == type && zap_config_get_cas_bits(ch, &cas_bits)) {
+			zap_log(ZAP_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+			continue;
+		}
+		configured += wp_open_range(span, spanno, channo, top, type, name, number, cas_bits);
 
 	}
 	
@@ -622,6 +653,19 @@ static ZIO_COMMAND_FUNCTION(wanpipe_command)
 			zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
 		}
 		break;
+	case ZAP_COMMAND_SET_CAS_BITS:
+		{
+			tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_WRITE_RBS_BITS;
+			tdm_api.wp_tdm_cmd.rbs_tx_bits = wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT);
+			err = wp_tdm_cmd_exec(zchan, &tdm_api);
+		}
+		break;
+	case ZAP_COMMAND_GET_CAS_BITS:
+		{
+			/* wanpipe does not has a command to get the CAS bits so we emulate it */
+			ZAP_COMMAND_OBJ_INT = zchan->cas_bits;
+		}
+		break;
 	default:
 		break;
 	};
@@ -899,6 +943,14 @@ ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
 					event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? ZAP_OOB_ONHOOK : ZAP_OOB_OFFHOOK;
 				}
 				break;
+			case WP_TDMAPI_EVENT_RBS:
+				{
+					event_id = ZAP_OOB_CAS_BITS_CHANGE;
+					/* save the CAS bits, user should retrieve it with ZAP_COMMAND_GET_CAS_BITS 
+					   is there a best play to store this? instead of adding cas_bits member to zap_chan? */
+					span->channels[i]->cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
+				}
+				break;
 			default:
 				{
 					zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
diff --git a/libs/freetdm/src/ozmod/ozmod_zt/ozmod_zt.c b/libs/freetdm/src/ozmod/ozmod_zt/ozmod_zt.c
index 43a662d9fd..4d5c7c7c01 100644
--- a/libs/freetdm/src/ozmod/ozmod_zt/ozmod_zt.c
+++ b/libs/freetdm/src/ozmod/ozmod_zt/ozmod_zt.c
@@ -51,7 +51,7 @@ static zap_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
 ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
 ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
 
-static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number)
+static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number, unsigned char cas_bits)
 {
 	unsigned configured = 0, x;
 	char path[] = "/dev/zap/channel";
@@ -59,6 +59,9 @@ static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, za
 
 	memset(&ztp, 0, sizeof(ztp));
 
+	if (type == ZAP_CHAN_TYPE_CAS) {
+		zap_log(ZAP_LOG_DEBUG, "Configuring CAS channels with abcd == 0x%X\n", cas_bits);
+	}	
 	for(x = start; x < end; x++) {
 		zap_channel_t *zchan;
 		zap_socket_t sockfd = ZT_INVALID_SOCKET;
@@ -136,6 +139,19 @@ static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, za
 				}
 			}
 
+			if (type == ZAP_CHAN_TYPE_CAS) {
+				struct zt_chanconfig cc;
+				memset(&cc, 0, sizeof(cc));
+				cc.chan = cc.master = x;
+				cc.sigtype = ZT_SIG_CAS;
+				cc.idlebits = cas_bits;
+				if (ioctl(CONTROL_FD, ZT_CHANCONFIG, &cc)) {
+					zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d err:%s", path, zchan->span_id, zchan->chan_id, sockfd, strerror(errno));
+					close(sockfd);
+					continue;
+				}
+			}
+
 			if (zchan->type != ZAP_CHAN_TYPE_DQ921 && zchan->type != ZAP_CHAN_TYPE_DQ931) {
 				len = zt_globals.codec_ms * 8;
 				if (ioctl(zchan->sockfd, ZT_SET_BLOCKSIZE, &len)) {
@@ -224,8 +240,9 @@ static ZIO_CONFIGURE_SPAN_FUNCTION(zt_configure_span)
 {
 
 	int items, i;
-    char *mydata, *item_list[10];
+        char *mydata, *item_list[10];
 	char *ch, *mx;
+	unsigned char cas_bits = 0;
 	int channo;
 	int top = 0;
 	unsigned configured = 0;
@@ -266,8 +283,11 @@ static ZIO_CONFIGURE_SPAN_FUNCTION(zt_configure_span)
 			zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
 			continue;
 		}
-
-		configured += zt_open_range(span, channo, top, type, name, number);
+		if (ZAP_CHAN_TYPE_CAS == type && zap_config_get_cas_bits(ch, &cas_bits)) {
+			zap_log(ZAP_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+			continue;
+		}
+		configured += zt_open_range(span, channo, top, type, name, number, cas_bits);
 
 	}
 	
@@ -471,6 +491,18 @@ static ZIO_COMMAND_FUNCTION(zt_command)
 			}
 		}
 		break;
+	case ZAP_COMMAND_SET_CAS_BITS:
+		{
+			int bits = ZAP_COMMAND_OBJ_INT;
+			err = ioctl(zchan->sockfd, ZT_SETTXBITS, &bits);
+		}
+		break;
+	case ZAP_COMMAND_GET_CAS_BITS:
+		{
+			/* probably we should call ZT_GETRXBITS instead? */
+			ZAP_COMMAND_OBJ_INT = zchan->cas_bits;
+		}
+		break;
 	default:
 		break;
 	};
@@ -663,6 +695,17 @@ ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
 					event_id = ZAP_OOB_ALARM_CLEAR;
 				}
 				break;
+			case ZT_EVENT_BITSCHANGED:
+				{
+					event_id = ZAP_OOB_CAS_BITS_CHANGE;
+					int bits = 0;
+					int err = ioctl(span->channels[i]->sockfd, ZT_GETRXBITS, &bits);
+					if (err) {
+						return ZAP_FAIL;
+					}
+					span->channels[i]->cas_bits = bits;
+				}
+				break;
 			default:
 				{
 					zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
diff --git a/libs/freetdm/src/ozmod/ozmod_zt/ozmod_zt.h b/libs/freetdm/src/ozmod/ozmod_zt/ozmod_zt.h
index c3e2067585..d965de4b93 100644
--- a/libs/freetdm/src/ozmod/ozmod_zt/ozmod_zt.h
+++ b/libs/freetdm/src/ozmod/ozmod_zt/ozmod_zt.h
@@ -226,9 +226,16 @@ ZT_SIG_FXOKS				= ((1 << 5) | (1 << 12)),	/* FXO, Kewlstart */
 ZT_SIG_EM					= (1 << 6),					/* E&M */
 ZT_SIG_CLEAR				= (1 << 7),
 ZT_SIG_HDLCRAW				= ((1 << 8)  | ZT_SIG_CLEAR),
-ZT_SIG_HDLCFCS				= ((1 << 9)  | ZT_SIG_HDLCRAW)
+ZT_SIG_HDLCFCS				= ((1 << 9)  | ZT_SIG_HDLCRAW),
+ZT_SIG_CAS                              = (1 << 15)
 } zt_sigtype_t;
 
+typedef enum {
+ZT_DBIT = 1,
+ZT_CBIT = 2,
+ZT_BBIT = 4,
+ZT_ABIT = 8
+} zt_cas_bit_t;
 
 /* Defines */
 
@@ -279,6 +286,10 @@ ZT_SIG_HDLCFCS				= ((1 << 9)  | ZT_SIG_HDLCRAW)
 #define		ZT_GETCONFMUTE		_IOR  (ZT_CODE, 49, int)				/* Get Conference to mute mode */
 #define		ZT_ECHOTRAIN		_IOW  (ZT_CODE, 50, int)				/* Control Echo Trainer */
 
+/* Set/Get CAS bits */
+#define ZT_SETTXBITS _IOW (ZT_CODE, 43, int)
+#define ZT_GETRXBITS _IOR (ZT_CODE, 45, int)
+
 
 #endif
 
diff --git a/libs/freetdm/src/zap_config.c b/libs/freetdm/src/zap_config.c
index cce3507f25..b1f6bd90c4 100644
--- a/libs/freetdm/src/zap_config.c
+++ b/libs/freetdm/src/zap_config.c
@@ -53,7 +53,7 @@ int zap_config_open_file(zap_config_t *cfg, const char *file_path)
 
 	memset(cfg, 0, sizeof(*cfg));
 	cfg->lockto = -1;
-
+	zap_log(ZAP_LOG_DEBUG, "Configuration file is %s.\n", path);
 	f = fopen(path, "r");
 
 	if (!f) {
@@ -209,6 +209,36 @@ int zap_config_next_pair(zap_config_t *cfg, char **var, char **val)
 
 }
 
+int zap_config_get_cas_bits(char *strvalue, unsigned char *outbits)
+{
+	char cas_bits[5];
+	unsigned char bit = 0x8;
+	char *double_colon = strchr(strvalue, ':');
+	if (!double_colon) {
+		zap_log(ZAP_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon);
+		return -1;
+	}
+	double_colon++;
+	*outbits = 0;
+	cas_bits[4] = 0;
+	if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) {
+		zap_log(ZAP_LOG_ERROR, "Invalid CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon);
+		return -1;
+	}
+	zap_log(ZAP_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits);
+	int x = 0;
+	for (; cas_bits[x]; x++) {
+		if ('1' == cas_bits[x]) {
+			*outbits |= bit;
+		} else if ('0' != cas_bits[x]) {
+			zap_log(ZAP_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n");
+			return -1;
+		}
+		bit >>= 1;
+	}
+	return 0;
+}
+
 /* For Emacs:
  * Local Variables:
  * mode:c
diff --git a/libs/freetdm/src/zap_io.c b/libs/freetdm/src/zap_io.c
index a835a78b62..444f3b85fb 100644
--- a/libs/freetdm/src/zap_io.c
+++ b/libs/freetdm/src/zap_io.c
@@ -2239,9 +2239,13 @@ static zap_status_t load_config(void)
 					configured += zio->configure_span(span, val, qtype, name, number);
 					d++;
 				}
+			} else if (!strcasecmp(var, "cas-channel")) {
+				configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_CAS, name, number);	
 			} else if (!strcasecmp(var, "dtmf_hangup")) {
 				span->dtmf_hangup = strdup(val);
 				span->dtmf_hangup_len = strlen(val);
+			} else {
+				zap_log(ZAP_LOG_ERROR, "unknown span variable '%s'\n", var);
 			}
 		} else {
 			zap_log(ZAP_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val);
@@ -2500,6 +2504,7 @@ zap_status_t zap_global_init(void)
 	zap_mutex_create(&globals.mutex);
 	
 	modcount = zap_load_modules();
+	zap_log(ZAP_LOG_NOTICE, "Modules configured: %d \n", modcount);
 
 	if (load_config() == ZAP_SUCCESS) {
 		globals.running = 1;