diff --git a/connection.h b/connection.h
deleted file mode 100644
index c74e31aa1618425bf3ee4a8381da39e9725ba621..0000000000000000000000000000000000000000
--- a/connection.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef ENDPTMNGR_CONNECTION_H
-#define ENDPTMNGR_CONNECTION_H
-
-
-//-------------------------------------------------------------
-extern struct connection_t *connection;
-
-//-------------------------------------------------------------
-int find_connection_from_asterisk_id(int line, int conId);
-
-#endif
diff --git a/libvoice/broadcom/brcm-connection.c b/libvoice/broadcom/brcm-connection.c
index 922dfce41bd2983b75eb9262766c6f4e3d323049..90f83e7a3e428a56a32db7fb460ea228b71f4053 100644
--- a/libvoice/broadcom/brcm-connection.c
+++ b/libvoice/broadcom/brcm-connection.c
@@ -1,4 +1,3 @@
-
 // Management of call connections
 
 #include <stdio.h>
@@ -8,23 +7,17 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
-#include <sched.h>																// sched_yield()
+#include <sched.h>           // sched_yield()
 
 #include <bosTypes.h>
-#include <hapi_rtp.h>															// for vrgEndptPrivate.h to work
-#include <vrgEndptCfg.h>														// for vrgEndptPrivate.h to work
-#include <bosSemLinuxUser.h>													// for vrgEndptPrivate.h to work
-#include <vrgEndptPrivate.h>													// struct VRG_ENDPT
-#include <hdspCmd.h>															// hdspSendCmd
-#include <hapi_hec.h>															// HAPI_HEC_SETREG1_CMD
-
-#include "connection.h"
-#include "main.h"
-#include "line.h"
-#include "line-dect.h"
-#include "log.h"
+#include <hapi_rtp.h>        // for vrgEndptPrivate.h to work
+#include <vrgEndptCfg.h>     // for vrgEndptPrivate.h to work
+#include <bosSemLinuxUser.h> // for vrgEndptPrivate.h to work
+#include <vrgEndptPrivate.h> // struct VRG_ENDPT
+#include <hdspCmd.h>         // hdspSendCmd
+#include <hapi_hec.h>        // HAPI_HEC_SETREG1_CMD
 
-struct connection_t *connection;
+#include "libvoice.h"
 
 //-------------------------------------------------------------
 // Create an endpoint connection and assign the unique
@@ -33,69 +26,72 @@ struct connection_t *connection;
 int voice_connection_create(int line, int conId) {
 	VRG_ENDPT *epIntern;
 	EPSTATUS status;
+	EPZCNXPARAM *epCnx;
 	int conIdx, i;
 
 	// Check that the new connection is unique
-	if(find_connection_from_asterisk_id(line, conId) != -1) {
+	if(voice_connection_find(line, conId) != -1) {
 		ENDPT_DBG("Error; duplicated connection %d %d\n", line, conId);
 		return -1;
 	}
 
 	// Find a free slot for this new connection
-	for(conIdx = 0; conIdx < epInfo.numEndpoints * MAX_NUM_CNX &&
-		connection[conIdx].line != -1 &&
-		connection[conIdx].conId != -1; conIdx++);
-	if(conIdx == epInfo.numEndpoints * MAX_NUM_CNX) {
-		ENDPT_DBG("Error; out of connetion memory %d %d\n", line, conId);
+	for(conIdx = 0;
+		conIdx < max_num_connections && connections[conIdx].line != -1 && connections[conIdx].conId != -1;
+		conIdx++);
+	if(conIdx >= max_num_connections) {
+		ENDPT_DBG("Error; out of connection memory %d %d\n", line, conId);
 		return -1;
 	}
 
 	// Find lines[line].epHandle for this connection
 	for(i = 0; i < epInfo.numEndpoints && lines[i].epHandle.lineId != line; i++);
-	if(i == epInfo.numEndpoints) {
+	if(i >= epInfo.numEndpoints) {
 		ENDPT_DBG("Error; can't find endpoint %d %d\n", line, conId);
 		return -1;
 	}
-	connection[conIdx].line = i;												
-	connection[conIdx].conId = conId;
+	connections[conIdx].line = i;
+	connections[conIdx].conId = conId;
 
 	/* Arguments for which codec to use etc. This maps endpoint
 	 * capabilites and UCI config to per connection config. */
-	memset(&connection[conIdx].epCnx, 0, sizeof(EPZCNXPARAM));
-	connection[conIdx].epCnx.mode = EPCNXMODE_SNDRX;
-	connection[conIdx].epCnx.cnxParmList.send.codecs[0].type = CODEC_PCMA;
-	connection[conIdx].epCnx.cnxParmList.recv.codecs[0].type = CODEC_PCMA;
-	connection[conIdx].epCnx.cnxParmList.send.codecs[0].rtpPayloadType =
+	epCnx = (EPZCNXPARAM *)connections[conIdx].priv;
+	memset(epCnx, 0, sizeof(EPZCNXPARAM));
+	epCnx->mode = EPCNXMODE_SNDRX;
+	epCnx->cnxParmList.send.codecs[0].type = CODEC_PCMA;
+	epCnx->cnxParmList.recv.codecs[0].type = CODEC_PCMA;
+	epCnx->cnxParmList.send.codecs[0].rtpPayloadType =
 		RTP_PAYLOAD_PCMA;
-	connection[conIdx].epCnx.cnxParmList.recv.codecs[0].rtpPayloadType =
+	epCnx->cnxParmList.recv.codecs[0].rtpPayloadType =
 		RTP_PAYLOAD_PCMA;
-	connection[conIdx].epCnx.cnxParmList.send.numCodecs = 1;
-	connection[conIdx].epCnx.cnxParmList.recv.numCodecs = 1;
-	connection[conIdx].epCnx.cnxParmList.send.numPeriods = 1;
-	connection[conIdx].epCnx.cnxParmList.recv.numPeriods = 1;
-	connection[conIdx].epCnx.cnxParmList.send.period[0] = CODEC_PTIME_20;
-	connection[conIdx].epCnx.cnxParmList.recv.period[0] = CODEC_PTIME_20;
-	connection[conIdx].epCnx.namedPhoneEvts = lines[line].epCap.nteCap;
-	connection[conIdx].epCnx.echocancel =
+	epCnx->cnxParmList.send.numCodecs = 1;
+	epCnx->cnxParmList.recv.numCodecs = 1;
+	epCnx->cnxParmList.send.numPeriods = 1;
+	epCnx->cnxParmList.recv.numPeriods = 1;
+	epCnx->cnxParmList.send.period[0] = CODEC_PTIME_20;
+	epCnx->cnxParmList.recv.period[0] = CODEC_PTIME_20;
+	epCnx->namedPhoneEvts = lines[line].epCap.nteCap;
+	epCnx->echocancel =
 		(lines[line].epCap.eCap && lines[line].uciConf.echocancel ? 1 : 0);
-	connection[conIdx].epCnx.silence =
+	epCnx->silence =
 		(lines[line].epCap.sCap && lines[line].uciConf.silence ? 1 : 0);
-	connection[conIdx].epCnx.comfortNoise = (lines[line].uciConf.comfortNoise ? 1 : 0);
-	connection[conIdx].epCnx.preserveFaxMode = 0;
-	connection[conIdx].epCnx.secHdrSize = 0;
-	connection[conIdx].epCnx.dataMode = EPDATAMODE_NONE;
-	connection[conIdx].epCnx.autoEncoder = EPAUTOENC_OFF;
-	connection[conIdx].epCnx.vbdparam.vbdMode = EPVBDMODE_NONE;
-	connection[conIdx].epCnx.digitRelayType = EPDTMFRFC2833_DISABLED;
-	connection[conIdx].epCnx.rtcpXRConfig = HAPI_RTP_RTCP_XR_GENERATE_VOIP_REPORT;
-	connection[conIdx].epCnx.txVolume = lines[line].uciConf.txgain;
-	connection[conIdx].epCnx.rxVolume = lines[line].uciConf.rxgain;
+	epCnx->comfortNoise = (lines[line].uciConf.comfortNoise ? 1 : 0);
+	epCnx->preserveFaxMode = 0;
+	epCnx->secHdrSize = 0;
+	epCnx->dataMode = EPDATAMODE_NONE;
+	epCnx->autoEncoder = EPAUTOENC_OFF;
+	epCnx->vbdparam.vbdMode = EPVBDMODE_NONE;
+	epCnx->digitRelayType = EPDTMFRFC2833_DISABLED;
+	epCnx->rtcpXRConfig = HAPI_RTP_RTCP_XR_GENERATE_VOIP_REPORT;
+	epCnx->txVolume = lines[line].uciConf.txgain;
+	epCnx->rxVolume = lines[line].uciConf.rxgain;
 
 	// Is the endpoint in onhook state? For dect we simulate offhook.
-	if(perhapsSimulateHook(line, EPEVT_OFFHOOK)) goto err;
+	if(perhapsSimulateHook(line, EPEVT_OFFHOOK))
+		goto err;
 
-	status = vrgEndptCreateConnection(&lines[connection[conIdx].line].epHandle,
-			conId, &connection[conIdx].epCnx);
+	status = vrgEndptCreateConnection(&lines[connections[conIdx].line].epHandle,
+			conId, &connections[conIdx].epCnx);
 	if (status != EPSTATUS_SUCCESS) {
 		ENDPT_DBG("Error creating connection %d: %s\n",
 			conId, strerror_endp(status));
@@ -105,7 +101,7 @@ int voice_connection_create(int line, int conId) {
 	/* Disable DSP-lib non-linear processing due to it causes audio
 	 * clipping. An alternative is to disable echo cancelation. This
 	 * method is however less intrusive we hope... */
-	if(connection[conIdx].epCnx.echocancel) {
+	if(epCnx->echocancel) {
 		epIntern = GetEndptState(line);
 		if(!epIntern) goto err;
 
@@ -119,8 +115,8 @@ int voice_connection_create(int line, int conId) {
 	return 0;
 
 err:
-	connection[conIdx].line = -1;
-	connection[conIdx].conId = -1;
+	connections[conIdx].line = -1;
+	connections[conIdx].conId = -1;
 	return -1;
 }
 
@@ -133,16 +129,17 @@ int voice_connection_close(int line, int conId) {
 
 	res = 0;
 	epIntern = GetEndptState(line);
-	if(!epIntern || epIntern->cnxCnt == 0) return 0;							// Line was already closed
+	if(!epIntern || epIntern->cnxCnt == 0) return 0; // Line was already closed
 
-	conIdx = find_connection_from_asterisk_id(line, conId);
-	if(conIdx == -1) return -1;
+	conIdx = voice_connection_find(line, conId);
+	if (conIdx == -1)
+		return -1;
 
 	// Does the the endpoint use simulated hook events? Then do onhook now.
 	res = perhapsSimulateHook(line, EPEVT_ONHOOK);
 
 	status = vrgEndptDeleteConnection(
-		&lines[connection[conIdx].line].epHandle, conId);
+		&lines[connections[conIdx].line].epHandle, conId);
 	if (status != EPSTATUS_SUCCESS) {
 		ENDPT_DBG("Error closeing connection %d\n", conId);
 		ENDPT_DBG("Error closeing connection BRCM/%d/%d\n", line, conId);
@@ -150,8 +147,8 @@ int voice_connection_close(int line, int conId) {
 	}
 
 	if(res == 0) ENDPT_DBG("Closed connection BRCM/%d/%d\n", line, conId);
-	connection[conIdx].line = -1;												// Mark connection slot free
-	connection[conIdx].conId = -1;
+	connections[conIdx].line = -1; // Mark connection slot free
+	connections[conIdx].conId = -1;
 
 	return res;
 }
@@ -163,10 +160,10 @@ int voice_connection_close_all(void) {
 
 	res = 0;
 
-	for(conIdx = 0; conIdx < epInfo.numEndpoints * MAX_NUM_CNX; conIdx++) {
-		if(connection[conIdx].line != -1 && connection[conIdx].conId != -1 &&
-				lines[connection[conIdx].line].epHandle.lineId != -1 &&
-				voice_connection_close(connection[conIdx].line, connection[conIdx].line)) {
+	for(conIdx = 0; conIdx < max_num_connections; conIdx++) {
+		if(connections[conIdx].line != -1 && connections[conIdx].conId != -1 &&
+				lines[connections[conIdx].line].epHandle.lineId != -1 &&
+				voice_connection_close(connections[conIdx].line, connections[conIdx].line)) {
 			res = -1;
 		}
 	}
@@ -178,14 +175,17 @@ int voice_connection_close_all(void) {
 // Set an existing connection into conferece call mode
 int voice_connection_conference_start(int line, int conId) {
 	EPSTATUS status;
+	EPZCNXPARAM *epCnx;
 	int conIdx;
 
-	conIdx = find_connection_from_asterisk_id(line, conId);
-	if(conIdx == -1) return -1;
+	conIdx = voice_connection_find(line, conId);
+	if(conIdx == -1)
+		return -1;
 
-	connection[conIdx].epCnx.mode = EPCNXMODE_CONF;
-	status = vrgEndptModifyConnection(&lines[connection[conIdx].line].epHandle,
-		conId, &connection[conIdx].epCnx);
+	epCnx = (EPZCNXPARAM *)connections[conIdx].priv;
+	epCnx->mode = EPCNXMODE_CONF;
+	status = vrgEndptModifyConnection(&lines[connections[conIdx].line].epHandle,
+		conId, epCnx);
 	if (status == EPSTATUS_SUCCESS) {
 		ENDPT_DBG("Enabled conference for connection %d/%d\n", line, conId);
 	}
@@ -201,14 +201,17 @@ int voice_connection_conference_start(int line, int conId) {
 // Set an existing conference call into "normal" mode
 int voice_connection_conference_stop(int line, int conId) {
 	EPSTATUS status;
+	EPZCNXPARAM *epCnx;
 	int conIdx;
 
-	conIdx = find_connection_from_asterisk_id(line, conId);
-	if(conIdx == -1) return -1;
+	conIdx = voice_connection_find(line, conId);
+	if(conIdx == -1)
+		return -1;
 
-	connection[conIdx].epCnx.mode = EPCNXMODE_SNDRX;
-	status = vrgEndptModifyConnection(&lines[connection[conIdx].line].epHandle,
-		conId, &connection[conIdx].epCnx);
+	epCnx = (EPZCNXPARAM *)connections[conIdx].priv;
+	epCnx->mode = EPCNXMODE_SNDRX;
+	status = vrgEndptModifyConnection(&lines[connections[conIdx].line].epHandle,
+		conId, epCnx);
 	if (status == EPSTATUS_SUCCESS) {
 		ENDPT_DBG("Disabled conference for connection %d/%d\n", line, conId);
 	}
@@ -221,19 +224,23 @@ int voice_connection_conference_stop(int line, int conId) {
 }
 
 //-------------------------------------------------------------
-int voice_connection_init(void) {
+int voice_connection_init(int num_terminals) {
 	int i;
 
-	// Initialize list of active connections and mark all as free
-	connection = malloc(sizeof(struct connection_t) *
-		epInfo.numEndpoints * MAX_NUM_CNX);
-	if(!connection) {
-		err_exit("Error init connection mem\n");
+	max_num_connections = num_terminals * VRG_ENDPT_CFG_MAX_CNX_PER_ENDPT;
+
+	connections = malloc(sizeof(struct connection_t) * max_num_connections);
+	if(!connections) {
+		err_exit("Error out of memory\n");
 	}
 
-	for(i = 0; i < epInfo.numEndpoints * MAX_NUM_CNX; i++) {
-		connection[i].line = -1;
-		connection[i].conId = -1;
+	for(i = 0; i < max_num_connections; i++) {
+		connections[i].line = -1;
+		connections[i].conId = -1;
+		connections[i].priv = (EPZCNXPARAM *)malloc(sizeof(EPZCNXPARAM));
+		if(!connections[i].priv) {
+			err_exit("Error out of memory\n");
+		}
 	}
 
 	return 0;
@@ -241,11 +248,15 @@ int voice_connection_init(void) {
 
 //-------------------------------------------------------------
 int voice_connection_deinit(void) {
-	// Terminate all calls
-	if(connection) {
+	int i;
+
+	if(connections) {
 		voice_connection_close_all();
-		free(connection);
-		connection = NULL;
+		for(i = 0; i < max_num_connections; i++) {
+			free(connections[i].priv);
+		}
+		free(connections);
+		connections = NULL;
 	}
 
 	return 0;
diff --git a/libvoice/broadcom/brcm-dect.c b/libvoice/broadcom/brcm-dect.c
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..594bdd3963022fd47c0736eeed766295b750d7e7 100644
--- a/libvoice/broadcom/brcm-dect.c
+++ b/libvoice/broadcom/brcm-dect.c
@@ -0,0 +1,162 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include <bosTypes.h>
+#include <vrgEndptCfg.h>      // for vrgEndptPrivate.h to work
+#include <hapi_rtp.h>         // for vrgEndptPrivate.h to work
+#include <bosSemLinuxUser.h>  // for vrgEndptPrivate.h to work
+#include <vrgEndptPrivate.h>  // struct VRG_ENDPT
+
+//-------------------------------------------------------------
+// Simulate phone line onhook for external Dect handset.
+static int setDectOnhook(int line) {
+	VRG_ENDPT *epIntern;
+	int res = 0;
+
+	ENDPT_DBG("%s: line=%d\n", __func__, line);
+
+	epIntern = GetEndptState(line);
+	if(!epIntern) {
+		ENDPT_DBG("%s: GetEndptState() failed\n", __func__);
+		return -1;
+	}
+
+	if(epIntern->cnxCnt > 1) {
+		ENDPT_DBG("%s: epIntern->cnxCnt(%d) > 1\n", __func__, epIntern->cnxCnt);
+		return 0;
+	}
+
+	if(!lines[line].simulatedHook) {
+		ENDPT_DBG("%s:lines[%d].simulatedHook=0\n", __func__, line);
+		return 0;
+	}
+
+	// Consider future hook states again.
+	if(casCtlIgnoreHookState(epIntern->casCtlHandle,
+			CAS_IGNOREHOOKSTATE_OFF) != CAS_CTL_SUCCESS) {
+		res = -1;
+	}
+
+	// Go "early onhook" and then "fully onhook".
+	if(simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_EARLY_ONHOOK) ||
+			simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_ONHOOK)) {
+		res = -1;
+	}
+
+	// Restore libvoip force onhook timeout.
+	if(vrgEndptProvSet(line, EPPROV_MinDisconnect, &lines[line].defMinDisconnect,
+			sizeof(uint32_t)) != EPSTATUS_SUCCESS) {
+		res = -1;
+	}
+	lines[line].simulatedHook = 0;
+	lines[line].signalizedCw = 0;
+
+	return res;
+}
+
+//-------------------------------------------------------------
+// Simulate phone line offhook for Dect handset.
+static int setDectOffhook(int line) {
+	uint32_t onhookTimeout = CAS_IGNOREHOOKSTATE_ON;							// 16-bit variable in libvoip
+	VRG_ENDPT *epIntern;
+	EPSTATUS status;
+
+	epIntern = GetEndptState(line);
+	if(!epIntern)
+		return -1;
+	if(epIntern->cnxCnt > 1)
+		return 0;
+	if(isLineOffhook(line))
+		return 0;// No need for offhook
+	ENDPT_DBG("%s() BRCM/%d\n", __func__, line);
+
+	// Extend the time until libvoip force onhooks.
+	status = vrgEndptProvSet(line, EPPROV_MinDisconnect,
+		&onhookTimeout, sizeof(uint32_t));
+	if(status != EPSTATUS_SUCCESS) {
+		ENDPT_DBG("Error setting force onhook time %d: %s\n",
+			line, strerror_endp(status));
+		goto err;
+	}
+
+	// Go "early offhook" and then "fully offhook".
+	if(simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_EARLY_OFFHOOK) ||
+			simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_OFFHOOK)) {
+		goto err;
+	}
+
+	// Ignore future hook state.
+	if(casCtlIgnoreHookState(epIntern->casCtlHandle,
+			CAS_IGNOREHOOKSTATE_ON) == CAS_CTL_SUCCESS) {
+		ENDPT_DBG("Simulated offhook for BRCM/%d/%c\n", line, '*');
+		lines[line].simulatedHook = 1;
+	}
+	else {
+		goto err;
+	}
+
+	return 0;
+err:
+	setDectOnhook(line);
+	return -1;
+}
+
+//-------------------------------------------------------------
+// Simulate Dect hook flash (the R-key).
+static int doDectHookFlash(int line) {
+	VRG_ENDPT *epIntern;
+
+	epIntern = GetEndptState(line);
+	if(!epIntern) return -1;
+	if(epIntern->cnxCnt == 0) return 0; // No need for hook flash
+	if(!lines[line].simulatedHook) return 0;
+	if(!isLineOffhook(line)) return 0;
+	ENDPT_DBG("%s() BRCM/%d\n", __func__, line);
+
+	// Go "early onhook", "early offhook" and then "flash".
+	if(simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_EARLY_ONHOOK) ||
+			simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_EARLY_OFFHOOK) ||
+			simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_FLASH)) {
+		goto err;
+	}
+
+	// Ignore future hook state.
+	if(casCtlIgnoreHookState(epIntern->casCtlHandle,
+			CAS_IGNOREHOOKSTATE_ON) == CAS_CTL_SUCCESS) {
+		ENDPT_DBG("Simulated hook flash (R-key) for BRCM/%d\n", line);
+	}
+	else {
+		goto err;
+	}
+
+	return 0;
+err:
+	setDectOnhook(line);
+	return -1;
+}
+
+//-------------------------------------------------------------
+// If necessary, simulate an phone line event.
+int perhapsSimulateHook(int line, EPEVT event) {
+	if(lines[line].epHandle.endptType != EPTYPE_DECT) return 0;
+
+	switch(event) {
+		case EPEVT_ONHOOK:
+			return setDectOnhook(line);
+
+		case EPEVT_OFFHOOK:
+			return setDectOffhook(line);
+
+		case EPEVT_FLASH:
+			return doDectHookFlash(line);
+
+		default:
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/libvoice/broadcom/brcm-line.c b/libvoice/broadcom/brcm-line.c
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..392f2bdbab09422ecc09451aaf796829745cac8b 100644
--- a/libvoice/broadcom/brcm-line.c
+++ b/libvoice/broadcom/brcm-line.c
@@ -0,0 +1,24 @@
+#include <endpoint_api.h>
+#include <vrgEndptCfg.h>	// VRG_ENDPT_CFG_MAX_CNX_PER_ENDPT
+#include <casCtl.h>			// CAS_CTL_DETECT_EVENT
+#include <hapi_hec.h>		// HAPI_HEC_VOLUME_MAX
+
+int voice_get_min_tx_gain(void)
+{
+	return HAPI_HEC_GAIN_MIN;
+}
+
+int voice_get_max_tx_gain(void)
+{
+	return HAPI_HEC_GAIN_MAX;
+}
+
+int voice_get_min_rx_gain(void)
+{
+	return HAPI_HEC_VOLUME_MIN;
+}
+
+int voice_get_max_rx_gain(void)
+{
+	return HAPI_HEC_VOLUME_MAX;
+}
diff --git a/libvoice/common.c b/libvoice/common.c
new file mode 100644
index 0000000000000000000000000000000000000000..da34c35c845b7bb0f4c58a017e4242b322f7bf6c
--- /dev/null
+++ b/libvoice/common.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+#include <libvoice.h>
+
+struct connection_t *connections = NULL;
+int max_num_connections = 0;
+
+int voice_connection_find(int line, int conId)
+{
+	int conIdx;
+
+	for(conIdx = 0; conIdx < max_num_connections; conIdx++) {
+		if(connections[conIdx].line == line && connections[conIdx].conId == conId) {
+			return conIdx;
+		}
+	}
+
+	return -1;
+}
diff --git a/libvoice/libvoice.h b/libvoice/libvoice.h
index 7e98cf3b940441d53f079843d54be4a7ec5267aa..8a1d82fb8c6180407853911f52c3ff07f41045ce 100644
--- a/libvoice/libvoice.h
+++ b/libvoice/libvoice.h
@@ -1,18 +1,59 @@
 #ifndef __LIBVOICE_H
 #define __LIBVOICE_H
 
-struct connection_t {															// Per connection parameters (one line can have many connections)
-	int line;																	// Logical line VOICE_DAUGHTER_BOARD_PARMS.BP_CHAN_PCM[i]
-	int conId;																	// Arbitrary number from Asterisk
-	EPZCNXPARAM epCnx;
+#include <stdint.h>
+
+struct connection_t { // Per connection parameters (one line can have many connections)
+	int line;         // Logical line VOICE_DAUGHTER_BOARD_PARMS.BP_CHAN_PCM[i]
+	int conId;        // Arbitrary number from Asterisk
+	void *priv;       // Platform dependent data
+};
+
+struct rtp_stats_t {
+	uint16_t local_burst_density;
+	uint16_t remote_burst_density;
+	uint16_t local_burst_duration;
+	uint16_t remote_burst_duration;
+	uint16_t local_gap_density;
+	uint16_t remote_gap_density;
+	uint16_t local_gap_duration;
+	uint16_t remote_gap_duration;
+	uint16_t local_jb_rate;
+	uint16_t remote_jb_rate;
+	uint16_t local_jb_max;
+	uint16_t remote_jb_max;
+	uint16_t local_jb_nominal;
+	uint16_t remote_jb_nominal;
+	uint16_t local_jb_abs_max;
+	uint16_t remote_jb_abs_max;
+	uint32_t discarded;
+	uint32_t lost;
+	uint32_t rxpkts;
+	uint32_t txpkts;
+	uint16_t jb_avg;
+	uint32_t jitter;
+	uint16_t loss_rate;
+	uint32_t max_jitter;
+	uint32_t avg_round_trip_delay;
 };
 
+extern struct connection_t *connections;
+extern int max_num_connections;
+
+// Connection API
+int voice_connection_init(int num_terminals);
+int voice_connection_deinit(void);
 int voice_connection_create(int line, int conId);
 int voice_connection_close(int line, int conId);
 int voice_connection_close_all(void);
 int voice_connection_conference_start(int line, int conId);
 int voice_connection_conference_stop(int line, int conId);
-int voice_connection_init(void);
-int voice_connection_deinit(void);
+int voice_connection_find(int line, int conId);
+
+// Misc
+int voice_get_min_tx_gain(void);
+int voice_get_max_tx_gain(void);
+int voice_get_min_rx_gain(void);
+int voice_get_max_rx_gain(void);
 
 #endif
diff --git a/line-dect.c b/line-dect.c
index b8fa69626ab91423daddb4bfe4eb2f43eddaea5f..b2cda9080a8862c1025b3c93ceec0e98b319bbe9 100644
--- a/line-dect.c
+++ b/line-dect.c
@@ -10,16 +10,9 @@
 #include <sys/types.h>
 #include <assert.h>
 
-#include <bosTypes.h>
-#include <vrgEndptCfg.h>      // for vrgEndptPrivate.h to work
-#include <hapi_rtp.h>         // for vrgEndptPrivate.h to work
-#include <bosSemLinuxUser.h>  // for vrgEndptPrivate.h to work
-#include <vrgEndptPrivate.h>  // struct VRG_ENDPT
-
 #include "line-dect.h"
 #include "line.h"
 #include "ubus.h"
-#include "connection.h"
 #include "log.h"
 
 //-------------------------------------------------------------
@@ -86,156 +79,6 @@ int ubus_process_queued_reqs_to_dectmngr(void) {
 	return 0;
 }
 
-//-------------------------------------------------------------
-// Simulate phone line onhook for external Dect handset.
-static int setDectOnhook(int line) {
-	VRG_ENDPT *epIntern;
-	int res = 0;
-
-	ENDPT_DBG("%s: line=%d\n", __func__, line);
-
-	epIntern = GetEndptState(line);
-	if(!epIntern) {
-		ENDPT_DBG("%s: GetEndptState() failed\n", __func__);
-		return -1;
-	}
-
-	if(epIntern->cnxCnt > 1) {
-		ENDPT_DBG("%s: epIntern->cnxCnt(%d) > 1\n", __func__, epIntern->cnxCnt);
-		return 0;
-	}
-
-	if(!lines[line].simulatedHook) {
-		ENDPT_DBG("%s:lines[%d].simulatedHook=0\n", __func__, line);
-		return 0;
-	}
-
-	// Consider future hook states again.
-	if(casCtlIgnoreHookState(epIntern->casCtlHandle,
-			CAS_IGNOREHOOKSTATE_OFF) != CAS_CTL_SUCCESS) {
-		res = -1;
-	}
-
-	// Go "early onhook" and then "fully onhook".
-	if(simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_EARLY_ONHOOK) ||
-			simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_ONHOOK)) {
-		res = -1;
-	}
-
-	// Restore libvoip force onhook timeout.
-	if(vrgEndptProvSet(line, EPPROV_MinDisconnect, &lines[line].defMinDisconnect,
-			sizeof(uint32_t)) != EPSTATUS_SUCCESS) {
-		res = -1;
-	}
-	lines[line].simulatedHook = 0;
-	lines[line].signalizedCw = 0;
-
-	return res;
-}
-
-//-------------------------------------------------------------
-// Simulate phone line offhook for Dect handset.
-static int setDectOffhook(int line) {
-	uint32_t onhookTimeout = CAS_IGNOREHOOKSTATE_ON;							// 16-bit variable in libvoip
-	VRG_ENDPT *epIntern;
-	EPSTATUS status;
-
-	epIntern = GetEndptState(line);
-	if(!epIntern)
-		return -1;
-	if(epIntern->cnxCnt > 1)
-		return 0;
-	if(isLineOffhook(line))
-		return 0;// No need for offhook
-	ENDPT_DBG("%s() BRCM/%d\n", __func__, line);
-
-	// Extend the time until libvoip force onhooks.
-	status = vrgEndptProvSet(line, EPPROV_MinDisconnect,
-		&onhookTimeout, sizeof(uint32_t));
-	if(status != EPSTATUS_SUCCESS) {
-		ENDPT_DBG("Error setting force onhook time %d: %s\n",
-			line, strerror_endp(status));
-		goto err;
-	}
-
-	// Go "early offhook" and then "fully offhook".
-	if(simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_EARLY_OFFHOOK) ||
-			simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_OFFHOOK)) {
-		goto err;
-	}
-
-	// Ignore future hook state.
-	if(casCtlIgnoreHookState(epIntern->casCtlHandle,
-			CAS_IGNOREHOOKSTATE_ON) == CAS_CTL_SUCCESS) {
-		ENDPT_DBG("Simulated offhook for BRCM/%d/%c\n", line, '*');
-		lines[line].simulatedHook = 1;
-	}
-	else {
-		goto err;
-	}
-
-	return 0;
-err:
-	setDectOnhook(line);
-	return -1;
-}
-
-//-------------------------------------------------------------
-// Simulate Dect hook flash (the R-key).
-static int doDectHookFlash(int line) {
-	VRG_ENDPT *epIntern;
-
-	epIntern = GetEndptState(line);
-	if(!epIntern) return -1;
-	if(epIntern->cnxCnt == 0) return 0; // No need for hook flash
-	if(!lines[line].simulatedHook) return 0;
-	if(!isLineOffhook(line)) return 0;
-	ENDPT_DBG("%s() BRCM/%d\n", __func__, line);
-
-	// Go "early onhook", "early offhook" and then "flash".
-	if(simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_EARLY_ONHOOK) ||
-			simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_EARLY_OFFHOOK) ||
-			simulate_hook_event(&lines[line].epHandle, CAS_CTL_EVENT_FLASH)) {
-		goto err;
-	}
-
-	// Ignore future hook state.
-	if(casCtlIgnoreHookState(epIntern->casCtlHandle,
-			CAS_IGNOREHOOKSTATE_ON) == CAS_CTL_SUCCESS) {
-		ENDPT_DBG("Simulated hook flash (R-key) for BRCM/%d\n", line);
-	}
-	else {
-		goto err;
-	}
-
-	return 0;
-err:
-	setDectOnhook(line);
-	return -1;
-}
-
-//-------------------------------------------------------------
-// If necessary, simulate an phone line event.
-int perhapsSimulateHook(int line, EPEVT event) {
-	if(lines[line].epHandle.endptType != EPTYPE_DECT) return 0;
-
-	switch(event) {
-		case EPEVT_ONHOOK:
-			return setDectOnhook(line);
-
-		case EPEVT_OFFHOOK:
-			return setDectOffhook(line);
-
-		case EPEVT_FLASH:
-			return doDectHookFlash(line);
-
-		default:
-			return -1;
-	}
-
-	return 0;
-}
-
 //-------------------------------------------------------------
 // If appropriate, simulate keypad digit presses. Returns
 // true if something was sent and false if not.
diff --git a/line.c b/line.c
index 65effb343ffc1a63223516e2dd278c52eb8a151c..bf2651e45d30d76fa523b1a8e69465a91cfdbf00 100644
--- a/line.c
+++ b/line.c
@@ -441,15 +441,15 @@ void lineAudioTx(pe_packet_t *p) {
 	}
 
 	ep_packet.packetp = ap->rtp;
-	conIdx = find_connection_from_asterisk_id(ap->line, ap->cnx_id);
+	conIdx = voice_connection_find(ap->line, ap->cnx_id);
 
 	if (conIdx == -1 || (ap->rtp[0] != 0x80 && ap->rtp[0] != 0x81) || !ap->rtp_size ||
-			lines[connection[conIdx].line].epHandle.lineId == -1) {
+			lines[connections[conIdx].line].epHandle.lineId == -1) {
 		ENDPT_DBG("bad audio packet\n");
 		return;
 	}
 
-	ret = vrgEndptPacket(&lines[connection[conIdx].line].epHandle,
+	ret = vrgEndptPacket(&lines[connections[conIdx].line].epHandle,
 			ap->cnx_id, &ep_packet, ap->rtp_size, 0);
 	if (ret != EPSTATUS_SUCCESS) {
 		ENDPT_DBG("Error vrgEndptPacket: %s\n", strerror_endp(ret));
@@ -1363,18 +1363,3 @@ int voice_get_rtp_stats(int line, int connection, int reset, struct rtp_stats_t
 
 	return 0;
 }
-
-//-------------------------------------------------------------
-// Map the phone line and connection ID Asterisk use
-// to our internal list of connections.
-int find_connection_from_asterisk_id(int line, int conId) {
-	int conIdx;
-
-	for(conIdx = 0; conIdx < epInfo.numEndpoints * MAX_NUM_CNX; conIdx++) {
-		if(connection[conIdx].line == line && connection[conIdx].conId == conId) {
-			return conIdx;
-		}
-	}
-
-	return -1;
-}
diff --git a/line.h b/line.h
index 498e3516ed62610de67a8ba9c149b9cafc1630d2..7fd220b9f1c2e118b97f6fd0ed9e37587ebf01ca 100644
--- a/line.h
+++ b/line.h
@@ -3,33 +3,9 @@
 
 #include <stdint.h>
 
-#if defined(PLATFORM_BROADCOM)
-#include <endpoint_api.h>
-#include <vrgEndptCfg.h>	// VRG_ENDPT_CFG_MAX_CNX_PER_ENDPT
-#include <casCtl.h>			// CAS_CTL_DETECT_EVENT
-#include <hapi_hec.h>		// HAPI_HEC_VOLUME_MAX
-#elif defined(PLATFORM_QUALCOMM)
-// TODO: include Qualcomm specific headers
-#endif
 #include <libpicoevent.h>
-
 #include "ubus.h"
 
-//-------------------------------------------------------------
-#if defined(PLATFORM_BROADCOM)
-#define MAX_NUM_CNX		(VRG_ENDPT_CFG_MAX_CNX_PER_ENDPT)	// Max number of connections per phone line
-#define TX_GAIN_MIN		HAPI_HEC_GAIN_MIN
-#define TX_GAIN_MAX		HAPI_HEC_GAIN_MAX
-#define RX_GAIN_MIN		HAPI_HEC_VOLUME_MIN
-#define RX_GAIN_MAX		HAPI_HEC_VOLUME_MAX
-#elif defined(PLATFORM_QUALCOMM)
-// TODO: Qualcomm specific values
-#define MAX_NUM_CNX
-#define TX_GAIN_MIN
-#define TX_GAIN_MAX
-#define RX_GAIN_MIN
-#define RX_GAIN_MAX
-#endif
 #define MAX_CALLID_LEN		120		// Max length of caller id string we accept.
 #define MAX_KEYPAD_DIGITS	100		// Max number of simulated keypad presses we accept.
 
@@ -129,35 +105,6 @@ struct lineReq_t {
 	struct ubusReq_t ubus;
 };
 
-struct rtp_stats_t {
-	uint16_t local_burst_density;
-	uint16_t remote_burst_density;
-	uint16_t local_burst_duration;
-	uint16_t remote_burst_duration;
-	uint16_t local_gap_density;
-	uint16_t remote_gap_density;
-	uint16_t local_gap_duration;
-	uint16_t remote_gap_duration;
-	uint16_t local_jb_rate;
-	uint16_t remote_jb_rate;
-	uint16_t local_jb_max;
-	uint16_t remote_jb_max;
-	uint16_t local_jb_nominal;
-	uint16_t remote_jb_nominal;
-	uint16_t local_jb_abs_max;
-	uint16_t remote_jb_abs_max;
-	uint32_t discarded;
-	uint32_t lost;
-	uint32_t rxpkts;
-	uint32_t txpkts;
-	uint16_t jb_avg;
-	uint32_t jitter;
-	uint16_t loss_rate;
-	uint32_t max_jitter;
-	uint32_t avg_round_trip_delay;
-};
-
-
 //-------------------------------------------------------------
 extern struct ep_info_t epInfo;		// Misc info about the endpoint from low level driver
 extern struct line_t *lines;		// Array of phone lines (endpoints) indexed by logical number
diff --git a/main.c b/main.c
index e300b1e94d99401e44abf190c0efecdb7825b03d..207a34f6869023562e62e45474a0bcbd02cf86ca 100644
--- a/main.c
+++ b/main.c
@@ -212,7 +212,7 @@ int main(void) {
 	if(config_init(context, package)) goto err;
 	package = NULL; // the package has been unloaded by config_init()
 	if(lineInit()) goto err;
-	if(voice_connection_init()) goto err;
+	if(voice_connection_init(epInfo.numEndpoints)) goto err;
 	if(perhaps_erase_unuseds_lines(context)) goto err;
 	if(ubus_enable_receive()) goto err;
 
diff --git a/ubus.c b/ubus.c
index d0c493eb33dfcb6bccb7decf34719a7cca7e9e8e..37807424aaad5f6be40072c2bcabea595f265036 100644
--- a/ubus.c
+++ b/ubus.c
@@ -10,6 +10,7 @@
 #include <assert.h>
 
 #include <libpicoevent.h>
+#include <libvoice.h>
 #include "ubus.h"
 #include "line.h"
 #include "line-dect.h"
@@ -386,7 +387,7 @@ static void uci_query_lineX(struct uci_context *context, struct uci_section *sec
 		free(error);
 	} else {
 		intVal = strtol(strVal, NULL, 10);
-		if(intVal >= TX_GAIN_MIN && intVal <= TX_GAIN_MAX) {
+		if(intVal >= voice_get_min_tx_gain() && intVal <= voice_get_max_tx_gain()) {
 			lines[phoneLine].uciConf.txgain = intVal;
 			ENDPT_DBG("  %s=%d\n", option, intVal);
 		} else {
@@ -402,7 +403,7 @@ static void uci_query_lineX(struct uci_context *context, struct uci_section *sec
 		free(error);
 	} else {
 		intVal = strtol(strVal, NULL, 10);
-		if(intVal >= RX_GAIN_MIN && intVal <= RX_GAIN_MAX) {
+		if(intVal >= voice_get_min_rx_gain() && intVal <= voice_get_max_rx_gain()) {
 			lines[phoneLine].uciConf.rxgain = intVal;
 			ENDPT_DBG("  %s=%d\n", option, intVal);
 		} else {
@@ -723,9 +724,9 @@ static int ubus_request_rtp_stats(struct ubus_context *uctx, struct ubus_object
 	reset = blobmsg_get_bool(keys[RTP_STATS_RESET]);
 
 	// Make sure this line has an active connection
-	for(conIdx = 0; conIdx < (epInfo.numEndpoints * MAX_NUM_CNX) && connection[conIdx].line != line; conIdx++)
+	for(conIdx = 0; conIdx < max_num_connections && connections[conIdx].line != line; conIdx++)
 		continue;
-	if (conIdx >= epInfo.numEndpoints * MAX_NUM_CNX) {
+	if (conIdx >= max_num_connections) {
 		ENDPT_DBG("Error: out of connection memory %d\n", line);
 		return UBUS_STATUS_UNKNOWN_ERROR;
 	}
@@ -734,7 +735,7 @@ static int ubus_request_rtp_stats(struct ubus_context *uctx, struct ubus_object
 	if(blob_buf_init(&blob, 0))
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
-	if (voice_get_rtp_stats(line, connection[conIdx].conId, reset, &rtp_stats) != 0)
+	if (voice_get_rtp_stats(line, connections[conIdx].conId, reset, &rtp_stats) != 0)
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
 	blobmsg_add_u16(&blob, "lineId", line);