ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/services/dxslic/api_lib/src/dxs_access.c b/marvell/services/dxslic/api_lib/src/dxs_access.c
new file mode 100644
index 0000000..d17d4ea
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_access.c
@@ -0,0 +1,577 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_access.c
+ Implementation of low level access functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdio.h>
+#include <semaphore.h>
+
+#include "dxs_lib.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_spi.h"
+#include "dxs_access.h"
+#include "dxs_init.h"
+#ifdef EVENT_LOGGER_DEBUG
+#include <sys/ioctl.h>
+#endif
+
+#include "dxslic_spi.h"
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+/* SPI header length in bytes */
+#define DXS_SPI_HDR_LENGTH 2 /* in bytes */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+#if 0
+//debug
+static int32_t dxs_spi_write(
+ int fd,
+ uint8_t offset,
+ uint16_t *pbuf,
+ uint32_t len);
+
+static int32_t dxs_spi_read(
+ int fd,
+ uint8_t offset,
+ uint16_t *pbuf,
+ uint32_t len);
+
+#endif
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+#ifdef EVENT_LOGGER_DEBUG
+static void dxs_el_trace_reg_wr(DXS_DEVICE_t *pDev,
+ int32_t reg_offset,
+ uint16_t *reg_data,
+ int32_t data_count)
+{
+ EL_IoctlAddLog_t stLog;
+ stLog.nLogType = EL_LOG_TYPE_REG_WR;
+ stLog.nOrygLogType = EL_MAX_LOG_TYPE;
+ stLog.nDevType = DXS_LIB_DEV_TYPE;
+ stLog.nDevNum = pDev->nDevNum;
+ stLog.nChNum = 0;
+ stLog.uLogDetails.stReg_Wr.nReg_offset = (reg_offset);
+ stLog.uLogDetails.stReg_Wr.pReg_data = (uint8_t *)(reg_data);
+ stLog.uLogDetails.stReg_Wr.nDataLength = (data_count);
+ stLog.uLogDetails.stReg_Wr.nCount = (data_count);
+ ioctl(pDev->el_fd, EL_ADD_LOG, (int32_t)&stLog);
+}
+
+static void dxs_el_trace_reg_rd(DXS_DEVICE_t *pDev,
+ int32_t reg_offset,
+ uint16_t *reg_data,
+ int32_t data_count)
+{
+ EL_IoctlAddLog_t stLog;
+ stLog.nLogType = EL_LOG_TYPE_REG_RD;
+ stLog.nOrygLogType = EL_MAX_LOG_TYPE;
+ stLog.nDevType = DXS_LIB_DEV_TYPE;
+ stLog.nDevNum = pDev->nDevNum;
+ stLog.nChNum = 0;
+ stLog.uLogDetails.stReg_Rd.nReg_offset = (reg_offset);
+ stLog.uLogDetails.stReg_Rd.pReg_data = (uint8_t *)(reg_data);
+ stLog.uLogDetails.stReg_Rd.nDataLength = (data_count);
+ stLog.uLogDetails.stReg_Rd.nCount = (data_count);
+ ioctl(pDev->el_fd, EL_ADD_LOG, (int32_t)&stLog);
+}
+#endif
+
+static uint32_t dxs_spi_max_frag_size_get()
+{
+ DXS_DEVICE_t *pDev = dxs_get_dev(0);
+
+ return (pDev->access == DXS_ACCESS_CSI) ?
+ SPI_MAX_BUFF_SIZE_CSI : SPI_MAXBYTES_SIZE;
+}
+
+/**
+ Write a value to one chip register.
+
+ \param pDev Pointer to device struct.
+ \param offset Register offset (address).
+ \param pValue 16-bit word value to write.
+
+ \return
+ Error code from dxs_spi_write().
+*/
+int32_t DXS_RegWrite( DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t nValue)
+{
+ int32_t ret;
+
+ if (pDev->access == DXS_ACCESS_CSI)
+ {
+ uint16_t tmp[2];
+
+ tmp[0] = tmp[1] = nValue;
+ ret = dxs_spi_write(pDev->spidev, offset, tmp, sizeof(tmp));
+ }
+ else
+ {
+ uint16_t tmp = nValue;
+
+ ret = dxs_spi_write(pDev->spidev, offset, &tmp, 2);
+ }
+
+#ifdef EVENT_LOGGER_DEBUG
+ dxs_el_trace_reg_wr(pDev, offset, &nValue, 2);
+#endif
+
+ /* fprintf (stderr, "[rw] %02X: %04X\n", offset, tmp); */
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Read a value from one chip register.
+
+ \param pDev Pointer to device struct.
+ \param offset Register offset (address).
+ \param pValue Pointer to variable where to return
+ the 16-bit word value.
+
+ \return
+ Error code from dxs_spi_read().
+*/
+int32_t DXS_RegRead( DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t *pValue)
+{
+ int32_t ret;
+
+ if (pDev->access == DXS_ACCESS_CSI)
+ {
+ uint16_t tmp[2];
+
+ ret = dxs_spi_read(pDev->spidev, offset, tmp, sizeof(tmp));
+ *pValue = tmp[1];
+ }
+ else
+ {
+ ret = dxs_spi_read(pDev->spidev, offset, pValue, 2);
+ }
+
+#ifdef EVENT_LOGGER_DEBUG
+ dxs_el_trace_reg_rd(pDev, offset, pValue, 2);
+#endif
+
+ /* fprintf (stderr, "[rr] %02X: %04X\n", offset, *pValue); */
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Write multiple consecutive chip registers.
+
+ \param pDev Pointer to device struct.
+ \param offset Register offset (address).
+ \param pValue Pointer to array with 16-bit word values to write.
+ \param count Number of 16-bit words to write.
+
+ \return
+ Error code from dxs_spi_write().
+*/
+int32_t DXS_RegWriteMulti(
+ DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t *nValue,
+ uint8_t count)
+{
+ int32_t ret;
+
+ ret = dxs_spi_write(pDev->spidev, offset, nValue, (2*count));
+
+#ifdef EVENT_LOGGER_DEBUG
+ dxs_el_trace_reg_wr(pDev, offset, nValue, (2*count));
+#endif
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Read multiple consecutive chip registers.
+
+ \param pDev Pointer to device struct.
+ \param offset Register offset (address).
+ \param pValue Pointer to array where to return the 16-bit word values.
+ \param count Number of 16-bit words to read.
+
+ \return
+ Error code from dxs_spi_read().
+*/
+int32_t DXS_RegReadMulti(
+ DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t *pValue,
+ uint8_t count)
+{
+ int32_t ret;
+
+ ret = dxs_spi_read(pDev->spidev, offset, pValue, (2*count));
+
+#ifdef EVENT_LOGGER_DEBUG
+ dxs_el_trace_reg_rd(pDev, offset, pValue, (2*count));
+#endif
+
+ DXS_RETURN(ret);
+}
+
+
+/* ************************ endianess correct copy ****************************/
+
+/**
+ Copy a 16-bit-word buffer into a byte buffer respecting the endianess.
+
+ Odd and even offsets and length are handled by this function.
+ In place copy is possible but otherwise the buffers must not overlap.
+
+ \param pBbuf Pointer to byte buffer. (Destination)
+ \param pWbuf Pointer to 16-bit-word buffer. (Source)
+ \param nWoffset Offset in bytes within the source buffer.
+ \param nB Number of bytes to be copied.
+*/
+void DXS_cpw2b ( uint8_t *pBbuf,
+ const uint16_t * const pWbuf,
+ const uint32_t nWoffset,
+ const uint32_t nB)
+{
+ uint32_t i;
+ uint16_t nWord;
+
+ for (i = 0; i < nB; i++)
+ {
+ nWord = pWbuf[(nWoffset + i) >> 1];
+ pBbuf[i] = (uint8_t)
+ ((((nWoffset+i) % 2) ? nWord : nWord >> 8) & 0xFF);
+ }
+}
+
+/**
+ Copy a byte buffer into a 16-bit-word buffer respecting the endianness.
+
+ In place copy is possible but otherwise the buffers must not overlap.
+ When an odd number of bytes is to be copied the missing byte in the
+ 16-bit-word is filled with zero.
+
+ \param pWbuf Word buffer.
+ \param pBbuf Byte buffer.
+ \param nB Number of Bytes to be copied.
+*/
+void DXS_cpb2w ( uint16_t *pWbuf,
+ const uint8_t * const pBbuf,
+ uint32_t nB)
+{
+ uint32_t i;
+ uint16_t nWord;
+
+ for (i=0; i < nB; i+=2)
+ {
+ /* Copy each byte separately into the word buffer. Make sure that when
+ an index out of range is addressed zero is copied instead. */
+ nWord = (uint16_t)pBbuf[i+0] << 8;
+ if ((i+1) < nB)
+ {
+ /* LSB is only added when index is within range. */
+ nWord |= (uint16_t)pBbuf[i+1];
+ }
+ pWbuf[i>>1] = nWord;
+ }
+}
+
+
+/**
+ Copy a byte buffer into a 32-bit-word buffer respecting the endianness.
+
+ In place copy is possible but otherwise the buffers must not overlap.
+ When an odd number of bytes is to be copied the missing bytes in the
+ 32-bit-word is filled with zero.
+
+ \param pWbuf Word buffer.
+ \param pBbuf Byte buffer.
+ \param nB Number of Bytes to be copied.
+*/
+void DXS_cpb2dw ( uint32_t *pWbuf,
+ const uint8_t * const pBbuf,
+ uint32_t nB)
+{
+ uint32_t i;
+ uint32_t nWord;
+
+ for (i=0; i < nB; i+=4)
+ {
+ /* Copy each byte separately into the word buffer. Make sure that when
+ an index out of range is addressed zero is copied instead. */
+ nWord = (uint32_t)pBbuf[i+0] << 24;
+ if ((i+1) < nB)
+ nWord |= (uint32_t)pBbuf[i+1] << 16;
+ if ((i+2) < nB)
+ nWord |= (uint32_t)pBbuf[i+2] << 8;
+ if ((i+3) < nB)
+ nWord |= (uint32_t)pBbuf[i+3];
+ pWbuf[i>>2] = nWord;
+ }
+}
+
+/***************************** SPI bus adaption ******************************/
+
+/**
+ Write a number of bytes to a given DXS register using SPI.
+
+ If the length of the data exceeds the SPI_MAXBYTES_SIZE this function
+ fragments the data into multiple blocks and calls the SPI write interface
+ repeatedly until all data is transmitted.
+
+ \param fd Filedescriptor of the SPI driver.
+ \param offset DXS register address.
+ \param pbuf Pointer to buffer with data to be written.
+ \param len Number of bytes to write.
+
+ \return
+ DXS_statusOk or error code.
+*/
+int32_t dxs_spi_write(int fd, uint8_t offset, uint16_t *pbuf, uint32_t len)
+{
+ uint8_t tx_buf[SPI_MAXBYTES_SIZE];
+ uint32_t tx_buf_length,
+ written,
+ fragment_length;
+ int32_t ret = DXS_statusOk;
+
+ uint32_t max_frag_sz = dxs_spi_max_frag_size_get();
+
+ /* TODO: len and offset assertion */
+ /* TODO: setup SPI */
+
+ /* This variable counts the number of bytes already written. */
+ written = 0;
+ /* Build SPI header (16-bit word) */
+#if SPI_IOC_WR_BITS_PER_WORD_8BITS
+ /* SPI_IOC_WR_BITS_PER_WORD is 8bits */
+ tx_buf[0] = 0x7E;
+ tx_buf[1] = offset;
+
+ if (offset == DXS_REG_CSI_M_CFG || offset == DXS_REG_CSI_M_STAT)
+ {
+ tx_buf[1] <<= 1;
+ }
+#else
+ /* SPI_IOC_WR_BITS_PER_WORD is 16bits */
+ tx_buf[0] = offset;
+ tx_buf[1] = 0x7E;
+
+ if (offset == DXS_REG_CSI_M_CFG || offset == DXS_REG_CSI_M_STAT)
+ {
+ tx_buf[0] <<= 1;
+ }
+#endif
+
+ /* The tx_buf now contains the SPI header. */
+ tx_buf_length = DXS_SPI_HDR_LENGTH;
+
+ while ((ret == DXS_statusOk) && (written < len))
+ {
+ /* Calculate the amount of payload bytes that can be sent during one
+ write call. */
+ fragment_length = len - written; /* remaining bytes to transfer */
+ if (fragment_length > (max_frag_sz - tx_buf_length))
+ {
+ /* Limit the transfer to the maximum the SPI can transmit. */
+ fragment_length = (max_frag_sz - tx_buf_length);
+ }
+#if SPI_IOC_WR_BITS_PER_WORD_8BITS
+ /* SPI_IOC_WR_BITS_PER_WORD is 8bits */
+
+ /* Copy the payload into the write buffer with correct endianess. */
+ DXS_cpw2b(tx_buf+tx_buf_length, pbuf, written, fragment_length);
+#else
+ /* SPI_IOC_WR_BITS_PER_WORD is 16bits */
+ memcpy(tx_buf+tx_buf_length, (uint8_t *)pbuf+written, fragment_length);
+#endif
+ /* Increment by the number of payload bytes written. */
+ tx_buf_length += fragment_length;
+ written += fragment_length;
+
+ /* Access SPI for writing (rx buffer is NULL). */
+ ret = dxs_spi_linux_read_write(fd, tx_buf, NULL, tx_buf_length);
+ /* ret is evaluated before the next iteration. */
+
+ /* Preserve and reuse the SPI header for the next fragment. */
+ tx_buf_length = DXS_SPI_HDR_LENGTH;
+ }
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Read a number of bytes from a given DXS register using SPI.
+
+ If the length of the data to be read exceeds the SPI_MAXBYTES_SIZE this
+ function calls the SPI read function repeatedly until all data is read
+ and reassembles the data in the return buffer.
+
+ \param fd Filedescriptor of the SPI driver.
+ \param offset DXS register address.
+ \param pbuf Pointer to buffer where to return the data.
+ \param len Number of bytes to be read.
+
+ \return
+ DXS_statusOk or error code.
+*/
+int32_t dxs_spi_read(int fd, uint8_t offset, uint16_t *pbuf, uint32_t len)
+{
+ uint8_t tx_buf[SPI_MAXBYTES_SIZE] = {0},
+ rx_buf[SPI_MAXBYTES_SIZE] = {0};
+ uint32_t tx_buf_length,
+ read,
+ fragment_length;
+ int32_t ret = DXS_statusOk;
+
+ uint32_t max_frag_sz = dxs_spi_max_frag_size_get();
+
+ /* TODO: len and offset assertion */
+ /* TODO: setup SPI */
+
+ /* tx_buf is the buffer for writing the read request. Because SPI in general
+ is full duplex the complete buffer is set to zero to avoid sending random
+ data after the SPI header that we set below. */
+ /* Build SPI header (16-bit word) */
+#if SPI_IOC_WR_BITS_PER_WORD_8BITS
+ /* SPI_IOC_WR_BITS_PER_WORD is 8bits */
+ tx_buf[0] = 0xBE;
+ tx_buf[1] = offset;
+
+ if (offset == DXS_REG_CSI_M_CFG || offset == DXS_REG_CSI_M_STAT)
+ {
+ tx_buf[1] <<= 1;
+ }
+#else
+ /* SPI_IOC_WR_BITS_PER_WORD is 16bits */
+ tx_buf[0] = offset;
+ tx_buf[1] = 0xBE;
+
+ if (offset == DXS_REG_CSI_M_CFG || offset == DXS_REG_CSI_M_STAT)
+ {
+ tx_buf[0] <<= 1;
+ }
+#endif
+
+ /* The tx_buf contains now the SPI header. */
+ tx_buf_length = DXS_SPI_HDR_LENGTH;
+
+ /* Loop while more data needs to be read. */
+ for (read = 0; (ret == DXS_statusOk) && (read < len); read += fragment_length)
+ {
+ /* Calculate the amount of payload bytes that can be read during one
+ read call. */
+ fragment_length = len - read; /* remaining bytes to read */
+ if (fragment_length > (max_frag_sz - tx_buf_length))
+ {
+ /* Limit the transfer to the maximum the SPI can transmit. */
+ fragment_length = (max_frag_sz - tx_buf_length);
+ }
+
+ /* Access SPI for writing and reading. */
+ ret = dxs_spi_linux_read_write(fd, tx_buf, rx_buf,
+ tx_buf_length + fragment_length);
+ if (ret == DXS_statusOk)
+ {
+#if SPI_IOC_WR_BITS_PER_WORD_8BITS
+ /* SPI_IOC_WR_BITS_PER_WORD is 8bits */
+
+ /* Copy the byte buffer into the 16-bit-word buffer respecting
+ the endianess. */
+ DXS_cpb2w (pbuf + (read/2),
+ rx_buf + DXS_SPI_HDR_LENGTH, fragment_length);
+#else
+ /* SPI_IOC_WR_BITS_PER_WORD is 16bits */
+ memcpy((uint8_t *)pbuf+read, rx_buf + DXS_SPI_HDR_LENGTH, fragment_length);
+#endif
+ }
+
+ /* ret is evaluated before the next iteration. */
+ }
+
+ DXS_RETURN(ret);
+}
+
+
+/**
+ Return the number of payload bytes that can be transferred over SPI
+ without being fragmented into multiple SPI transfers.
+
+ \return
+ Maximum number of bytes for a single SPI transfer.
+*/
+uint32_t DXS_spi_blocksize_get(DXS_DEVICE_t *pDev)
+{
+ return (pDev->access == DXS_ACCESS_CSI) ?
+ (SPI_MAX_BUFF_SIZE_CSI - DXS_SPI_HDR_LENGTH) :
+ (SPI_MAXBYTES_SIZE - DXS_SPI_HDR_LENGTH);
+}
+
+/**
+ Get device interrupt status.
+
+ \return
+ none
+*/
+void DXS_StatusGet(DXS_DEVICE_t *pDev)
+{
+ uint16_t nRegInt1 = 0, nRegInt2 = 0;
+
+ if (pDev->flags & DXS_DEV_ACCESS_INITIALIZED)
+ {
+ DXS_RegRead(pDev, DXS_REG_INT1, &nRegInt1);
+ if (nRegInt1 & DXS_REG_INT1_ERR)
+ {
+ DXS_RegRead(pDev, DXS_REG_INT2, &nRegInt2);
+ if (nRegInt2 & DXS_REG_INT2_CBO_UFL)
+ {
+ fprintf (stderr, "Out-Box Underflow, dev%d\n", pDev->nDevNum);
+ /* acknowledge the interrupt */
+ DXS_RegWrite(pDev, DXS_REG_INT2, nRegInt2);
+ }
+ if (nRegInt2 & DXS_REG_INT2_CBI_OFL)
+ {
+ fprintf (stderr, "In-Box Overflow, dev%d\n", pDev->nDevNum);
+ /* acknowledge the interrupt */
+ DXS_RegWrite(pDev, DXS_REG_INT2, nRegInt2);
+ }
+ }
+
+ /* new data in the outbox */
+ if ((nRegInt1 & DXS_REG_INT1_CBO_RDY) &&
+ (pDev->flags & DXS_DEV_OBX_HND_INITIALIZED))
+ sem_post(&pDev->obxSemaphore);
+ }
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_access.h b/marvell/services/dxslic/api_lib/src/dxs_access.h
new file mode 100644
index 0000000..90854f3
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_access.h
@@ -0,0 +1,151 @@
+#ifndef __DXS_ACCESS_H__
+#define __DXS_ACCESS_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_access.h
+ Low level access macros and functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_lib.h"
+#include <stdio.h>
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* Define the maximum number of bytes that the SPI interface can transfer with
+ one call to the interface.
+ This driver will fragment all data during read or write transfer into pieces
+ no larger than the value given here. To avoid overhead due to fragmentation
+ use the maximum value the SPI interface can support.
+ Possible values are calculated by (2+4*n) with n=1,2, ...
+ The minimum possible value is 6 bytes. There is no upper limit but values
+ larger than 34 bytes are never used by the DXS driver. */
+#define SPI_MAXBYTES_SIZE 30
+#define SPI_MAX_BUFF_SIZE_CSI 6
+
+#define DXS_REG_CFG 0x06
+#define DXS_REG_IEN1 0x08
+#define DXS_REG_STAT1 0x0C
+#define DXS_REG_INT1 0x10
+#define DXS_REG_IEN2 0x0A
+#define DXS_REG_STAT2 0x0E
+#define DXS_REG_INT2 0x12
+#define DXS_REG_DATA 0x14
+#define DXS_REG_LEN 0x18
+#define DXS_REG_CMD 0x1C
+#define DXS_REG_BCFG 0x20
+#define DXS_REG_BINF 0x24
+/* CSI Master registers */
+#define DXS_REG_CSI_M_CFG 0x30
+#define DXS_REG_CSI_M_STAT 0x31
+#define DXS_REG_CSI_M_CFG_PAUSE_DEFAULT 3
+#define DXS_REG_CSI_M_CFG_PDEMUX (1 << 10)
+
+#define DXS_REG_CFG_RST_MASK 0x0080
+#define DXS_REG_CFG_RST_RSTCORE (0x1 << 7)
+#define DXS_REG_CFG_8BIT_EN (0x1 << 2)
+#define DXS_REG_CFG_SC_MD (0x1 << 1)
+
+#define DXS_REG_BCFG_ASC_MASK 0x00FF
+#define DXS_REG_BCFG_ASC_ROM 0x0
+#define DXS_REG_BCFG_ASC_SPI 0x3
+
+#define DXS_REG_BINF_BOOTSTATE_MASK 0x00FF
+
+#define DXS_REG_INT1_ERR 1
+#define DXS_REG_INT1_CBO_RDY (1 << 11)
+
+#define DXS_REG_INT2_CBO_UFL (1 << 9)
+#define DXS_REG_INT2_CBI_OFL (1 << 8)
+
+/*******************************************************************************
+ * HOST Interrupt Enable 1 Register
+ ******************************************************************************/
+/* Reset value */
+#define DXS_REG_IEN1_RESET 0x0000
+/* Out-Box Ready Interrupt (11) */
+#define DXS_REG_IEN1_OBX_RDY (0x1 << 11)
+/* In-Box Empty Interrupt Mask (9) */
+#define DXS_REG_IEN1_IBX_EMP (0x1 << 9)
+/* Error Interrupt Mask (0) */
+#define DXS_REG_IEN1_ERR (0x1)
+
+/*******************************************************************************
+ * HOST Interrupt Enable 2 Register
+ ******************************************************************************/
+/* Reset value */
+#define DXS_REG_IEN2_RESET 0x0000
+/* Out-Box Underflow Interrupt (9) */
+#define DXS_REG_IEN2_OBX_UFL (0x1 << 9)
+/* In-Box Overflow Interrupt (8) */
+#define DXS_REG_IEN2_IBX_OFL (0x1 << 8)
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern int32_t DXS_RegWrite(
+ DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t nValue);
+
+extern int32_t DXS_RegRead(
+ DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t *pValue);
+
+extern int32_t DXS_RegWriteMulti(
+ DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t *nValue,
+ uint8_t count);
+
+extern int32_t DXS_RegReadMulti(
+ DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t *pValue,
+ uint8_t count);
+
+extern void DXS_cpw2b ( uint8_t *pBbuf,
+ const uint16_t * const pWbuf,
+ const uint32_t nWoffset,
+ const uint32_t nB);
+
+extern void DXS_cpb2w ( uint16_t *pWbuf,
+ const uint8_t * const pBbuf,
+ uint32_t nB);
+extern void DXS_cpb2dw ( uint32_t *pWbuf,
+ const uint8_t * const pBbuf,
+ uint32_t nB);
+extern uint32_t DXS_spi_blocksize_get(DXS_DEVICE_t *pDev);
+extern void DXS_StatusGet(DXS_DEVICE_t *pDev);
+
+extern int32_t dxs_spi_write(
+ int fd,
+ uint8_t offset,
+ uint16_t *pbuf,
+ uint32_t len);
+
+extern int32_t dxs_spi_read(
+ int fd,
+ uint8_t offset,
+ uint16_t *pbuf,
+ uint32_t len);
+#endif /* __DXS_ACCESS_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_api.c b/marvell/services/dxslic/api_lib/src/dxs_api.c
new file mode 100644
index 0000000..0b58fbd
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_api.c
@@ -0,0 +1,2056 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_api.c
+ This file contains the function prototypes specific to the DXS library
+ interface and is used by applications.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs.h"
+#include "dxs_init.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_config.h"
+#include "dxs_bbd.h"
+#include "dxs_wait.h"
+#include "dxs_sdd.h"
+#include "dxs_gpio.h"
+#include "dxs_cid.h"
+#include "dxs_pcm.h"
+#include "dxs_dwld.h"
+#include "dxs_sig.h"
+#include "dxs_debug_api.h"
+#include "dxs_event.h"
+#include "dxs_dcdc_hw.h"
+#include "dxs_ring.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_DEV_CTX_GET \
+ do { \
+ pDev = dxs_get_dev(dxs); \
+ if (pDev == NULL) { \
+ DXS_ERROR_PUSH(DXS_statusDevNotFound); \
+ return DXS_statusDevNotFound; \
+ } \
+ } while(0)
+
+#define DXS_DEV_INIT_VALIDATE \
+ do { \
+ if (!(pDev->flags & DXS_DEV_INITIALIZED)) { \
+ DXS_ERROR_PUSH(DXS_statusDevNotInitialized); \
+ return DXS_statusDevNotInitialized; \
+ } \
+ } while(0)
+
+#define DXS_CH_CTX_GET \
+ do { \
+ if (line >= pDev->nChannels) { \
+ DXS_ERROR_PUSH(DXS_statusChannelNotFound); \
+ return DXS_statusChannelNotFound; \
+ } \
+ pCh = &pDev->pChannel[line]; \
+ if (pCh == NULL){ \
+ DXS_ERROR_PUSH(DXS_statusChannelNotFound); \
+ return DXS_statusChannelNotFound; \
+ } \
+ } while(0)
+
+#define DXS_API_EXIT(ret) \
+ do { \
+ if (ret != DXS_statusOk) { \
+ DXS_ERROR_PUSH(ret); \
+ } \
+ return ret; \
+ } while(0)
+
+#define DXS_DEV_API_ENTRY \
+ do { \
+ DXS_DEV_CTX_GET; \
+ DXS_ERROR_RESET; \
+ DXS_DEV_INIT_VALIDATE; \
+ } while(0)
+
+#define DXS_CH_API_ENTRY \
+ do { \
+ DXS_DEV_API_ENTRY; \
+ DXS_CH_CTX_GET; \
+ } while(0)
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+/**
+ DXS Device Init
+
+ \param dxs - device number
+ \param chipSelect - CS number
+ \param irqNumber - IRQ line number
+ \param dcdcType - DCDC variant handled by DXS_DCDC_Var_t type
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsInit(uint8_t dxs, uint8_t chipSelect, int32_t irqNumber,
+ uint8_t dcdcType, uint8_t acc_mode)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_CTX_GET;
+ DXS_ERROR_RESET;
+
+ ret = dxs_init(pDev, chipSelect, irqNumber, dcdcType, acc_mode, dxs);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ DXS Device Exit
+
+ \param dxs - device number
+
+ \return
+ - DXS_statusOk
+*/
+int32_t DxsExit(uint8_t dxs)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = dxs_exit(pDev);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ DXS BBD Download
+
+ \param dxs - channel number
+ \param pBbd - pointer to BBD data
+ \param nBytes - BBD data size
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsBBD(uint8_t dxs, uint8_t line, uint8_t *pBbd, uint32_t nBytes)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = dxs_bbd_download(pCh, pBbd, nBytes);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ DXS PRAM Patch Download
+
+ \param dxs - device number
+ \param pPatch - pointer to PRAM patch data
+ \param nBytes - PRAM patch data size
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsPatch(uint8_t dxs, uint8_t *pPatch, uint32_t nBytes)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = DXS_FW_Select(pDev, pPatch, nBytes);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ DXS Firmware Capabilities Read
+
+ \param dxs - device number
+ \param pCap - pointer to DXS_Caps_t structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsCapabilitiesRead(uint8_t dxs, DXS_Caps_t *pCap)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = dxs_caps_read(pDev, pCap);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ DXS Version Read
+
+ \param dxs - device number
+ \param pVersion - pointer to DXS_Version_t structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsVersionRead(uint8_t dxs, DXS_Version_t *pVersion)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = dxs_vers_read(pDev, pVersion);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ DXS Sleep Mode Enable
+
+ \param dxs - device number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsSleepEnable(uint8_t dxs)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = dxs_sleep(pDev, 1);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ DXS Sleep Mode Disable
+
+ \param dxs - device number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsSleepDisable(uint8_t dxs)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = dxs_sleep(pDev, 0);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ PCM Interface Enable
+
+ \param dxs - device number
+ \param xoff - transmit bit offset
+ \param dbl - double bit clock
+ \param xs - transmit slope
+ \param rs - receive slope
+ \param drv0 - bit 0 drive length
+ \param sh - shift control
+ \param roff - receive bit offset
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsPcmInterfaceEnable(uint8_t dxs, uint8_t xoff, uint8_t dbl,
+ uint8_t xs, uint8_t rs, uint8_t drv0,
+ uint8_t sh, uint8_t roff)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = dxs_pcm_if_config(pDev, xoff, dbl, xs, rs, drv0, sh, roff);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ PCM Channel Enable
+
+ \param dxs - device number
+ \param line - line number
+ \param wb - wideband
+ \param wbtsc - wideband PCM time slot configuration
+ \param codec - codec
+ \param xts - transmit highway time slot
+ \param rts - receive highway time slot
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsPcmChannelEnable(uint8_t dxs, uint8_t line, uint8_t wb, uint8_t wbtsc,
+ uint8_t codec, uint8_t xts, uint8_t rts)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = dxs_pcm_ch_act(pCh, wb, wbtsc, codec, xts, rts);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ PCM Channel Disable
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsPcmChannelDisable(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = dxs_pcm_ch_deact(pCh);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ PCM Channel Mute in RX direction
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsPcmChannelMute(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = dxs_pcm_ch_mute(pCh, 1);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ PCM Channel Unmute in RX direction
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsPcmChannelUnmute(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = dxs_pcm_ch_mute(pCh, 0);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Ring configuration
+
+ \param dxs - device number
+ \param line - line number
+ \param waveForm - waveform type
+ \param crestFactor - crest factor
+ \param frequency - frequency
+ \param amplitude - amplitude
+ \param dcOffset - DC offset
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsRingConfig(uint8_t dxs, uint8_t line, uint8_t waveForm,
+ uint8_t crestFactor, uint8_t frequency,
+ uint16_t amplitude, uint16_t dcOffset)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_SDD_RingConfigAPI(pCh, waveForm, crestFactor, frequency,
+ amplitude, dcOffset);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Message Waiting Lamp configuration
+
+ \param dxs - device number
+ \param line - line number
+ \param voltage - voltage
+ \param thresh - threshold
+ \param slope - slope
+ \param onTime - on-time
+ \param offTime - off-time
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsMwlConfig(uint8_t dxs, uint8_t line, uint8_t voltage, uint8_t thresh,
+ uint16_t slope, uint16_t onTime, uint16_t offTime)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_SDD_MwlConfigAPI(pCh, voltage, thresh, slope, onTime, offTime);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Digital gain configuration
+
+ \param dxs - device number
+ \param line - line number
+ \param usg - upstream relative level setting
+ \param dsg - downstream relative level setting
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsGainsSet(uint8_t dxs, uint8_t line, int16_t TxGain, int16_t RxGain)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_SDD_GainSet(pCh, TxGain, RxGain);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Digital gain readback
+
+ \param dxs - device number
+ \param line - line number
+ \param pusg - pointer to upstream relative level setting
+ \param pdsg - pointer to downstream relative level setting
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsGainsGet(uint8_t dxs, uint8_t line, int16_t *pTxGain, int16_t *pRxGain)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_SDD_GainGet(pCh, pTxGain, pRxGain);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Line feeding mode set
+
+ \param dxs - device number
+ \param line - line number
+ \param mode - line feeding mode
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsLineModeSet(uint8_t dxs, uint8_t line, int mode)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ /* We need to signal that calibration was started by API */
+ if (mode == DXS_LINE_FEED_CALIBRATE)
+ (void) DXS_SDD_CalibrationInternalSet(pCh, 0);
+ ret = DXS_SDD_LineModeSet(pCh, mode);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Line feeding mode read
+
+ \param dxs - device number
+ \param line - line number
+ \param pMode - pointer to line feeding mode
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsLineModeGet(uint8_t dxs, uint8_t line, int *pMode)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_SDD_LineModeGet(pCh, pMode);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Read from DXS internal register
+ (requires --enable-debug-api)
+
+ \param dxs - device number
+ \param offset - register offset
+ \param pValue - pointer to value returned
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsDebugRegRead16(uint8_t dxs, uint8_t offset, uint16_t *pValue)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_DEV_API_ENTRY;
+
+#ifdef DXS_FEAT_DEBUG_API
+ ret = dxs_reg_read (pDev, offset, pValue, 1);
+#endif /* DXS_FEAT_DEBUG_API */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Write into DXS internal register
+ (requires --enable-debug-api)
+
+ \param dxs - device number
+ \param offset - register offset
+ \param value - value
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsDebugRegWrite16(uint8_t dxs, uint8_t offset, uint16_t value)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+ uint16_t temp_value = value;
+
+ DXS_DEV_API_ENTRY;
+
+#ifdef DXS_FEAT_DEBUG_API
+ ret = dxs_reg_write (pDev, offset, &temp_value, 1);
+#endif /* DXS_FEAT_DEBUG_API */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Read from DXS internal register
+ (requires --enable-debug-api)
+
+ \param dxs - device number
+ \param offset - register offset
+ \param pValue - pointer to value returned
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsDebugRegRead32(uint8_t dxs, uint8_t offset, uint32_t *pValue)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_DEV_API_ENTRY;
+
+#ifdef DXS_FEAT_DEBUG_API
+ ret = dxs_reg_read (pDev, offset, (uint16_t *)pValue, 2);
+#endif /* DXS_FEAT_DEBUG_API */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Write into DXS internal register
+ (requires --enable-debug-api)
+
+ \param dxs - device number
+ \param offset - register offset
+ \param value - value
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsDebugRegWrite32(uint8_t dxs, uint8_t offset, uint32_t value)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+ uint32_t temp_value = value;
+
+ DXS_DEV_API_ENTRY;
+
+#ifdef DXS_FEAT_DEBUG_API
+ ret = dxs_reg_write (pDev, offset, (uint16_t *)&temp_value, 2);
+#endif /* DXS_FEAT_DEBUG_API */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Read DXS firmware command
+ (requires --enable-debug-api)
+
+ \param dxs - device number
+ \param hdr - command header
+ \param pLength - length of data
+ \param pData - pointer to read data into
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsDebugCmdRead(uint8_t dxs, uint32_t hdr,
+ uint8_t *pLength, uint32_t *pData)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_DEV_API_ENTRY;
+
+#ifdef DXS_FEAT_DEBUG_API
+ ret = dxs_cmd_read (pDev, hdr, pData, pLength);
+#endif /* DXS_FEAT_DEBUG_API */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Write DXS firmware command
+ (requires --enable-debug-api)
+
+ \param dxs - device number
+ \param length - the length of buffer
+ \param pCmd - pointer to buffer with command
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsDebugCmdWrite(uint8_t dxs, uint8_t length, uint32_t *pCmd)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_DEV_API_ENTRY;
+
+#ifdef DXS_FEAT_DEBUG_API
+ ret = dxs_cmd_write (pDev, pCmd, length);
+#endif /* DXS_FEAT_DEBUG_API */
+
+ DXS_API_EXIT(ret);
+}
+
+#if 0
+/*
+ * DxsDebugBBDGet()
+ * requires --enable-debug-api
+ */
+int32_t DxsDebugBBDGet(uint8_t dxs, int nBuffer, uchar *pBbd, int *nByte)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_DEV_API_ENTRY;
+
+#ifdef DXS_FEAT_DEBUG_API
+ /* TODO: ret = dxs_bbd_get (pDev, pCmd, length); */
+#endif /* DXS_FEAT_DEBUG_API */
+
+ DXS_API_EXIT(ret);
+}
+#endif
+
+/**
+ Tone Configuration
+ (requires --enable-tg)
+
+ \param dxs - device number
+ \param line - line number
+ \param level1 - level for frequency 1
+ \param level2 - level for frequency 2
+ \param freq1 - tone frequency 1
+ \param freq2 - tone frequency 2
+ \param amModulated - amplitude modulation flag
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsToneConfig(uint8_t dxs, uint8_t line, int16_t level1,
+ int16_t level2, uint16_t freq1, uint16_t freq2,
+ uint8_t amModulated)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_TG
+ ret = dxs_tone_config(pCh, level1, level2, freq1, freq2, amModulated, 1);
+#endif /* DXS_FEAT_TG */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Tone Playout Enable
+ (requires --enable-tg)
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsToneEnable(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_TG
+ ret = dxs_tone_start(pCh);
+#endif /* DXS_FEAT_TG */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Tone Playout Disable
+ (requires --enable-tg)
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsToneDisable(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_TG
+ ret = dxs_tone_stop(pCh);
+#endif /* DXS_FEAT_TG */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ CID Generator Coefficients update
+ (requires --enable-fsk)
+
+ \param dxs - device number
+ \param line - line number
+ \param level - CID send level
+ \param seizure - number of seizure bytes
+ \param mark - number of mark bits
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsFskConfig(uint8_t dxs, uint8_t line, int16_t level,
+ uint16_t seizure, uint16_t mark)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_FSK
+ ret = DXS_FSK_Configure(pCh, level, seizure, mark);
+#endif /* DXS_FEAT_FSK */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ CID Generator Enable
+ (requires --enable-fsk)
+
+ \param dxs - device number
+ \param line - line number
+ \param standard - CID standard
+ \param autodeact - auto deactivation
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsFskEnable(uint8_t dxs, uint8_t line, uint8_t standard, uint8_t autodeact)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_FSK
+ ret = DXS_FSK_Enable(pCh, standard, autodeact);
+#endif /* DXS_FEAT_FSK */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ CID Generator Disable
+ (requires --enable-fsk)
+
+ \param dxs - device number
+ \param line - line number
+ \param autodeact - auto deactivation
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsFskDisable(uint8_t dxs, uint8_t line, uint8_t autodeact)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_FSK
+ ret = DXS_FSK_Disable(pCh, autodeact);
+#endif /* DXS_FEAT_FSK */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Send new data to the CID sender
+ (requires --enable-fsk)
+
+ \param dxs - device number
+ \param line - line number
+ \param nByte - data buffer size
+ \param pByte - pointer to data buffer
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsFskData(uint8_t dxs, uint8_t line, uint8_t nByte, uint8_t *pByte)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_FSK
+ ret = DXS_FSK_Data(pCh, nByte, pByte);
+#endif /* DXS_FEAT_FSK */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Enable UTD
+ (requires --enable-utd)
+
+ \param dxs - device number
+ \param line - line number
+ \param tone_idx - tone index
+ \param direction - detection direction
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsUtdEnable(uint8_t dxs, uint8_t line, uint16_t tone_idx,
+ int direction)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+#ifdef DXS_FEAT_UTD
+ ret = DXS_SIG_UtdEnable(pCh, tone_idx, direction);
+#endif /* DXS_FEAT_UTD */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Disable UTD
+ (requires --enable-utd)
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsUtdDisable(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_UTD
+ ret = DXS_SIG_UtdDisable(pCh);
+#endif /* DXS_FEAT_UTD */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ DTMF Receiver Coefficients
+ (requires --enable-dtmfd)
+
+ \param dxs - device number
+ \param line - line number
+ \param level - minimum signal level
+ \param twist - maximum allowed twist
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsDtmfConfig(uint8_t dxs, uint8_t line, int16_t level, int16_t twist)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_DTMFD
+ ret = dxs_dtmf_config(pCh, level, twist);
+#endif /* DXS_FEAT_DTMFD */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ DTMF Receiver Enable
+ (requires --enable-dtmfd)
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsDtmfEnable(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_DTMFD
+ ret = dxs_dtmf_enable(pCh, 1);
+#endif /* DXS_FEAT_DTMFD */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ DTMF Receiver Disable
+ (requires --enable-dtmfd)
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsDtmfDisable(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_DTMFD
+ ret = dxs_dtmf_enable(pCh, 0);
+#endif /* DXS_FEAT_DTMFD */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Set GR-909 limits
+ (requires --enable-gr909)
+
+ \param dxs - device number
+ \param line - line number
+ \param pGR909Conf - pointer to SDD GR909 configuration structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsGr909LimitsSet(uint8_t dxs, uint8_t line,
+ DXS_GR909Config_t *pGR909Conf)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_GR909
+ ret = DXS_SDD_GR909LimitsSet(pCh, pGR909Conf);
+#endif /* DXS_FEAT_GR909 */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Get GR-909 limits
+ (requires --enable-gr909)
+
+ \param dxs - device number
+ \param line - line number
+ \param pGR909Conf - pointer to SDD GR909 configuration structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsGr909LimitsGet(uint8_t dxs, uint8_t line,
+ DXS_GR909Config_t *pGR909Conf)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_GR909
+ ret = DXS_SDD_GR909LimitsGet(pCh, pGR909Conf);
+#endif /* DXS_FEAT_GR909 */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Get GR-909 results
+ (requires --enable-gr909)
+
+ \param dxs - device number
+ \param line - line number
+ \param pGR909Result - pointer to SDD GR909 result structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsGr909ResultGet(uint8_t dxs, uint8_t line,
+ DXS_GR909Result_t *pGR909Result)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_GR909
+ ret = DXS_SDD_GR909ResultGet(pCh, pGR909Result);
+#endif /* DXS_FEAT_GR909 */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ GPIO port configuration
+ (requires --enable-gpio)
+
+ \param dxs - device number
+ \param pGpioConf - pointer to GPIO configuration structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsGpioPortConfig(uint8_t dxs, DXS_GpioConfig_t *pGpioConf)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_DEV_API_ENTRY;
+
+#ifdef DXS_FEAT_GPIO
+ ret = DXS_GPIO_Config(pDev, pGpioConf);
+#endif /* DXS_FEAT_GPIO */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ GPIO write
+ (requires --enable-gpio)
+
+ \param dxs - device number
+ \param pin - GPIO pin number
+ \param val - value
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsGpioWrite(uint8_t dxs, uint8_t pin, uint8_t val)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_DEV_API_ENTRY;
+
+#ifdef DXS_FEAT_GPIO
+ ret = DXS_GPIO_Write(pDev, pin, val);
+#endif /* DXS_FEAT_GPIO */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ GPIO read
+ (requires --enable-gpio)
+
+ \param dxs - device number
+ \param pin - GPIO pin number
+ \param *value - value
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsGpioRead(uint8_t dxs, uint8_t pin, uint8_t *value)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_DEV_API_ENTRY;
+
+#ifdef DXS_FEAT_GPIO
+ ret = DXS_GPIO_Read(pDev, pin, value);
+#endif /* DXS_FEAT_GPIO */
+
+ DXS_API_EXIT(ret);
+}
+
+
+/**
+ Read the results of calibration measurements.
+
+ \param dxs - device number
+ \param line - line number
+ \param pCalibration - pointer to calibration structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsCalibrationGet(uint8_t dxs, uint8_t line,
+ DXS_Calibration_t *pCalibration)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_SDD_CalibrationGet(pCh, pCalibration);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Write hardware configuration values.
+
+ \param dxs - device number
+ \param line - line number
+ \param pCalibration - pointer to calibration structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsCalibrationSet(uint8_t dxs, uint8_t line,
+ DXS_Calibration_t *pCalibration)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_SDD_CalibrationSet(pCh, pCalibration);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Sets the validation times for hook, pulse digit and flashhook.
+
+ \param dxs - device number
+ \param line - line number
+ \param pTime - type of validation setting, min and max time in
+ milliseconds.
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsHookValTimeSet(uint8_t dxs, uint8_t line, DXS_HookValTime_t *pTime)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_HSM
+ ret = DXS_Dial_HookValTimeSet(pCh, pTime);
+#endif /* DXS_FEAT_HSM */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Get capacitance measurement result
+
+ \param dxs - device number
+ \param line - line number
+ \param pCapacitance - pointer to capacitance measurement structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsCapMeasurementResultGet(uint8_t dxs, uint8_t line,
+ DXS_Capacitance_t *pCapacitance)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_CAPMEAS
+ ret = DXS_SDD_CapMeasurementResultGet(pCh, 1, pCapacitance);
+#endif /* DXS_FEAT_CAPMEAS */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Get continuous measurements result
+
+ \param dxs - device number
+ \param line - line number
+ \param pResult - pointer to continuous measurement structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsContMeasurementResultGet(uint8_t dxs, uint8_t line,
+ DXS_ContMeasurementResult_t *pResult)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_SDD_ContMeasurementResultGet(pCh, pResult);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Enable metering pulse. The pulse length can be programmed
+ with SDD_BasicConfig.
+ (requires --enable-metering)
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsMeteringPulseEnable(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_METERING
+ ret = DXS_SIG_MeterPulseEnable(pCh);
+#endif /* DXS_FEAT_METERING */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Disable metering pulse.
+ (requires --enable-metering)
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsMeteringPulseDisable(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_METERING
+ ret = DXS_SIG_MeterPulseDisable(pCh);
+#endif /* DXS_FEAT_METERING */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Open Loop Calibration
+
+ \param dxs - device number
+ \param line - line number
+ \param loops - number of loops
+ \param pOLCalibrationResult - pointer to Open Loop Calibration structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsOpenLoopCalibration(uint8_t dxs, uint8_t line, uint8_t loops,
+ DXS_OLCalibration_t *pOLCalibrationResult)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
+ ret = DXS_SDD_OLCalibration(pCh, loops, pOLCalibrationResult);
+#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to set the Open Loop Calibration configuration
+
+ \param dxs - device number
+ \param line - line number
+ \param pOLCalibration - pointer to Open Loop Calibration structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsOpenLoopConfigSet(uint8_t dxs, uint8_t line,
+ DXS_OLCalibration_t *pOLCalibration)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
+ ret = DXS_SDD_OLCalibrationConfigSet(pCh, pOLCalibration);
+#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to get the Open Loop Calibration configuration
+
+ \param dxs - device number
+ \param line - line number
+ \param pOLCalibration - pointer to Open Loop Calibration structure
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsOpenLoopConfigGet(uint8_t dxs, uint8_t line,
+ DXS_OLCalibration_t *pOLCalibration)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
+ ret = DXS_SDD_OLCalibrationConfigGet(pCh, pOLCalibration);
+#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to start the ACLM measurement
+
+ \param dxs - device number
+ \param line - line number
+ \param aclm_mt - ACLM measurment code
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsAcLmMeasurementStart(uint8_t dxs, uint8_t line,
+ DXS_ACLM_Measurement_t aclm_mt)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_ACMETER
+ ret = DXS_SDD_ACLM_Start(pCh, aclm_mt);
+#endif /* DXS_FEAT_ACMETER */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to retrieve the available ACLM measurement result number
+
+ \param dxs - device number
+ \param line - line number
+ \param aclm_mt - ACLM measurment code
+ \param pResNum - ACLM result number (output)
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsAcLmMeasResNumGet(uint8_t dxs, uint8_t line,
+ DXS_ACLM_Measurement_t aclm_mt,
+ int32_t *pResNum)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_ACMETER
+ ret = DXS_SDD_ACLM_ResultGet(pCh,
+ aclm_mt, DXS_ACLM_RESULT_NUMBER, 0, pResNum);
+#endif /* DXS_FEAT_ACMETER */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to retrieve the argument of particular ACLM measurement index
+
+ \param dxs - device number
+ \param line - line number
+ \param aclm_mt - ACLM measurment code
+ \param index - ACLM measurment index
+ \param pResArg - ACLM result argument (output)
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsAcLmMeasResArgGet(uint8_t dxs, uint8_t line,
+ DXS_ACLM_Measurement_t aclm_mt,
+ int32_t index, int32_t *pResArg)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_ACMETER
+ ret = DXS_SDD_ACLM_ResultGet(pCh,
+ aclm_mt, DXS_ACLM_RESULT_ARG, index, pResArg);
+#endif /* DXS_FEAT_ACMETER */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to retrieve the result value of particular ACLM measurement index
+
+ \param dxs - device number
+ \param line - line number
+ \param aclm_mt - ACLM measurment code
+ \param index - ACLM measurment index
+ \param pResArg - ACLM result argument (output)
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsAcLmMeasResValGet(uint8_t dxs, uint8_t line,
+ DXS_ACLM_Measurement_t aclm_mt,
+ int32_t index, int32_t *pResVal)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_ACMETER
+ ret = DXS_SDD_ACLM_ResultGet(pCh,
+ aclm_mt, DXS_ACLM_RESULT_VALUE, index, pResVal);
+#endif /* DXS_FEAT_ACMETER */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to initialize CID interface for a channel
+
+ \param dxs - device number
+ \param line - line number
+ \param std - CID standard
+ \param as - CID alert signal
+ \param fmt - CID data format
+ \param dtmf_ack_idx - DTMF index for acknowledgment (type2)
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsCidInit (uint8_t dxs, uint8_t line, DXS_CID_Std_t std,
+ DXS_CID_AS_t as, DXS_CID_DATA_FMT_t fmt, uint8_t dtmf_ack_idx)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_CID
+ ret = DXS_CID_Init(pCh, std, as, fmt, dtmf_ack_idx);
+#endif /* DXS_FEAT_CID */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to configure timers for a given CID standard.
+
+ \param dxs - device number
+ \param line - line number
+ \param std - CID standard
+ \param pTimers - pointer to timer union
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsCidTimerConfig (uint8_t dxs, uint8_t line, DXS_CID_Std_t std,
+ DXS_CID_Timers_t *pTimers)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_CID
+ ret = DXS_CID_TimerConfig(pCh, std, pTimers);
+#endif /* DXS_FEAT_CID */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to create (or update) the CID message per channel
+
+ \param dxs - device number
+ \param line - line number
+ \param msg_type - CID message type
+ \param param - CID message parameter
+ \param pData - pointer to char data of the parameter value
+ \param length - length of the data pointed by pData
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsCidMsgSetup(uint8_t dxs, uint8_t line, DXS_CID_MsgType_t msg_type,
+ DXS_CID_MsgParam_t param, char *pData, uint8_t length)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_CID
+ ret = DXS_CID_MsgUpdate(pCh, msg_type, param, pData, length);
+#endif /* DXS_FEAT_CID */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to delete entirely the CID message per channel
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsCidMsgReset(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_CID
+ ret = DXS_CID_MsgCleanup(pCh);
+#endif /* DXS_FEAT_CID */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to start the playout of CID TypeI sequence
+
+ \param dxs - device number
+ \param line - line number
+ \param std - CID standard
+ \param as - Alert signal
+ \param fmt - Data format
+ \param msg_type - message type selected for playout
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsCidTypeIMsgStart(uint8_t dxs, uint8_t line,
+ DXS_CID_MsgType_t msg_type)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_CID
+ ret = DXS_CID_TypeI_Play(pCh, msg_type, DXS_CID_CALL_FROM_CID_API);
+#endif /* DXS_FEAT_CID */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to start the playout of CID TypeII sequence
+
+ \param dxs - device number
+ \param line - line number
+ \param std - CID standard
+ \param as - Alert signal
+ \param fmt - Data format
+ \param msg_type - message type selected for playout
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsCidTypeIIMsgStart(uint8_t dxs, uint8_t line,
+ DXS_CID_MsgType_t msg_type)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_CID
+ ret = DXS_CID_TypeII_Play(pCh, msg_type);
+#endif /* DXS_FEAT_CID */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to stop the playout of CID sequence
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsCidSeqStop(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret = DXS_statusFeatNotCompiledIn;
+
+ DXS_CH_API_ENTRY;
+
+#ifdef DXS_FEAT_CID
+ ret = DXS_CID_Stop(pCh);
+#endif /* DXS_FEAT_CID */
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to configure the ringing cadence
+
+ \param dxs - device number
+ \param line - line number
+ \param pRC - pointer to \ref DXS_RingCadence_t structure
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsRingCadenceInit(uint8_t dxs, uint8_t line, DXS_RingCadence_t *pRC)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_RING_CadenceInit(pCh, pRC);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to start the ringing cadence
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsRingCadenceStart(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_RING_CadenceStart(pCh);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Function to stop the ringing cadence
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - \ref DXS_status_t code
+*/
+int32_t DxsRingCadenceStop(uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_RING_CadenceStop(pCh);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Prevent ESD mode and line voltage drop
+ on PCM clock failure
+
+ \param dxs - device number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsClockFailLineFeedFreeze (uint8_t dxs)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = DXS_CfEsdSwitch(pDev, 0);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Allow ESD mode and line voltage drop
+ on PCM clock failure
+
+ \param dxs - device number
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsClockFailLineFeedUnFreeze (uint8_t dxs)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = DXS_CfEsdSwitch(pDev, 1);
+
+ DXS_API_EXIT(ret);
+}
+
+/* =================== MULTI-CHANNEL SHARED HW SUPPORT ====================== */
+
+/**
+ Configure the driver for the master channel.
+
+ \param dxs - device number
+ \param line - line number
+
+ \return
+ - DXS_statusOk
+ - DXS_statusDevNotFound
+ - DXS_statusDevNotInitialized
+ - DXS_statusChannelNotFound
+ - DXS_statusInvalidParam
+*/
+int32_t DxsSharedDcDcMasterSet (uint8_t dxs, uint8_t line)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_DCDC_HW_SharedDcDcMasterChSet(pCh);
+
+ DXS_API_EXIT(ret);
+}
+/* ========================================================================== */
+
+/* ===================== E V E N T S U P P O R T ========================== */
+
+/**
+ Initialize Waiting List
+
+ \return
+ - waiting list instance
+*/
+DXS_WaitList_t DxsWaitListInit(void)
+{
+ return dxs_wl_init();
+}
+
+/**
+ Initialize Waiting List
+
+ \param wl - waiting list instance
+
+*/
+void DxsWaitListDestroy(DXS_WaitList_t wl)
+{
+ dxs_wl_destroy(wl);
+}
+
+/**
+ Add device to the waiting list
+
+ \param dxs - device number
+ \param wl - waiting list instance
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsWaitListDevAdd(uint8_t dxs, DXS_WaitList_t wl)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = dxs_wl_dev_add(pDev, wl);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Remove device from the waiting list
+
+ \param dxs - device number
+ \param wl - waiting list instance
+
+ \return
+ - DXS_statusOk or DXS_statusError
+*/
+int32_t DxsWaitListDevRemove(uint8_t dxs, DXS_WaitList_t wl)
+{
+ DXS_DEVICE_t *pDev;
+ int32_t ret;
+
+ DXS_DEV_API_ENTRY;
+
+ ret = dxs_wl_dev_remove(pDev, wl);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Wait on the Waiting List instance
+
+ \param wl - waiting list instance
+
+ \return
+ - the first device number on the Waiting List
+ having non-empty event queue
+ or negative value in case of error
+*/
+int32_t DxsWaitForEvent(DXS_WaitList_t wl)
+{
+ return dxs_wait(wl);
+}
+
+/**
+ Read a single event from the device
+
+ \param dxs - device number
+ \param pEvent - pointer to DXS_Event_t structure
+
+ \return
+ - the remaining event count in device event queue
+ or negative value in case of error
+*/
+int32_t DxsEventGet(uint8_t dxs, DXS_Event_t *pEvent)
+{
+ DXS_DEVICE_t *pDev;
+
+ DXS_DEV_API_ENTRY;
+
+ /* no DXS_API_EXIT macro, as the function returns
+ the event count instead of a status code */
+
+ return dxs_event_get(pDev, pEvent);
+}
+
+/**
+ Enable dispatching of a particular event on a given line
+ to the application.
+
+ \param dxs Device number.
+ \param line Line number.
+ \param event Event id
+
+ \return
+ Return value according to \ref DXS_status_t.
+*/
+int32_t DxsEventEnable(uint8_t dxs, uint8_t line, DXS_Event_id_t event)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_EventEnable(pCh, event);
+
+ DXS_API_EXIT(ret);
+}
+
+/**
+ Disable dispatching of a particular event on a given line
+ to the application.
+
+ \param dxs Device number.
+ \param line Line number.
+ \param event Event id
+
+ \return
+ Return value according to \ref DXS_status_t.
+*/
+int32_t DxsEventDisable(uint8_t dxs, uint8_t line, DXS_Event_id_t event)
+{
+ DXS_DEVICE_t *pDev;
+ DXS_CHANNEL_t *pCh;
+ int32_t ret;
+
+ DXS_CH_API_ENTRY;
+
+ ret = DXS_EventDisable(pCh, event);
+
+ DXS_API_EXIT(ret);
+}
+
+/* ========================================================================== */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_bbd.c b/marvell/services/dxslic/api_lib/src/dxs_bbd.c
new file mode 100644
index 0000000..9638426
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_bbd.c
@@ -0,0 +1,530 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_bbd.c
+ Implementation of BBD functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdio.h>
+
+#include "dxs.h"
+#include "dxs_config.h"
+#include "dxs_lib.h"
+#include "dxs_fw_cmd.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_sdd.h"
+#include "dxs_sig.h"
+#include "dxs_init.h"
+#include "dxs_access.h"
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define BBD_MAGIC 0x21626264
+#define BBD_FAMILY_ID_DXS 0x44585321
+#define BBD_FAMILY_ID_DX8 0x44583821
+
+#define BBD_BLK_ID_MASTER 0x000a
+#define BBD_BLK_ID_CRAM 0x1001
+#define BBD_BLK_ID_CRAM2 0x1020
+#define BBD_BLK_ID_RING 0x1003
+#define BBD_BLK_ID_BASIC 0x1005
+#define BBD_BLK_ID_DCDC 0x1009
+#define BBD_BLK_ID_MWL 0x1008
+#define BBD_BLK_ID_UTD 0x1007
+#define BBD_BLK_ID_END 0x0000
+
+/** Reads 8bit value from big endian byte buffer */
+#define BBD_GET_VAL8(buf, pos, val8) \
+ val8 = (buf)[(pos)]; (pos) +=1;
+
+/** Reads 16bit value from big endian byte buffer */
+#define BBD_GET_VAL16(buf, pos, val16) \
+ val16 = (((buf)[(pos)] << 8) |(buf)[(pos)+1]);\
+ (pos) += 2;
+
+/** Reads 32bit value from big endian byte buffer */
+#define BBD_GET_VAL32(buf, pos, val32) \
+ val32 = (((buf)[(pos)] << 24) | ((buf)[(pos)+1] << 16) | \
+ ((buf)[(pos)+2] << 8) | (buf)[(pos)+3]);\
+ (pos) += 4;
+
+/** Reads a complete bbd head, assuming given position is correct.*/
+#define BBD_GET_HEAD(buf, pos, head)\
+ do {\
+ BBD_GET_VAL16((buf), (pos), (head)->tag);\
+ BBD_GET_VAL16((buf), (pos), (head)->vers);\
+ BBD_GET_VAL32((buf), (pos), (head)->len);\
+ }while(0);
+
+/** Reads a complete master block exclusive head,
+ assuming given position is correct. */
+#define BBD_GET_MASTER(buf, pos, master)\
+ do {\
+ BBD_GET_VAL32((buf), (pos), (master)->magic);\
+ BBD_GET_VAL32((buf), (pos), (master)->family);\
+ BBD_GET_VAL8 ((buf), (pos), (master)->year);\
+ BBD_GET_VAL8 ((buf), (pos), (master)->month);\
+ BBD_GET_VAL8 ((buf), (pos), (master)->day);\
+ BBD_GET_VAL8 ((buf), (pos), (master)->padding);\
+ }while(0);
+
+/** Skip the actual block, assuming given position is correct */
+#define BBD_SKIP_BLOCK(pos, block_len)\
+ (pos) += (block_len);
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+/** BBD block header */
+struct bbd_block_header
+{
+ /** block id */
+ uint16_t tag;
+ /** block version */
+ uint16_t vers;
+ /** length */
+ uint32_t len;
+} __attribute__ ((packed));
+
+/** BBD block master */
+struct bbd_block_master
+{
+ uint32_t magic;
+ uint32_t family;
+ uint8_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t padding;
+} __attribute__ ((packed));
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+/**
+ Function bbd_block_cram
+
+ \param pCh - pointer to DXS channel structure
+ \param pHdr - pointer to BBD block header structure
+ \param pCram - poiner to CRAM block data
+ \param family - value from master block
+
+ \return
+ - DXS_status_t
+*/
+static int32_t bbd_block_cram(DXS_CHANNEL_t *pCh, struct bbd_block_header *pHdr,
+ uint8_t *pCram, uint32_t family)
+{
+ uint16_t cram_offset, cmdLenBytes, pos = 0, cramLenWords;
+ int16_t words16;
+ uint8_t *pData;
+ int32_t ret = DXS_statusOk;
+ uint16_t paddingBytes;
+ uint8_t dest;
+ uint16_t blockOffset;
+
+ /* skip unsupported family block */
+ if (family != BBD_FAMILY_ID_DXS && family != BBD_FAMILY_ID_DX8)
+ return DXS_statusOk;
+
+ if (pHdr->tag == BBD_BLK_ID_CRAM2)
+ dest = 1;
+ else
+ dest = 0;
+
+ /* read offset */
+ DXS_cpb2w (&cram_offset, pCram, sizeof(uint16_t));
+
+ pData = pCram + sizeof(cram_offset);
+
+ /* data len in words16, minus len of offset_16 and crc_16 */
+ words16 = (pHdr->len - 2 * sizeof(uint16_t)) >> 1;
+
+ while (words16 > 0)
+ {
+ if (words16 > ((DXS_FW_SDD_Coeff_MAXLENGTH >> 1) - 1))
+ cmdLenBytes = DXS_FW_SDD_Coeff_MAXLENGTH;
+ else
+ cmdLenBytes = (words16 + 1) << 1;
+
+ paddingBytes = cmdLenBytes % sizeof(uint32_t);
+ cramLenWords = (cmdLenBytes >> 1) - 1;
+ blockOffset = cram_offset + (pos >> 1);
+
+ ret = DXS_SDD_CoeffBBD(pCh, dest, blockOffset, cramLenWords,
+ &pData[pos], paddingBytes);
+
+ pos += (cmdLenBytes - 2);
+ words16 -= cramLenWords;
+ }
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function bbd_block_ring
+
+ \param pCh - pointer to DXS channel structure
+ \param pHdr - pointer to BBD block header structure
+ \param pRing - pointer to RING block data
+ \param family - value from master block
+
+ \return
+ - DXS_status_t
+*/
+static int32_t bbd_block_ring(DXS_CHANNEL_t *pCh,
+ struct bbd_block_header *pHdr,
+ uint8_t *pRing,
+ uint32_t family)
+{
+ union DXS_FW_SDD_RingConfig_u ring = {0};
+ uint32_t len = pHdr->len;
+ int32_t ret;
+
+ /* skip unsupported family block */
+ if (family != BBD_FAMILY_ID_DXS && family != BBD_FAMILY_ID_DX8)
+ return DXS_statusOk;
+
+ DXS_cpb2dw(&ring.u32[0], pRing, len);
+
+ ret = DXS_SDD_RingConfigBBD(pCh, &ring.fwmsg);
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function bbd_block_basic
+
+ \param pCh - pointer to DXS channel structure
+ \param pHdr - pointer to BBD block header structure
+ \param pBasic - pointer to BASIC block data
+ \param family - value from master block
+
+ \return
+ - DXS_status_t
+*/
+static int32_t bbd_block_basic(DXS_CHANNEL_t *pCh,
+ struct bbd_block_header *pHdr, uint8_t *pBasic,
+ uint32_t family)
+{
+ union DXS_FW_SDD_BasicConfig_u basic = {0};
+ uint32_t len = pHdr->len;
+ int32_t ret;
+
+ /* skip unsupported family block */
+ if (family != BBD_FAMILY_ID_DXS && family != BBD_FAMILY_ID_DX8)
+ return DXS_statusOk;
+
+ DXS_cpb2dw(&basic.bc_data.data_u32[0], pBasic, len);
+
+ ret = DXS_SDD_BasicConfigBBD (pCh, &basic.bc_data);
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function bbd_block_dcdc
+
+ \param pCh - pointer to DXS channel structure
+ \param pHdr - pointer to BBD block header structure
+ \param pDcdc - pointer to DC/DC block data
+ \param family - value from master block
+
+ \return
+ - DXS_status_t
+*/
+static int32_t bbd_block_dcdc(DXS_CHANNEL_t *pCh,
+ struct bbd_block_header *pHdr, uint8_t *pDcdc,
+ uint32_t family)
+{
+ union DXS_FW_SDD_DcDcConfig_u dcdc_cfg = {0};
+ uint32_t len = pHdr->len;
+ int32_t ret = DXS_statusOk;
+
+ if (family == BBD_FAMILY_ID_DXS)
+ {
+ DXS_DCDC_Var_t dcdc_hw_bbd;
+
+ DXS_cpb2dw(&dcdc_cfg.dcdc_data.data_u32[0], pDcdc, len);
+ dcdc_hw_bbd = dcdc_cfg.fwmsg.DcDcHw;
+
+ /* sanity check */
+ if (dcdc_hw_bbd != DXS_DCDC_IBB12 &&
+ dcdc_hw_bbd != DXS_DCDC_CIBB12 &&
+ dcdc_hw_bbd != DXS_DCDC_IB12 &&
+ dcdc_hw_bbd != DXS_DCDC_BB48 &&
+ dcdc_hw_bbd != DXS_DCDC_CBB48 &&
+ dcdc_hw_bbd != DXS_DCDC_IFB12 &&
+ dcdc_hw_bbd != DXS_DCDC_CIFB12 &&
+ dcdc_hw_bbd != DXS_DCDC_IBGD12 &&
+ dcdc_hw_bbd != DXS_DCDC_IBVD3)
+ {
+ fprintf (stderr, "BBD: Unsupported DCDC HW option %d\n", dcdc_hw_bbd);
+ DXS_RETURN(DXS_statusBbdUnknownDcDcOpt);
+ }
+
+ /* check if DCDC HW matches the configured HW option */
+ if (dcdc_hw_bbd != pCh->pParent->dcdcType)
+ {
+ fprintf (stderr,
+ "BBD: DCDC HW configuration mismatch: init=%d, bbd=%d\n",
+ pCh->pParent->dcdcType, dcdc_hw_bbd);
+ DXS_RETURN(DXS_statusBbdDCDCHwCfgMismatch);
+ }
+
+ /* enable charge pump */
+ if (dcdc_hw_bbd == DXS_DCDC_IB12 || dcdc_hw_bbd == DXS_DCDC_IFB12 ||
+ dcdc_hw_bbd == DXS_DCDC_CIFB12)
+ {
+ ret = DXS_ChargePumpSwitchOn(pCh->pParent);
+ }
+ }
+ else if (family == BBD_FAMILY_ID_DX8)
+ {
+ DXS_cpb2dw(&dcdc_cfg.dcdc_data.data_u32[0], pDcdc, len);
+
+ if (pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ /* sanity check - not perfect due to missing DcDcHw field
+ in the command */
+ if (dcdc_cfg.dx8fwmsg.Res00 || dcdc_cfg.dx8fwmsg.Res01 ||
+ dcdc_cfg.dx8fwmsg.Res02)
+ {
+ fprintf (stderr,
+ "BBD: DCDC block does not match the declared HW: init=%d\n",
+ pCh->pParent->dcdcType);
+ DXS_RETURN(DXS_statusBbdDCDCHwCfgMismatch);
+ }
+ /* enable charge pump */
+ ret = DXS_ChargePumpSwitchOn(pCh->pParent);
+ }
+ }
+ else
+ {
+ /* skip unsupported family block */
+ return DXS_statusOk;
+ }
+
+ if (ret == DXS_statusOk)
+ ret = DXS_SDD_DcDcConfigBBD(pCh, &dcdc_cfg.dcdc_data);
+
+ /* Set flag to start an automatic calibration after BBD download. */
+ if (ret == DXS_statusOk || ret == DXS_statusBbdDcDcReconfig)
+ (void) DXS_SDD_CalibrationNeededSet(pCh, 1);
+
+ /* It's not a real error for the entire BBD download */
+ if (ret == DXS_statusBbdDcDcReconfig)
+ ret = DXS_statusOk;
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function bbd_block_mwl
+
+ \param pCh - pointer to DXS channel structure
+ \param pHdr - pointer to BBD block header structure
+ \param pMwl - pointer to MWL block data
+ \param family - value from master block
+
+ \return
+ - DXS_status_t
+*/
+static int32_t bbd_block_mwl(DXS_CHANNEL_t *pCh, struct bbd_block_header *pHdr,
+ uint8_t *pMwl, uint32_t family)
+{
+ union DXS_FW_SDD_MwlConfig_u mwl = {0};
+ uint32_t len = pHdr->len;
+ int32_t ret;
+
+ /* skip unsupported family block */
+ if (family != BBD_FAMILY_ID_DXS && family != BBD_FAMILY_ID_DX8)
+ return DXS_statusOk;
+
+ DXS_cpb2dw(&mwl.u32[0], pMwl, len);
+
+ ret = DXS_SDD_MwlConfigBBD (pCh, &mwl.fwmsg);
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function bbd_block_utd
+
+ \param pCh - pointer to DXS channel structure
+ \param pHdr - pointer to BBD block header structure
+ \param pUtd - pointer to UTD block data
+ \param family - value from master block
+
+ \return
+ - DXS_status_t
+*/
+static int32_t bbd_block_utd(DXS_CHANNEL_t *pCh, struct bbd_block_header *pHdr,
+ uint8_t *pUtd, uint32_t family)
+{
+#ifdef DXS_FEAT_UTD
+ union DXS_FW_SIG_UtdCoeff_u utd = {0};
+ uint32_t len = pHdr->len;
+ int32_t ret;
+ uint16_t unToneIdx;
+
+ /* skip unsupported family block */
+ if (family != BBD_FAMILY_ID_DXS && family != BBD_FAMILY_ID_DX8)
+ return DXS_statusOk;
+
+ /* Tone index */
+ DXS_cpb2w(&unToneIdx, pUtd, sizeof(uint16_t));
+ /* Tone coefficients */
+ DXS_cpb2dw(&utd.u32[0], pUtd + sizeof(uint16_t), len - sizeof(uint16_t));
+
+ ret = DXS_SIG_UtdCoeffUpdate(pCh, unToneIdx, &utd.fwmsg);
+
+ DXS_RETURN(ret);
+#else
+ return DXS_statusOk;
+#endif /* DXS_FEAT_UTD */
+}
+
+/**
+ Function dxs_bbd_download
+
+ \param pCh - pointer to DXS channel structure
+ \param pBbd - pointer to BBD data buffer
+ \param nBytes - size of BBD data buffer
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_bbd_download(DXS_CHANNEL_t *pCh, uint8_t *pBbd, uint32_t nBytes)
+{
+ struct bbd_block_header hdr = {0};
+ struct bbd_block_master master = {0};
+ int32_t ret = DXS_statusOk;
+ uint32_t byte_pos = 0;
+ uint8_t bCalibrationNeeded;
+
+ if (pCh==NULL || nBytes==0 || pBbd==NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ /* for ROM 1.0 devices the patch download is mandatory */
+ if (pCh->pParent->rom_mask_ver < 2 &&
+ !(pCh->pParent->flags & DXS_DEV_PRAM_PATCH_DOWNLOADED))
+ {
+ DXS_RETURN(DXS_statusPramPatchNotDownloaded);
+ }
+
+ pCh->flags &= ~DXS_CH_BBD_DOWNLOADED;
+
+ /* TODO: overall bbd file integrity check:
+ - summary block length matches nBytes
+ - DCDC HW option matches configuration
+ - unsupported blocks present */
+
+ while (byte_pos < nBytes)
+ {
+ BBD_GET_HEAD (pBbd, byte_pos, &hdr);
+
+ switch (hdr.tag)
+ {
+ case BBD_BLK_ID_MASTER:
+ {
+ BBD_GET_MASTER(pBbd, byte_pos, &master);
+ if (master.magic != BBD_MAGIC)
+ {
+ /* invalid master block */
+ DXS_RETURN(DXS_statusBbdMasterBlkInvalid);
+ }
+ }
+ break;
+
+ case BBD_BLK_ID_CRAM:
+ case BBD_BLK_ID_CRAM2:
+ ret = bbd_block_cram(pCh, &hdr, pBbd + byte_pos, master.family);
+ break;
+
+ case BBD_BLK_ID_RING:
+ ret = bbd_block_ring(pCh, &hdr, pBbd + byte_pos, master.family);
+ break;
+
+ case BBD_BLK_ID_BASIC:
+ ret = bbd_block_basic(pCh, &hdr, pBbd + byte_pos, master.family);
+ break;
+
+ case BBD_BLK_ID_DCDC:
+ ret = bbd_block_dcdc(pCh, &hdr, pBbd + byte_pos, master.family);
+ break;
+
+ case BBD_BLK_ID_MWL:
+ ret = bbd_block_mwl(pCh, &hdr, pBbd + byte_pos, master.family);
+ break;
+
+ case BBD_BLK_ID_UTD:
+ ret = bbd_block_utd(pCh, &hdr, pBbd + byte_pos, master.family);
+ break;
+
+ case BBD_BLK_ID_END:
+ /* do nothing */
+ break;
+
+ default:
+ {
+ fprintf (stderr,
+ "Unknown unsupported block id 0x%04X in BBD at offset %lu.\n",
+ hdr.tag, (unsigned long int)(byte_pos - sizeof(struct bbd_block_header)));
+ DXS_RETURN(DXS_statusBbdUnknownBlk);
+ }
+ }
+
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(ret);
+ }
+
+ /* go to next block */
+ if (hdr.tag != BBD_BLK_ID_MASTER)
+ BBD_SKIP_BLOCK (byte_pos, hdr.len);
+ }
+
+ if (ret == DXS_statusOk)
+ {
+ pCh->flags |= DXS_CH_BBD_DOWNLOADED;
+ /* Do automatically a calibration on the channel on which the BBD was
+ downloaded to adapt to new coefficients. */
+ (void) DXS_SDD_CalibrationNeededGet(pCh, &bCalibrationNeeded);
+
+ if (bCalibrationNeeded == 1)
+ {
+ ret = DXS_SDD_Calibration(pCh);
+ }
+
+ if (ret != DXS_statusOk)
+ {
+ /* Automatic calibration failed. */
+ ret = DXS_statusAutomaticCalibrationFailed;
+ }
+ }
+
+ DXS_RETURN(ret);
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_bbd.h b/marvell/services/dxslic/api_lib/src/dxs_bbd.h
new file mode 100644
index 0000000..262e092
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_bbd.h
@@ -0,0 +1,38 @@
+#ifndef __DXS_BBD_H__
+#define __DXS_BBD_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_bbd.h
+ BBD functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern int32_t dxs_bbd_download(DXS_CHANNEL_t *pCh,
+ uint8_t *pBbd, uint32_t nBytes);
+
+
+#endif /* __DXS_BBD_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_cid.c b/marvell/services/dxslic/api_lib/src/dxs_cid.c
new file mode 100644
index 0000000..d752141
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_cid.c
@@ -0,0 +1,3942 @@
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_cid.c
+ Implementation of Caller ID functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdlib.h>
+#include <time.h>
+#include <pthread.h>
+
+#include "dxs.h"
+#include "dxs_config.h"
+#include "dxs_lib.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_sdd.h"
+#include "dxs_sig.h"
+#include "dxs_event.h"
+#include "dxs_cid_fsk.h"
+#include "dxs_pcm.h"
+#include "dxs_cid.h"
+#include "dxs_ring.h"
+
+#ifdef DXS_FEAT_CID
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_CID_CTX_MAGIC 0x58434944 /* "XCID" */
+
+/* default FSK configuration */
+#define DXS_CID_FSK_LEVEL_DEFAULT (-69) /* -6.9 dBm0 */
+#define DXS_CID_FSK_SEIZURE_DEFAULT 300
+#define DXS_CID_FSK_MARK_DEFAULT 180
+#define DXS_CID_FSK_AD_DEFAULT 1
+
+/* default SIN BT FSK mark bits */
+#define DXS_CID_FSK_BT_MARK_DEFAULT 80
+
+/* default ETSI type2 FSK mark bits */
+#define DXS_CID_FSK_ETSI_TYPE2_MARK_DEFAULT 80
+
+/* default TG configuration for DTAS */
+#define DXS_CID_DTAS_LEVEL1 (-138) /* -13.8 dBm0 */
+#define DXS_CID_DTAS_LEVEL2 (-138) /* -13.8 dBm0 */
+#define DXS_CID_DTAS_FREQ1 2130
+#define DXS_CID_DTAS_FREQ2 2750
+
+/* default ETSI timers */
+#define DXS_CID_ETSI_LONG_RING_MS 1000
+#define DXS_CID_ETSI_DTAS_MS 100
+#define DXS_CID_ETSI_RPAS_MS 200
+#define DXS_CID_ETSI_T0_DEFAULT 200
+#define DXS_CID_ETSI_T1_DEFAULT 200
+#define DXS_CID_ETSI_T2_DEFAULT 350
+#define DXS_CID_ETSI_T3_DEFAULT 650
+#define DXS_CID_ETSI_T4_DEFAULT 300
+#define DXS_CID_ETSI_T5_DEFAULT 700
+#define DXS_CID_ETSI_T6_DEFAULT 500
+#define DXS_CID_ETSI_T7_MAX 700
+#define DXS_CID_ETSI_TYPE2_DTAS_MS 80
+#define DXS_CID_ETSI_TYPE2_T14_DEFAULT 160
+#define DXS_CID_ETSI_TYPE2_T10_DEFAULT 50
+#define DXS_CID_ETSI_TYPE2_T12_DEFAULT 100
+#define DXS_CID_ETSI_TYPE2_T13_DEFAULT 50
+#define DXS_CID_ETSI_TYPE2_T9_DEFAULT 50
+#define DXS_CID_ETSI_T0dtmf_DEFAULT 300
+#define DXS_CID_ETSI_Tdtmf_DEFAULT 60
+#define DXS_CID_ETSI_T2dtmf_DEFAULT 300
+
+/* default Telcordia timers */
+#define DXS_CID_TELCORDIA_LONG_RING_MS 2000
+#define DXS_CID_TELCORDIA_OSI_MS 250
+#define DXS_CID_TELCORDIA_T0_DEFAULT 700
+#define DXS_CID_TELCORDIA_T1_DEFAULT 400
+#define DXS_CID_TELCORDIA_T2_DEFAULT 300
+#define DXS_CID_TELCORDIA_TYPE2_OSI_MS 0
+#define DXS_CID_TELCORDIA_TYPE2_W_MS 60
+#define DXS_CID_TELCORDIA_TYPE2_X_MS 0
+#define DXS_CID_TELCORDIA_TYPE2_X1_MS 40
+#define DXS_CID_TELCORDIA_TYPE2_Y_MS 85
+#define DXS_CID_TELCORDIA_TYPE2_T1_MS 165
+#define DXS_CID_TELCORDIA_TYPE2_Q_MS 100
+#define DXS_CID_TELCORDIA_TYPE2_S_MS 80
+#define DXS_CID_TELCORDIA_T0dtmf_DEFAULT 300
+#define DXS_CID_TELCORDIA_Tdtmf_DEFAULT 60
+#define DXS_CID_TELCORDIA_T2dtmf_DEFAULT 300
+
+/* default SIN BT timers */
+#define DXS_CID_BT_DTAS_MS 100
+#define DXS_CID_BT_T0_DEFAULT 120
+#define DXS_CID_BT_T1_DEFAULT 55
+#define DXS_CID_BT_T2_DEFAULT 220
+#define DXS_CID_BT_TYPE2_DTAS_MS 85
+#define DXS_CID_BT_TYPE2_ACK_MS 150
+#define DXS_CID_BT_TYPE2_T0_DEFAULT 45
+#define DXS_CID_BT_TYPE2_T1_DEFAULT 80
+#define DXS_CID_BT_TYPE2_T2_DEFAULT 50
+
+/* default NTT timers */
+#define DXS_CID_NTT_CARON_MS 500
+#define DXS_CID_NTT_CAROFF_MS 500
+#define DXS_CID_NTT_T0_DEFAULT 100
+#define DXS_CID_NTT_T1_DEFAULT 6000
+#define DXS_CID_NTT_T2_DEFAULT 400
+#define DXS_CID_NTT_T3_DEFAULT 7000
+#define DXS_CID_NTT_T4_DEFAULT 300
+#define DXS_CID_NTT_TYPE2_AS1_MS 100
+#define DXS_CID_NTT_TYPE2_AS2_MS 100
+#define DXS_CID_NTT_TYPE2_AS_PAUSE_MS 50
+#define DXS_CID_NTT_TYPE2_T0_DEFAULT 45
+#define DXS_CID_NTT_TYPE2_T1_DEFAULT 80
+#define DXS_CID_NTT_TYPE2_T2_DEFAULT 50
+
+/* length of each CID message parameter */
+#define DXS_CID_MSG_PARAM_DATE_TIME_FIXLEN 8
+#define DXS_CID_MSG_PARAM_CALLING_LINE_ID_MAXLEN 20
+#define DXS_CID_MSG_PARAM_CALLED_LINE_ID_MAXLEN 20
+#define DXS_CID_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN 1
+#define DXS_CID_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN 50
+#define DXS_CID_MSG_PARAM_RA_CALLING_PARTY_NAME_FIXLEN 1
+#define DXS_CID_MSG_PARAM_VI_FIXLEN 1
+#define DXS_CID_MSG_PARAM_MSG_ID_FIXLEN 3
+#define DXS_CID_MSG_PARAM_LM_CLI_MAXLEN 20
+#define DXS_CID_MSG_PARAM_COMP_DATE_TIME_FIXLEN1 8
+#define DXS_CID_MSG_PARAM_COMP_DATE_TIME_FIXLEN2 10
+#define DXS_CID_MSG_PARAM_COMP_CALLING_LINE_ID_MAXLEN 20
+#define DXS_CID_MSG_PARAM_CALL_TYPE_FIXLEN 1
+#define DXS_CID_MSG_PARAM_FIRST_CALLED_LINE_ID_MAXLEN 20
+#define DXS_CID_MSG_PARAM_NUM_MESSAGES_FIXLEN 1
+#define DXS_CID_MSG_PARAM_TYPE_FWD_CALL_FIXLEN 1
+#define DXS_CID_MSG_PARAM_TYPE_CALLING_USER_FIXLEN 1
+#define DXS_CID_MSG_PARAM_REDIR_NUM_MAXLEN 20
+#define DXS_CID_MSG_PARAM_CHARGE_FIXLEN 14
+#define DXS_CID_MSG_PARAM_ADDON_CHARGE_FIXLEN 14
+#define DXS_CID_MSG_PARAM_DURA_CALL_FIXLEN 6
+#define DXS_CID_MSG_PARAM_NET_PROV_ID_MAXLEN 20
+#define DXS_CID_MSG_PARAM_CARRIER_ID_MAXLEN 20
+#define DXS_CID_MSG_PARAM_SEL_TERMINAL_FUNC_MAXLEN 21
+#define DXS_CID_MSG_PARAM_DISP_INFO_MAXLEN 253
+#define DXS_CID_MSG_PARAM_SERV_INFO_FIXLEN 1
+#define DXS_CID_MSG_PARAM_EXTENSION_FIXLEN 10
+
+/* length of SIN BT CID message parameter */
+#define DXS_CID_BT_MSG_PARAM_CALL_TYPE_FIXLEN 1
+#define DXS_CID_BT_MSG_PARAM_DATE_TIME_FIXLEN 8
+#define DXS_CID_BT_MSG_PARAM_CALLING_LINE_ID_MAXLEN 18
+#define DXS_CID_BT_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN 1
+#define DXS_CID_BT_MSG_PARAM_CALLED_LINE_ID_MAXLEN 18
+#define DXS_CID_BT_MSG_PARAM_RA_CALLING_PARTY_NAME_FIXLEN 1
+#define DXS_CID_BT_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN 20
+#define DXS_CID_BT_MSG_PARAM_NUM_MESSAGES_FIXLEN 1
+
+/* length of NTT CID message parameter */
+#define DXS_CID_NTT_MSG_PARAM_CALLING_LINE_ID_MAXLEN 20
+#define DXS_CID_NTT_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN 1
+#define DXS_CID_NTT_MSG_PARAM_EXP_SIGNAL_FIXLEN 3
+
+/* reversed polarity flag */
+#define DXS_CID_LINE_MODE_POLARITY_FLAG_NORMAL 0x00
+#define DXS_CID_LINE_MODE_POLARITY_FLAG_REVERSED 0x10
+
+/* offhook/onhook state */
+#define DXS_CID_HOOK_STATE_ONHOOK 0x1
+#define DXS_CID_HOOK_STATE_OFFHOOK 0x2
+
+/* default TG configuration for NTT type2 alert tone */
+#define DXS_CID_NTT_TYPE2_ATONE_LEVEL1 (-138) /* -13.8 dBm0 */
+#define DXS_CID_NTT_TYPE2_ATONE_LEVEL2 (-138) /* -13.8 dBm0 */
+#define DXS_CID_NTT_TYPE2_ATONE_FREQ1 852
+#define DXS_CID_NTT_TYPE2_ATONE_FREQ2 1633
+#define DXS_CID_NTT_TYPE2_ATONE_FREQ3 941
+
+/* CID FSK messsage buffer's size */
+#define DXS_CID_FSK_MSG_BUF_MAX_LEN 258
+#define DXS_CID_FSK_BITS_PER_SEC 1200
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+struct __cid_msg_elem
+{
+ /* message type */
+ DXS_CID_MsgParam_t type;
+ /* message data */
+ char *data;
+ /* length of message data */
+ uint16_t len;
+ /* next message */
+ struct __cid_msg_elem *next;
+};
+typedef struct __cid_msg_elem dxs_cid_message_t;
+
+/* CID resource context */
+typedef struct
+{
+ /* magic code */
+ uint32_t magic;
+
+ /* CID standard */
+ DXS_CID_Std_t std;
+ /* alert signal */
+ DXS_CID_AS_t as;
+ /* data format */
+ DXS_CID_DATA_FMT_t df;
+ /* DTMF index for acknowledgment (type2 only) */
+ uint8_t dtmf_ack_idx;
+
+ /* timers ETSI */
+ DXS_CID_ETSI_Timers_t tm_etsi;
+ /* timers Telcordia */
+ DXS_CID_TELCORDIA_Timers_t tm_tc;
+ /* timers BT */
+ DXS_CID_BT_Timers_t tm_bt;
+ /* timers NTT */
+ DXS_CID_NTT_Timers_t tm_ntt;
+
+ /* Call Set-up message */
+ dxs_cid_message_t *msg_cs;
+ /* Message Waiting Indicator message */
+ dxs_cid_message_t *msg_mwi;
+ /* Advice of Charge message */
+ dxs_cid_message_t *msg_aoc;
+ /* Short Message Service */
+ dxs_cid_message_t *msg_sms;
+ /* Number Display service */
+ dxs_cid_message_t *msg_nd;
+
+ /* transmit data buffer */
+ uint8_t xmit_buffer[DXS_CID_FSK_MSG_BUF_MAX_LEN];
+ /* transmit data buffer length */
+ uint16_t xmit_length;
+
+ /* thread ID */
+ pthread_t thrd;
+ /* sem ID */
+ sem_t sema;
+ /* thread status */
+ volatile uint32_t complete;
+ /* thread return code */
+ int32_t ret;
+
+ /* CID SM */
+ int32_t (*cid_state)(void *arg);
+ /* timeout value for CID SM */
+ uint32_t timeout;
+ /* parameter's length depends on CID standard */
+ uint8_t (*len_check) (DXS_CID_MsgParam_t param, uint8_t length);
+ /* initial polarity before starting CID */
+ uint8_t polarity_initial;
+ /* expected hook state flag for CID SM state */
+ uint8_t hook_state_exp;
+ /* hook state */
+ volatile uint8_t hook_state;
+ /* timestamp of onhook/offhook */
+ uint8_t hook_timestamp;
+ /* hide off-hook during OSI for CID type2 */
+ volatile uint8_t hook_block;
+ /* ACK detection for CID SM Type2 */
+ volatile uint8_t ack_detect;
+ /* Unmute channel */
+ uint8_t need_unmute;
+
+ /* supervisory timeout for CID NTT SM */
+ uint16_t ntt_timeout;
+
+ /* calling instance (user API or Ringing SM) */
+ uint8_t calling_instance;
+} DXS_CID_Ctx_t;
+
+/* CID resource array */
+static DXS_CID_Ctx_t cid_res[DXS_MAX_DEVICES * CH_PER_DEVICE] = {0};
+/* 0-9, * 10, # 11, A-D(a-d) 12-15 */
+typedef struct
+{
+ int16_t level1;
+ int16_t level2;
+ uint16_t freq1;
+ uint16_t freq2;
+} dtmf_t;
+static dtmf_t dtmf[16] = {{-9, -7, 941, 1336}, {-9, -7, 697, 1209}, {-9, -7, 697, 1336}, {-9, -7, 697, 1477},
+ {-9, -7, 770, 1209}, {-9, -7, 770, 1336}, {-9, -7, 770, 1477}, {-9, -7, 852, 1209},
+ {-9, -7, 852, 1336}, {-9, -7, 852, 1477}, {-9, -7, 941, 1209}, {-9, -7, 941, 1477},
+ {-9, -7, 697, 1633}, {-9, -7, 770, 1633}, {-9, -7, 852, 1633}, {-9, -7, 941, 1633},
+ };
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/**
+ Get the message of a type
+
+ \param pCid - pointer to \ref DXS_CID_Ctx_t structure
+ \param type - message type
+
+ \return
+ - message pointer
+*/
+static dxs_cid_message_t *dxs_cid_message_get(DXS_CID_Ctx_t *pCid,
+ DXS_CID_MsgType_t type)
+{
+ dxs_cid_message_t *pMsg = NULL;
+
+ if (type == DXS_CID_MSG_TYPE_CS)
+ pMsg = pCid->msg_cs;
+ else if (type == DXS_CID_MSG_TYPE_MWI)
+ pMsg = pCid->msg_mwi;
+ else if (type == DXS_CID_MSG_TYPE_AOC)
+ pMsg = pCid->msg_aoc;
+ else if (type == DXS_CID_MSG_TYPE_SMS)
+ pMsg = pCid->msg_sms;
+ else if (type == DXS_CID_MSG_TYPE_ND)
+ pMsg = pCid->msg_nd;
+ /* other message types are not supported */
+
+ return pMsg;
+}
+
+/**
+ Set the message of a type
+
+ \param pCid - pointer to \ref DXS_CID_Ctx_t structure
+ \param type - message type
+ \param pMsg - message
+
+ \return
+ - none
+*/
+static void dxs_cid_message_set(DXS_CID_Ctx_t *pCid, DXS_CID_MsgType_t type,
+ dxs_cid_message_t *pMsg)
+{
+ if (type == DXS_CID_MSG_TYPE_CS)
+ pCid->msg_cs = pMsg;
+ else if (type == DXS_CID_MSG_TYPE_MWI)
+ pCid->msg_mwi = pMsg;
+ else if (type == DXS_CID_MSG_TYPE_AOC)
+ pCid->msg_aoc = pMsg;
+ else if (type == DXS_CID_MSG_TYPE_SMS)
+ pCid->msg_sms = pMsg;
+ else if (type == DXS_CID_MSG_TYPE_ND)
+ pCid->msg_nd = pMsg;
+ /* other message types are not supported */
+}
+
+/**
+ Vipe a CID message from CID context
+
+ \param pCid - pointer to \ref DXS_CID_Ctx_t structure
+ \param type - message type \ref DXS_CID_MsgType_t
+
+ \return
+ - DXS_status_t
+*/
+static void dxs_cid_msg_clear (DXS_CID_Ctx_t *pCid, DXS_CID_MsgType_t type)
+{
+ dxs_cid_message_t *pMsg = dxs_cid_message_get(pCid, type);
+
+ while (pMsg != NULL)
+ {
+ dxs_cid_message_t *p = pMsg;
+
+ /* free parameter value */
+ free(pMsg->data);
+ /* take next message */
+ pMsg = pMsg->next;
+ dxs_cid_message_set(pCid, type, pMsg);
+ /* free parameter */
+ free (p);
+ }
+}
+
+/**
+ Vipe all CID messages from CID context
+
+ \param pCid - pointer to \ref DXS_CID_Ctx_t structure
+
+ \return
+ - DXS_status_t
+*/
+static void dxs_cid_msg_clearall (DXS_CID_Ctx_t *pCid)
+{
+ dxs_cid_msg_clear (pCid, DXS_CID_MSG_TYPE_CS);
+ dxs_cid_msg_clear (pCid, DXS_CID_MSG_TYPE_MWI);
+ dxs_cid_msg_clear (pCid, DXS_CID_MSG_TYPE_AOC);
+ dxs_cid_msg_clear (pCid, DXS_CID_MSG_TYPE_SMS);
+ dxs_cid_msg_clear (pCid, DXS_CID_MSG_TYPE_ND);
+}
+
+/**
+ Function to set parity bit
+
+ \param data_byte - source data
+
+ \return
+ - uint8_t
+*/
+static uint8_t dxs_cid_parity_set(uint8_t data_byte)
+{
+ uint8_t i, ones_num = 0, tmpByte = data_byte;
+
+ /* check even parity for b7...b1 */
+ for (i = 0; i < 7; i++)
+ {
+ /* count number of ones */
+ if (tmpByte & 0x1)
+ ones_num ++;
+ tmpByte >>= 1;
+ }
+ /* set parity bit as MSB in case of odd num (i.e. lowest bit is set) */
+ if (ones_num & 0x1)
+ data_byte |= 0x80;
+
+ return data_byte;
+}
+
+/**
+ Calculate CRC for NTT FSK encoding.
+
+ \param pCidBuf CID data buffer.
+ \param len Buffer size in octets.
+
+ \return calculated CRC
+
+ \remarks
+ \verbatim
+ 1- The CRC16 for NTT FSK Buffer is generated with the polynom
+ X^16 + X^12 + X^5 + X^2 + X^0 (Hexadecimal: 0x8408)
+ 2- The algorithm is:
+ a)initial value of CRC = 0x0000.
+ b)for each byte (from header to ETX)
+ compute the CRC with G(x) (CRC1)
+ CRC= CRC + CRC1
+ \endverbatim
+*/
+static uint16_t dxs_cid_crc_ntt(uint8_t *pCidBuf, uint8_t len)
+{
+ uint16_t crc = 0, tmp;
+ uint8_t i, j, byte;
+
+ for (i = 0; i < len; i++)
+ {
+ /* get reversed data byte */
+ byte = pCidBuf [i];
+ tmp = (byte << 1);
+ for (j = 8; j > 0; j--)
+ {
+ tmp >>= 1;
+ if ((tmp ^ crc) & 0x0001)
+ crc = (crc >> 1) ^ 0x8408;
+ else
+ crc >>= 1;
+ }
+ }
+ return crc;
+}
+
+/**
+ Prepare data buffer for DTMF transmit
+
+ \param pCid - pointer to \ref DXS_CID_Ctx_t structure
+ \param
+
+ \return
+ - DXS_status_t
+*/
+static int32_t dxs_cid_dtmf_buffer_prepare(DXS_CID_Ctx_t *pCid,
+ DXS_CID_MsgType_t msg_type)
+{
+ /* prepare buffer for sending in DTMF */
+ dxs_cid_message_t *p, *pMsg = dxs_cid_message_get(pCid, msg_type);
+ uint16_t buffer_length = 0, pos = 2;
+
+ if (pMsg == NULL)
+ {
+ /* uninitialized message, return error */
+ DXS_RETURN(DXS_statusCidMsgNotInit);
+ }
+
+ p = pMsg;
+ /* calculate total length for an DTMF buffer */
+ while (p != NULL)
+ {
+ buffer_length += (p->len);
+ p = p->next;
+ }
+ buffer_length += 2; /* length + pos in the head */
+
+ if (buffer_length > DXS_CID_FSK_MSG_BUF_MAX_LEN)
+ {
+ /* Message length is too high, return error */
+ DXS_RETURN(DXS_statusCidMsgLenWrong);
+ }
+
+ p = pMsg;
+ /* copy the parameters */
+ while (p != NULL)
+ {
+ uint8_t i;
+ {
+ for (i=0; i<p->len; i++)
+ {
+ /* 0-9, * 10, # 11, A-D(a-d) 12-15 */
+ if ((p->data[i] >= 0x30) && (p->data[i] <= 0x39))
+ pCid->xmit_buffer[pos++] = p->data[i] - 0x30;
+ else if (p->data[i] == 0x2A) /* * */
+ pCid->xmit_buffer[pos++] = 10;
+ else if (p->data[i] == 0x23) /* # */
+ pCid->xmit_buffer[pos++] = 11;
+ else if ((p->data[i] >= 0x41) && (p->data[i] <= 0x44)) /* A-D */
+ pCid->xmit_buffer[pos++] = p->data[i] - 0x35;
+ else if ((p->data[i] >= 0x61) && (p->data[i] <= 0x64)) /* a-d */
+ pCid->xmit_buffer[pos++] = p->data[i] - 0x55;
+ }
+ }
+
+ p = p->next;
+ }
+ /* set buffer length */
+ pCid->xmit_buffer[0] = pos - 2; /* length of data */
+ pCid->xmit_buffer[1] = 2; /* next data position, used when transmitting */
+ pCid->xmit_length = pos; /* total length includes the headerr */
+ /* printf("cid_prepare %d, %d, %d, %d, %d\n", pCid->xmit_length, pCid->xmit_buffer[0], pCid->xmit_buffer[1], pCid->xmit_buffer[2], pCid->xmit_buffer[3]); */
+ return DXS_statusOk;
+
+}
+
+/**
+ Prepare data buffer for FSK transmit
+
+ \param pCid - pointer to \ref DXS_CID_Ctx_t structure
+ \param
+
+ \return
+ - DXS_status_t
+*/
+static int32_t dxs_cid_fsk_buffer_prepare(DXS_CID_Ctx_t *pCid,
+ DXS_CID_MsgType_t msg_type)
+{
+ dxs_cid_message_t *p, *pMsg = dxs_cid_message_get(pCid, msg_type);
+ uint16_t buffer_length = 0, pos = 2, i;
+ uint8_t fsk_data_cksum = 0;
+
+ if (pMsg == NULL)
+ {
+ /* uninitialized message, return error */
+ DXS_RETURN(DXS_statusCidMsgNotInit);
+ }
+
+ p = pMsg;
+
+ /* calculate total length for an FSK buffer */
+ while (p != NULL)
+ {
+ buffer_length += (p->len + 2); /* + parameter code + length byte */
+ p = p->next;
+ }
+ buffer_length += 3; /* + message type code + total length byte + checksum */
+
+ if (buffer_length > DXS_CID_FSK_MSG_BUF_MAX_LEN)
+ {
+ /* Message length is too high, return error */
+ DXS_RETURN(DXS_statusCidMsgLenWrong);
+ }
+
+ pCid->xmit_buffer[0] = msg_type;
+ pCid->xmit_buffer[1] = buffer_length - 3;
+
+ p = pMsg;
+ /* copy the parameters */
+ while (p != NULL)
+ {
+ uint8_t i;
+
+ pCid->xmit_buffer[pos++] = p->type;
+ pCid->xmit_buffer[pos++] = p->len;
+
+#if 0
+ /* update date/time */
+ if (p->type == DXS_CID_MSG_PARAM_DATE_TIME)
+ {
+ struct tm tms = {0};
+ time_t rawtime = time(NULL);
+
+ localtime_r(&rawtime, &tms);
+
+ /* month */
+ pCid->xmit_buffer[pos++] = (tms.tm_mon + 1) / 10 + '0';
+ pCid->xmit_buffer[pos++] = (tms.tm_mon + 1) % 10 + '0';
+ /* day */
+ pCid->xmit_buffer[pos++] = tms.tm_mday / 10 + '0';
+ pCid->xmit_buffer[pos++] = tms.tm_mday % 10 + '0';
+ /* hour */
+ pCid->xmit_buffer[pos++] = tms.tm_hour / 10 + '0';
+ pCid->xmit_buffer[pos++] = tms.tm_hour % 10 + '0';
+ /* minute */
+ pCid->xmit_buffer[pos++] = tms.tm_min / 10 + '0';
+ pCid->xmit_buffer[pos++] = tms.tm_min % 10 + '0';
+ }
+ else
+#endif
+ {
+ for (i=0; i<p->len; i++)
+ pCid->xmit_buffer[pos++] = p->data[i];
+ }
+
+ p = p->next;
+ }
+
+ /* calculate checksum */
+ for (i=0; i<pos; i++)
+ fsk_data_cksum += pCid->xmit_buffer[i];
+
+ pCid->xmit_buffer[pos] = ~(fsk_data_cksum & 0xFF) + 1;
+
+ /* set buffer length */
+ pCid->xmit_length = buffer_length;
+
+ return DXS_statusOk;
+}
+
+/**
+ Prepare data buffer for FSK transmit (NTT standard)
+
+ \param pCid - pointer to \ref DXS_CID_Ctx_t structure
+ \param
+
+ \return
+ - DXS_status_t
+*/
+static int32_t dxs_cid_fsk_buffer_prepare_ntt(DXS_CID_Ctx_t *pCid,
+ DXS_CID_MsgType_t msg_type)
+{
+ dxs_cid_message_t *p, *pMsg = dxs_cid_message_get(pCid, msg_type);
+
+ uint16_t buffer_length = 0, pos = 6, crc;
+
+ if (pMsg == NULL)
+ {
+ /* uninitialized message, return error */
+ DXS_RETURN(DXS_statusCidMsgNotInit);
+ }
+ p = pMsg;
+
+ /* calculate total length for an FSK buffer */
+ while (p != NULL)
+ {
+ buffer_length += (p->len + 2); /* + parameter code + length byte */
+ /* Increase buffer's size for DLE insertion */
+ if (p->len == 16)
+ buffer_length++;
+ p = p->next;
+ }
+ /* Increase buffer's size for DLE insertion */
+ if (buffer_length == 16)
+ buffer_length++;
+ /* + DLE+SOH+Header+DLE+STX+ServiceType+MessageLength+DLE+ETX+CRC(2) */
+ buffer_length += 11;
+
+ if (buffer_length > 128)
+ {
+ /* Message length is too high, return error */
+ DXS_RETURN(DXS_statusCidMsgLenWrong);
+ }
+
+ pCid->xmit_buffer[0] = 0x90; /* DLE (w parity)*/
+ pCid->xmit_buffer[1] = 0x81; /* SOH (w parity) */
+ pCid->xmit_buffer[2] = 0x87; /* Header (w parity) */
+ pCid->xmit_buffer[3] = 0x90; /* DLE (w parity)*/
+ pCid->xmit_buffer[4] = 0x82; /* STX (w parity)*/
+ pCid->xmit_buffer[5] = dxs_cid_parity_set(msg_type);
+ if (buffer_length == 28)
+ {
+ pCid->xmit_buffer[pos++] = 0x90; /* DLE (w parity)*/
+ pCid->xmit_buffer[pos++] = 0x90;
+ }
+ else
+ pCid->xmit_buffer[pos++] = dxs_cid_parity_set(buffer_length - 11);
+
+ p = pMsg;
+ /* copy the parameters */
+ while (p != NULL)
+ {
+ uint8_t i;
+
+ pCid->xmit_buffer[pos++] = dxs_cid_parity_set(p->type);
+ if (p->len == 16)
+ pCid->xmit_buffer[pos++] = 0x90; /* DLE (w parity)*/
+ pCid->xmit_buffer[pos++] = dxs_cid_parity_set(p->len);
+ for (i=0; i<p->len; i++)
+ pCid->xmit_buffer[pos++] = dxs_cid_parity_set(p->data[i]);
+
+ p = p->next;
+ }
+
+ /* Add control fields */
+ pCid->xmit_buffer[pos++] = 0x90; /* DLE (w parity)*/
+ pCid->xmit_buffer[pos++] = 0x03; /* ETX (w parity)*/
+
+ /* Add CRC (from HEADER to ETX) */
+ crc = dxs_cid_crc_ntt(&pCid->xmit_buffer[2], (uint8_t) pos - 2);
+ pCid->xmit_buffer[pos++] = (uint8_t) (crc & 0xFF);
+ pCid->xmit_buffer[pos] = (uint8_t) ((crc >> 8) & 0xFF);
+
+ /* set buffer length */
+ pCid->xmit_length = buffer_length;
+
+ return DXS_statusOk;
+}
+
+/**
+ Check ETSI message parameter length
+
+ \param param - message parameter
+ \param length - message length
+
+ \return
+ - updated length
+*/
+static uint8_t dxs_cid_param_length_check_etsi(DXS_CID_MsgParam_t param,
+ uint8_t length)
+{
+ uint8_t updated_length = length;
+
+ switch (param)
+ {
+ case DXS_CID_MSG_PARAM_DATE_TIME:
+ updated_length = DXS_CID_MSG_PARAM_DATE_TIME_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_CALLING_LINE_ID:
+ if (updated_length > DXS_CID_MSG_PARAM_CALLING_LINE_ID_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_CALLING_LINE_ID_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_CALLED_LINE_ID:
+ if (updated_length > DXS_CID_MSG_PARAM_CALLED_LINE_ID_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_CALLED_LINE_ID_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_RA_CALLING_LINE_ID:
+ updated_length = DXS_CID_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_CALLING_PARTY_NAME:
+ if (updated_length > DXS_CID_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_RA_CALLING_PARTY_NAME:
+ updated_length = DXS_CID_MSG_PARAM_RA_CALLING_PARTY_NAME_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_VI:
+ updated_length = DXS_CID_MSG_PARAM_VI_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_MSG_ID:
+ updated_length = DXS_CID_MSG_PARAM_MSG_ID_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_LM_CLI:
+ if (updated_length > DXS_CID_MSG_PARAM_LM_CLI_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_LM_CLI_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_COMP_DATE_TIME:
+ if (updated_length != DXS_CID_MSG_PARAM_COMP_DATE_TIME_FIXLEN1 &&
+ updated_length != DXS_CID_MSG_PARAM_COMP_DATE_TIME_FIXLEN2)
+ updated_length = DXS_CID_MSG_PARAM_COMP_DATE_TIME_FIXLEN2;
+ break;
+
+ case DXS_CID_MSG_PARAM_COMP_CALLING_LINE_ID:
+ if (updated_length > DXS_CID_MSG_PARAM_COMP_CALLING_LINE_ID_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_COMP_CALLING_LINE_ID_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_CALL_TYPE:
+ updated_length = DXS_CID_MSG_PARAM_CALL_TYPE_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_FIRST_CALLED_LINE_ID:
+ if (updated_length > DXS_CID_MSG_PARAM_FIRST_CALLED_LINE_ID_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_FIRST_CALLED_LINE_ID_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_NUM_MESSAGES:
+ updated_length = DXS_CID_MSG_PARAM_NUM_MESSAGES_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_TYPE_FWD_CALL:
+ updated_length = DXS_CID_MSG_PARAM_TYPE_FWD_CALL_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_TYPE_CALLING_USER:
+ updated_length = DXS_CID_MSG_PARAM_TYPE_CALLING_USER_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_REDIR_NUM:
+ if (updated_length > DXS_CID_MSG_PARAM_REDIR_NUM_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_REDIR_NUM_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_CHARGE:
+ updated_length = DXS_CID_MSG_PARAM_CHARGE_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_ADDON_CHARGE:
+ updated_length = DXS_CID_MSG_PARAM_ADDON_CHARGE_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_DURA_CALL:
+ updated_length = DXS_CID_MSG_PARAM_DURA_CALL_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_NET_PROV_ID:
+ if (updated_length > DXS_CID_MSG_PARAM_NET_PROV_ID_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_NET_PROV_ID_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_CARRIER_ID:
+ if (updated_length > DXS_CID_MSG_PARAM_CARRIER_ID_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_CARRIER_ID_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_SEL_TERMINAL_FUNC:
+ if (updated_length > DXS_CID_MSG_PARAM_SEL_TERMINAL_FUNC_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_SEL_TERMINAL_FUNC_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_DISP_INFO:
+ if (updated_length > DXS_CID_MSG_PARAM_DISP_INFO_MAXLEN)
+ updated_length = DXS_CID_MSG_PARAM_DISP_INFO_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_SERV_INFO:
+ updated_length = DXS_CID_MSG_PARAM_SERV_INFO_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_EXTENSION:
+ updated_length = DXS_CID_MSG_PARAM_EXTENSION_FIXLEN;
+ break;
+
+ default:
+ break;
+ }
+
+ return updated_length;
+}
+
+/**
+ Check SIN BT message parameter length
+
+ \param param - message parameter
+ \param length - message length
+
+ \return
+ - updated length
+*/
+static uint8_t dxs_cid_param_length_check_bt(DXS_CID_MsgParam_t param,
+ uint8_t length)
+{
+ uint8_t updated_length = length;
+
+ switch (param)
+ {
+ case DXS_CID_MSG_PARAM_DATE_TIME:
+ updated_length = DXS_CID_BT_MSG_PARAM_DATE_TIME_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_CALLING_LINE_ID:
+ if (updated_length > DXS_CID_BT_MSG_PARAM_CALLING_LINE_ID_MAXLEN)
+ updated_length = DXS_CID_BT_MSG_PARAM_CALLING_LINE_ID_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_CALLED_LINE_ID:
+ if (updated_length > DXS_CID_BT_MSG_PARAM_CALLED_LINE_ID_MAXLEN)
+ updated_length = DXS_CID_BT_MSG_PARAM_CALLED_LINE_ID_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_RA_CALLING_LINE_ID:
+ updated_length = DXS_CID_BT_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_CALLING_PARTY_NAME:
+ if (updated_length > DXS_CID_BT_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN)
+ updated_length = DXS_CID_BT_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_RA_CALLING_PARTY_NAME:
+ updated_length = DXS_CID_BT_MSG_PARAM_RA_CALLING_PARTY_NAME_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_CALL_TYPE:
+ updated_length = DXS_CID_BT_MSG_PARAM_CALL_TYPE_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_NUM_MESSAGES:
+ updated_length = DXS_CID_BT_MSG_PARAM_NUM_MESSAGES_FIXLEN;
+ break;
+
+ default:
+ break;
+ }
+
+ return updated_length;
+}
+
+/**
+ Check NTT message parameter length
+
+ \param param - message parameter
+ \param length - message length
+
+ \return
+ - updated length
+*/
+static uint8_t dxs_cid_param_length_check_ntt(DXS_CID_MsgParam_t param,
+ uint8_t length)
+{
+ uint8_t updated_length = length;
+
+ switch (param)
+ {
+ case DXS_CID_MSG_PARAM_CALLING_LINE_ID:
+ if (updated_length > DXS_CID_NTT_MSG_PARAM_CALLING_LINE_ID_MAXLEN)
+ updated_length = DXS_CID_NTT_MSG_PARAM_CALLING_LINE_ID_MAXLEN;
+ break;
+
+ case DXS_CID_MSG_PARAM_RA_CALLING_LINE_ID:
+ updated_length = DXS_CID_NTT_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN;
+ break;
+
+ case DXS_CID_MSG_NTT_EXP_SIGNAL:
+ updated_length = DXS_CID_NTT_MSG_PARAM_EXP_SIGNAL_FIXLEN;
+ break;
+
+ default:
+ break;
+ }
+
+ return updated_length;
+}
+
+/**
+ Check Telcordia message parameter length
+
+ \param param - message parameter
+ \param length - message length
+
+ \return
+ - updated length
+*/
+static uint8_t dxs_cid_param_length_check_tc(DXS_CID_MsgParam_t param,
+ uint8_t length)
+{
+ uint8_t updated_length = length;
+
+ switch (param)
+ {
+ /* TODO */
+ default:
+ break;
+ }
+
+ return updated_length;
+}
+
+/**
+ Waiting function for a state machine
+
+ \param pCid - pointer to \ref DXS_CID_Ctx_t structure
+
+ \return
+ - DXS_status_t
+*/
+static void dxs_cid_wait (DXS_CID_Ctx_t *pCid)
+{
+ struct timespec ts = {0};
+
+ if (pCid->timeout == 0)
+ return;
+
+ /* wait */
+ clock_gettime (CLOCK_REALTIME, &ts);
+ if (!(pCid->timeout % 1000))
+ {
+ ts.tv_sec += pCid->timeout / 1000;
+ }
+ else
+ {
+ unsigned long ns;
+
+ ns = ts.tv_nsec + pCid->timeout * 1000 * 1000;
+ ts.tv_nsec = ns % (1000 * 1000 * 1000);
+ ts.tv_sec += ns / (1000 * 1000 * 1000);
+ }
+ sem_timedwait(&pCid->sema, &ts);
+}
+
+/* ========================================================================== */
+/* CID SM */
+/* ========================================================================== */
+
+/* CID SM final state (success) */
+/**
+ dxs_cid_sm_fin
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_sm_fin(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ DXS_Event_t dxs_event = {0};
+
+ pCid->complete = 1;
+
+ /* Unmute channel */
+ if (pCid->need_unmute)
+ {
+ if (dxs_pcm_ch_mute(pCh, 0) == DXS_statusOk)
+ pCid->need_unmute = 0;
+ }
+
+ /* if called from ring SM, inform ring SM */
+ if (pCid->calling_instance == DXS_CID_CALL_FROM_RING_SM)
+ {
+ DXS_Ring_CidFinished(pCh);
+ }
+ else
+ {
+ /* inform the application */
+ dxs_event.dev = pCh->pParent->nDevNum;
+ dxs_event.ch = pCh->nCh;
+ dxs_event.id = DXS_EVENT_CID_SEQ_END;
+ DXS_EventDispatch(pCh->pParent, &dxs_event);
+ }
+ pthread_detach(pCid->thrd);
+ sem_post(&pCid->sema);
+ return DXS_statusOk;
+}
+
+/* CID SM final state (timeout) */
+/**
+ dxs_cid_sm_err_timeout
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_sm_err_timeout(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ DXS_Event_t dxs_event = {0};
+
+ pCid->complete = 1;
+
+ /* Unmute channel */
+ if (pCid->need_unmute)
+ {
+ if (dxs_pcm_ch_mute(pCh, 0) == DXS_statusOk)
+ pCid->need_unmute = 0;
+ }
+
+ /* inform application */
+ dxs_event.dev = pCh->pParent->nDevNum;
+ dxs_event.ch = pCh->nCh;
+ dxs_event.id = DXS_EVENT_CID_SEQ_ERROR;
+ dxs_event.data.cid_err = DXS_EVENT_CID_TIMEOUT;
+ DXS_EventDispatch(pCh->pParent, &dxs_event);
+
+ pthread_detach(pCid->thrd);
+ sem_post(&pCid->sema);
+ return DXS_statusOk;
+}
+
+/* CID SM final state (incorrect hook state) */
+/**
+ dxs_cid_sm_err_hook
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_sm_err_hook(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ DXS_Event_t dxs_event = {0};
+
+ pCid->complete = 1;
+
+ /* Attempt to stop FSK transmitter */
+ if (pCid->df == DXS_CID_DATA_FSK)
+ DXS_CID_FSK_Stop(pCh);
+ /* Attempt to stop tone */
+ dxs_tone_stop(pCh);
+ /* Restore active line mode */
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ /* Unmute channel */
+ if (pCid->need_unmute)
+ {
+ if (dxs_pcm_ch_mute(pCh, 0) == DXS_statusOk)
+ pCid->need_unmute = 0;
+ }
+
+ /* inform application */
+ dxs_event.dev = pCh->pParent->nDevNum;
+ dxs_event.ch = pCh->nCh;
+ dxs_event.id = DXS_EVENT_CID_SEQ_ERROR;
+ dxs_event.data.cid_err = DXS_EVENT_CID_HOOK_STATE;
+ DXS_EventDispatch(pCh->pParent, &dxs_event);
+
+ pthread_detach(pCid->thrd);
+ sem_post(&pCid->sema);
+ return DXS_statusOk;
+}
+
+/* ========================================================================== */
+/* ETSI protocol */
+/* ========================================================================== */
+
+/* CID SM states - ETSI */
+static int32_t dxs_cid_etsi_init(void *arg);
+static int32_t dxs_cid_etsi_dtas(void *arg);
+static int32_t dxs_cid_etsi_ring(void *arg);
+static int32_t dxs_cid_etsi_after_lr(void *arg);
+static int32_t dxs_cid_dtmf_off(void *arg);
+static int32_t dxs_cid_dtmf_on(void *arg);
+static int32_t dxs_cid_etsi_after_alert(void *arg);
+static int32_t dxs_cid_etsi_data_xmit(void *arg);
+static int32_t dxs_cid_etsi_after_data_xmit(void *arg);
+
+/**
+ dxs_cid_etsi_init
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_init(void *arg)
+{
+ int32_t ret = DXS_statusOk;
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->as == DXS_CID_AS_DTAS || pCid->as == DXS_CID_AS_LR_DTAS)
+ {
+ dxs_tone_config(pCh, DXS_CID_DTAS_LEVEL1,
+ DXS_CID_DTAS_LEVEL2,
+ DXS_CID_DTAS_FREQ1,
+ DXS_CID_DTAS_FREQ2, 0, 0);
+ }
+
+ if (pCid->as == DXS_CID_AS_NONE)
+ {
+ ret = DXS_SDD_LineModeSet(pCh,
+ DXS_LINE_FEED_RING_BURST ^ pCid->polarity_initial);
+ pCid->timeout = pCid->tm_etsi.lring;
+ pCid->cid_state = dxs_cid_etsi_ring;
+ }
+ else if (pCid->as == DXS_CID_AS_DTAS)
+ {
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_etsi.dtas;
+ pCid->cid_state = dxs_cid_etsi_dtas;
+ }
+ else if (pCid->as == DXS_CID_AS_LR_DTAS)
+ {
+ DXS_SDD_LineModeSet(pCh,
+ DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
+ pCid->timeout = pCid->tm_etsi.T0;
+ pCid->cid_state = dxs_cid_etsi_after_lr;
+ }
+ else if (pCid->as == DXS_CID_AS_ETSI_DTMF)
+ {
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
+ pCid->timeout = pCid->tm_etsi.T0dtmf;
+ pCid->cid_state = dxs_cid_etsi_after_alert;
+ }
+ else if (pCid->as == DXS_CID_AS_RPAS)
+ {
+ ret = DXS_SDD_LineModeSet(pCh,
+ DXS_LINE_FEED_RING_BURST ^ pCid->polarity_initial);
+ pCid->timeout = pCid->tm_etsi.rpas;
+ pCid->cid_state = dxs_cid_etsi_ring;
+ }
+ return ret;
+}
+
+/**
+ dxs_cid_etsi_dtas
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_dtas(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_stop(pCh);
+
+ if (pCid->as == DXS_CID_AS_DTAS)
+ pCid->timeout = pCid->tm_etsi.T4;
+ else if (pCid->as == DXS_CID_AS_LR_DTAS)
+ pCid->timeout = pCid->tm_etsi.T1;
+
+ pCid->cid_state = dxs_cid_etsi_after_alert;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_etsi_ring
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_ring(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+
+ if (pCid->as == DXS_CID_AS_NONE)
+ pCid->timeout = pCid->tm_etsi.T5;
+ else if (pCid->as == DXS_CID_AS_RPAS)
+ pCid->timeout = pCid->tm_etsi.T3;
+
+ pCid->cid_state = dxs_cid_etsi_after_alert;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_etsi_after_lr
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_after_lr(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_etsi.dtas;
+ pCid->cid_state = dxs_cid_etsi_dtas;
+ return DXS_statusOk;
+}
+
+/**
+ Silent betwee 2 DTMF digits
+
+ \param arg
+
+ \return
+ - DXS_status_t
+*/
+
+int32_t dxs_cid_dtmf_off(void *arg) //YanJC
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ /* stop DTMF tone */
+ dxs_tone_stop(pCh);
+ pCid->timeout = pCid->tm_etsi.Tdtmf; /* */
+ pCid->cid_state = dxs_cid_dtmf_on;
+
+ return DXS_statusOk;
+}
+
+/**
+ Send next DTMF digit
+
+ \param arg
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_cid_dtmf_on(void *arg) //YanJC
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ uint8_t digi = pCid->xmit_buffer[pCid->xmit_buffer[1]];
+ if (pCid->xmit_length > pCid->xmit_buffer[1])
+ {
+ pCid->xmit_buffer[1] += 1;
+ /* send one digit */
+ dxs_tone_config(pCh, dtmf[digi].level1, dtmf[digi].level2, dtmf[digi].freq1, dtmf[digi].freq2, 0, 0);
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_etsi.Tdtmf; /* */
+ pCid->cid_state = dxs_cid_dtmf_off;
+ }
+ else
+ {
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ /* all digits over. */
+ pCid->timeout = pCid->tm_etsi.T2dtmf;
+ pCid->cid_state = dxs_cid_etsi_after_data_xmit;
+ }
+
+ return DXS_statusOk;
+}
+/**
+ dxs_cid_etsi_after_alert
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_after_alert(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->df == DXS_CID_DATA_FSK)
+ {
+ /* call FSK transmitter */
+ DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
+ pCid->xmit_length);
+ pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
+ pCid->cid_state = dxs_cid_etsi_data_xmit;
+ }
+ else if (pCid->df == DXS_CID_DATA_DTMF)
+ {
+ /* call DTMF transmitter */
+ dxs_cid_dtmf_on((void *)pCh);
+ }
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_etsi_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->as == DXS_CID_AS_NONE)
+ pCid->timeout = pCid->tm_etsi.T6;
+ else
+ pCid->timeout = pCid->tm_etsi.T2;
+
+ pCid->cid_state = dxs_cid_etsi_after_data_xmit;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_etsi_after_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_after_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->as == DXS_CID_AS_LR_DTAS)
+ {
+ /* restore line polarity */
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ }
+
+ pCid->timeout = 0;
+ pCid->cid_state = dxs_cid_sm_fin;
+ return DXS_statusOk;
+}
+
+/* CID type2 SM states - ETSI */
+static int32_t dxs_cid_etsi_type2_init(void *arg);
+static int32_t dxs_cid_etsi_type2_silence(void *arg);
+static int32_t dxs_cid_etsi_type2_as(void *arg);
+static int32_t dxs_cid_etsi_type2_wait_ack(void *arg);
+static int32_t dxs_cid_etsi_type2_before_data_xmit(void *arg);
+static int32_t dxs_cid_etsi_type2_data_xmit(void *arg);
+
+/**
+ dxs_cid_etsi_type2_init
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_type2_init(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_config(pCh, DXS_CID_DTAS_LEVEL1,
+ DXS_CID_DTAS_LEVEL2,
+ DXS_CID_DTAS_FREQ1,
+ DXS_CID_DTAS_FREQ2, 0, 0);
+
+ pCid->timeout = pCid->tm_etsi.t2_T10;
+ pCid->cid_state = dxs_cid_etsi_type2_silence;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_etsi_type2_silence
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_type2_silence(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_etsi.t2_dtas;
+ pCid->cid_state = dxs_cid_etsi_type2_as;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_etsi_type2_as
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_type2_as(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_stop(pCh);
+ pCid->timeout = pCid->tm_etsi.t2_T14;
+ pCid->cid_state = dxs_cid_etsi_type2_wait_ack;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_etsi_type2_wait_ack
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_type2_wait_ack(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->ack_detect)
+ {
+ pCid->ack_detect = 0;
+ pCid->timeout = pCid->tm_etsi.t2_T12;
+ pCid->cid_state = dxs_cid_etsi_type2_before_data_xmit;
+ }
+ else
+ {
+ /* Go to timeout state */
+ pCid->timeout = pCid->tm_etsi.t2_T9;
+ pCid->cid_state = dxs_cid_sm_err_timeout;
+ }
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_etsi_type2_before_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_type2_before_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* call FSK transmitter */
+ DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
+ pCid->xmit_length);
+
+ pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
+ pCid->cid_state = dxs_cid_etsi_type2_data_xmit;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_etsi_type2_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_etsi_type2_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pCid->timeout = pCid->tm_etsi.t2_T13;
+ pCid->cid_state = dxs_cid_sm_fin;
+ return DXS_statusOk;
+}
+
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* TELCORDIA protocol */
+/* ========================================================================== */
+
+/* CID SM states - Telcordia */
+static int32_t dxs_cid_tc_init(void *arg);
+static int32_t dxs_cid_tc_alert(void *arg);
+static int32_t dxs_cid_tc_after_alert(void *arg);
+static int32_t dxs_cid_tc_data_xmit(void *arg);
+static int32_t dxs_cid_dtmf_off_tc(void *arg);
+static int32_t dxs_cid_dtmf_on_tc(void *arg);
+/**
+ dxs_cid_tc_init
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_init(void *arg)
+{
+ int32_t ret = DXS_statusOk;
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->as == DXS_CID_AS_OSI)
+ {
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
+ pCid->timeout = pCid->tm_tc.osi;
+ }
+ else if (pCid->as == DXS_CID_AS_TELCORDIA_DTMF)
+ {
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
+ pCid->timeout = pCid->tm_tc.T0dtmf;
+ pCid->cid_state = dxs_cid_tc_after_alert;
+ }
+ else /* DXS_CID_AS_NONE */
+ {
+ ret = DXS_SDD_LineModeSet(pCh,
+ DXS_LINE_FEED_RING_BURST ^ pCid->polarity_initial);
+ pCid->timeout = pCid->tm_tc.lring;
+ }
+ pCid->cid_state = dxs_cid_tc_alert;
+ return ret;
+}
+
+/**
+ Silent betwee 2 DTMF digits
+
+ \param arg
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_cid_dtmf_off_tc(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ /* stop DTMF tone */
+ dxs_tone_stop(pCh);
+ pCid->timeout = pCid->tm_tc.Tdtmf;
+ pCid->cid_state = dxs_cid_dtmf_on_tc;
+
+ return DXS_statusOk;
+}
+
+/**
+ Send next DTMF digit
+
+ \param arg
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_cid_dtmf_on_tc(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ uint8_t digi = pCid->xmit_buffer[pCid->xmit_buffer[1]];
+ if (pCid->xmit_length > pCid->xmit_buffer[1])
+ {
+ pCid->xmit_buffer[1] += 1;
+ /* send one digit */
+ dxs_tone_config(pCh, dtmf[digi].level1, dtmf[digi].level2, dtmf[digi].freq1, dtmf[digi].freq2, 0, 0);
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_tc.Tdtmf;
+ pCid->cid_state = dxs_cid_dtmf_off_tc;
+ }
+ else
+ {
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ /* all digits over. */
+ pCid->timeout = pCid->tm_tc.T2dtmf;
+ pCid->cid_state = dxs_cid_etsi_after_data_xmit;
+ }
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_alert
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_alert(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ if (pCid->as == DXS_CID_AS_OSI)
+ pCid->timeout = pCid->tm_tc.T1;
+ else /* DXS_CID_AS_NONE */
+ pCid->timeout = pCid->tm_tc.T0;
+ pCid->cid_state = dxs_cid_tc_after_alert;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_after_alert
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_after_alert(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->df == DXS_CID_DATA_FSK)
+ {
+ /* call FSK transmitter */
+ DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_BEL202, 1, pCid->xmit_buffer,
+ pCid->xmit_length);
+ pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
+ pCid->cid_state = dxs_cid_tc_data_xmit;
+ }
+ else if (pCid->df == DXS_CID_DATA_DTMF)
+ {
+ /* call DTMF transmitter */
+ dxs_cid_dtmf_on_tc((void *)pCh);
+ }
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pCid->timeout = pCid->tm_tc.T2;
+ pCid->cid_state = dxs_cid_sm_fin;
+ return DXS_statusOk;
+}
+
+
+/* CID type2 SM states - Telcordia */
+static int32_t dxs_cid_tc_type2_init(void *arg);
+static int32_t dxs_cid_tc_type2_osi_first(void *arg);
+static int32_t dxs_cid_tc_type2_silence(void *arg);
+static int32_t dxs_cid_tc_type2_sas(void *arg);
+static int32_t dxs_cid_tc_type2_as_transition(void *arg);
+static int32_t dxs_cid_tc_type2_cas(void *arg);
+static int32_t dxs_cid_tc_type2_wait_ack(void *arg);
+static int32_t dxs_cid_tc_type2_before_data_xmit(void *arg);
+static int32_t dxs_cid_tc_type2_data_xmit(void *arg);
+static int32_t dxs_cid_tc_type2_osi_last(void *arg);
+
+/**
+ dxs_cid_tc_type2_init
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_type2_init(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+
+
+ if (pCid->tm_tc.t2_osi)
+ {
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
+ pCid->timeout = pCid->tm_tc.t2_osi;
+ pCid->cid_state = dxs_cid_tc_type2_osi_first;
+ }
+ else
+ {
+ pCid->timeout = pCid->tm_tc.t2_W;
+ pCid->cid_state = dxs_cid_tc_type2_silence;
+ }
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_type2_osi_first
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_type2_osi_first(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pCid->hook_block = 1;
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ pCid->timeout = pCid->tm_tc.t2_W;
+ pCid->cid_state = dxs_cid_tc_type2_silence;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_type2_silence
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_type2_silence(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pCid->hook_block = 0;
+ if (pCid->tm_tc.t2_X)
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_tc.t2_X;
+ pCid->cid_state = dxs_cid_tc_type2_sas;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_type2_sas
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_type2_sas(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->tm_tc.t2_X)
+ dxs_tone_stop(pCh);
+ pCid->timeout = pCid->tm_tc.t2_X1;
+ pCid->cid_state = dxs_cid_tc_type2_as_transition;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_type2_as_transition
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_type2_as_transition(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_config(pCh, DXS_CID_DTAS_LEVEL1,
+ DXS_CID_DTAS_LEVEL2,
+ DXS_CID_DTAS_FREQ1,
+ DXS_CID_DTAS_FREQ2, 0, 0);
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_tc.t2_Y;
+ pCid->cid_state = dxs_cid_tc_type2_cas;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_type2_cas
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_type2_cas(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_stop(pCh);
+ pCid->timeout = pCid->tm_tc.t2_T1;
+ pCid->cid_state = dxs_cid_tc_type2_wait_ack;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_type2_wait_ack
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_type2_wait_ack(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->ack_detect)
+ {
+ pCid->ack_detect = 0;
+ pCid->timeout = pCid->tm_tc.t2_Q;
+ pCid->cid_state = dxs_cid_tc_type2_before_data_xmit;
+ }
+ else
+ {
+ /* Go to timeout state */
+ pCid->timeout = 0;
+ pCid->cid_state = dxs_cid_sm_err_timeout;
+ }
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_type2_before_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_type2_before_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* call FSK transmitter */
+ DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_BEL202, 1, pCid->xmit_buffer,
+ pCid->xmit_length);
+
+ pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
+ pCid->cid_state = dxs_cid_tc_type2_data_xmit;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_type2_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_type2_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->tm_tc.t2_osi)
+ {
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
+ pCid->timeout = pCid->tm_tc.t2_osi;
+ pCid->cid_state = dxs_cid_tc_type2_osi_last;
+ }
+ else
+ {
+ pCid->timeout = pCid->tm_tc.t2_S;
+ pCid->cid_state = dxs_cid_sm_fin;
+ }
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_tc_type2_osi_last
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_tc_type2_osi_last(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pCid->hook_block = 1;
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ pCid->timeout = pCid->tm_tc.t2_S;
+ pCid->cid_state = dxs_cid_sm_fin;
+ return DXS_statusOk;
+}
+
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* BT protocol */
+/* ========================================================================== */
+
+/* CID SM states - BT */
+static int32_t dxs_cid_bt_init(void *arg);
+static int32_t dxs_cid_bt_after_lr(void *arg);
+static int32_t dxs_cid_bt_dtas(void *arg);
+static int32_t dxs_cid_bt_after_alert(void *arg);
+static int32_t dxs_cid_bt_data_xmit(void *arg);
+static int32_t dxs_cid_bt_after_data_xmit(void *arg);
+
+/**
+ dxs_cid_bt_init
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_init(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_config(pCh, DXS_CID_DTAS_LEVEL1,
+ DXS_CID_DTAS_LEVEL2,
+ DXS_CID_DTAS_FREQ1,
+ DXS_CID_DTAS_FREQ2, 0, 0);
+
+ DXS_SDD_LineModeSet(pCh,
+ DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
+ pCid->timeout = pCid->tm_bt.T0;
+ pCid->cid_state = dxs_cid_bt_after_lr;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_bt_after_lr
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_after_lr(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_bt.dtas;
+ pCid->cid_state = dxs_cid_bt_dtas;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_bt_dtas
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_dtas(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_stop(pCh);
+ pCid->timeout = pCid->tm_bt.T1;
+ pCid->cid_state = dxs_cid_bt_after_alert;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_bt_after_alert
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_after_alert(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* call FSK transmitter */
+ DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
+ pCid->xmit_length);
+
+ pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
+ pCid->cid_state = dxs_cid_bt_data_xmit;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_bt_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pCid->timeout = pCid->tm_bt.T2;
+ pCid->cid_state = dxs_cid_bt_after_data_xmit;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_bt_after_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_after_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* restore line polarity */
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+
+ pCid->timeout = 0;
+ pCid->cid_state = dxs_cid_sm_fin;
+ return DXS_statusOk;
+}
+
+/* CID type2 SM states - BT */
+static int32_t dxs_cid_bt_type2_init(void *arg);
+static int32_t dxs_cid_bt_type2_silence(void *arg);
+static int32_t dxs_cid_bt_type2_as(void *arg);
+static int32_t dxs_cid_bt_type2_wait_ack(void *arg);
+static int32_t dxs_cid_bt_type2_before_data_xmit(void *arg);
+static int32_t dxs_cid_bt_type2_data_xmit(void *arg);
+
+/**
+ dxs_cid_bt_type2_init
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_type2_init(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_config(pCh, DXS_CID_DTAS_LEVEL1,
+ DXS_CID_DTAS_LEVEL2,
+ DXS_CID_DTAS_FREQ1,
+ DXS_CID_DTAS_FREQ2, 0, 0);
+
+ pCid->timeout = pCid->tm_bt.t2_T0;
+ pCid->cid_state = dxs_cid_bt_type2_silence;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_bt_type2_silence
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_type2_silence(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_bt.t2_dtas;
+ pCid->cid_state = dxs_cid_bt_type2_as;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_bt_type2_as
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_type2_as(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_stop(pCh);
+ pCid->timeout = pCid->tm_bt.t2_ack;
+ pCid->cid_state = dxs_cid_bt_type2_wait_ack;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_bt_type2_wait_ack
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_type2_wait_ack(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->ack_detect)
+ {
+ pCid->ack_detect = 0;
+ pCid->timeout = pCid->tm_bt.t2_T1;
+ pCid->cid_state = dxs_cid_bt_type2_before_data_xmit;
+ }
+ else
+ {
+ /* Go to timeout state */
+ pCid->timeout = 0;
+ pCid->cid_state = dxs_cid_sm_err_timeout;
+ }
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_bt_type2_before_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_type2_before_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* call FSK transmitter */
+ DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
+ pCid->xmit_length);
+
+ pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
+ pCid->cid_state = dxs_cid_bt_type2_data_xmit;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_bt_type2_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_bt_type2_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pCid->timeout = pCid->tm_bt.t2_T2;
+ pCid->cid_state = dxs_cid_sm_fin;
+ return DXS_statusOk;
+}
+
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* NTT protocol */
+/* ========================================================================== */
+
+/* CID SM states - NTT */
+static int32_t dxs_cid_ntt_init(void *arg);
+static int32_t dxs_cid_ntt_car_off(void *arg);
+static int32_t dxs_cid_ntt_car_on(void *arg);
+static int32_t dxs_cid_ntt_timeout(void *arg);
+static int32_t dxs_cid_ntt_after_offhook(void *arg);
+static int32_t dxs_cid_ntt_data_xmit(void *arg);
+static int32_t dxs_cid_ntt_wait_onhook(void *arg);
+static int32_t dxs_cid_ntt_after_onhook(void *arg);
+
+/**
+ dxs_cid_ntt_init
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_init(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* set line feeding modes and proceed with SM */
+ DXS_SDD_LineModeSet(pCh,
+ DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
+ pCid->ntt_timeout = pCid->tm_ntt.T1;
+ pCid->timeout = pCid->tm_ntt.T0;
+ pCid->cid_state = dxs_cid_ntt_car_off;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_car_off
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_car_off(void *arg)
+{
+ int32_t ret = DXS_statusOk;
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->hook_state == DXS_CID_HOOK_STATE_OFFHOOK)
+ {
+ pCid->hook_state_exp = DXS_CID_HOOK_STATE_OFFHOOK;
+ pCid->cid_state = dxs_cid_ntt_after_offhook;
+ pCid->timeout = pCid->tm_ntt.T2;
+ }
+ else
+ {
+ pCid->hook_state_exp =
+ (DXS_CID_HOOK_STATE_OFFHOOK | DXS_CID_HOOK_STATE_ONHOOK);
+ if (pCid->ntt_timeout <= pCid->tm_ntt.CARon)
+ {
+ /* Timeout - terminate CID */
+ pCid->timeout = 0;
+ pCid->cid_state = dxs_cid_ntt_timeout;
+ }
+ else
+ {
+ ret = DXS_SDD_LineModeSet(pCh,
+ DXS_LINE_FEED_RINGING_REVPOL ^ pCid->polarity_initial);
+ pCid->ntt_timeout -= pCid->timeout;
+ pCid->timeout = pCid->tm_ntt.CARon;
+ pCid->cid_state = dxs_cid_ntt_car_on;
+ }
+ }
+ return ret;
+}
+
+/**
+ dxs_cid_ntt_car_on
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_car_on(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->hook_state == DXS_CID_HOOK_STATE_OFFHOOK)
+ {
+ pCid->hook_state_exp = DXS_CID_HOOK_STATE_OFFHOOK;
+ pCid->cid_state = dxs_cid_ntt_after_offhook;
+ pCid->timeout = pCid->tm_ntt.T2;
+ }
+ else
+ {
+ DXS_SDD_LineModeSet(pCh,
+ DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
+ if (pCid->ntt_timeout <= pCid->tm_ntt.CARoff)
+ {
+ /* Timeout - terminate CID */
+ pCid->timeout = 0;
+ pCid->cid_state = dxs_cid_ntt_timeout;
+ }
+ else
+ {
+ pCid->ntt_timeout -= pCid->timeout;
+ pCid->timeout = pCid->tm_ntt.CARoff;
+ pCid->cid_state = dxs_cid_ntt_car_off;
+ }
+ }
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_timeout
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_timeout(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+
+ pCid->timeout = 0;
+ pCid->cid_state = dxs_cid_sm_err_timeout;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_after_offhook
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_after_offhook(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
+ pCid->xmit_length);
+ pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
+ pCid->cid_state = dxs_cid_ntt_data_xmit;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* set any expected hook state to be able to report timeout if it occurs */
+ pCid->hook_state_exp =
+ (DXS_CID_HOOK_STATE_OFFHOOK | DXS_CID_HOOK_STATE_ONHOOK);
+ pCid->timeout = pCid->tm_ntt.T3;
+ pCid->cid_state = dxs_cid_ntt_wait_onhook;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_wait_onhook
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_wait_onhook(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pCid->hook_state == DXS_CID_HOOK_STATE_ONHOOK)
+ {
+ pCid->timeout = pCid->tm_ntt.T4;
+ pCid->cid_state = dxs_cid_ntt_after_onhook;
+ }
+ else
+ {
+ /* Report previous off-hook event which was hidden by CID NTT */
+#ifndef DXS_FEAT_HSM
+ DXS_Event_t dxs_event = {0};
+
+ dxs_event.dev = pCh->pParent->nDevNum;
+ dxs_event.ch = pCh->nCh;
+ dxs_event.id = DXS_EVENT_FXS_OFFHOOK;
+ DXS_EventDispatch(pCh->pParent, &dxs_event);
+#else
+ DXS_Dial_HookEvent(pCh, 1, pCid->hook_timestamp);
+#endif
+ /* Go to timeout state */
+ pCid->timeout = 0;
+ pCid->cid_state = dxs_cid_ntt_timeout;
+ }
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_after_onhook
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_after_onhook(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* NTT defines that line polarity should be restored after real off-hook,
+ however we restore polarity right here so the demo application can switch to
+ RING_BURST without errors. This is the only purpose of this state -
+ restore polarity, otherwise this state can be removed. */
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ pCid->timeout = 0;
+ pCid->cid_state = dxs_cid_sm_fin;
+ return DXS_statusOk;
+}
+
+/* CID type2 SM states - NTT */
+static int32_t dxs_cid_ntt_type2_init(void *arg);
+static int32_t dxs_cid_ntt_type2_silence(void *arg);
+static int32_t dxs_cid_ntt_type2_as_first(void *arg);
+static int32_t dxs_cid_ntt_type2_as_pause(void *arg);
+static int32_t dxs_cid_ntt_type2_as_second(void *arg);
+static int32_t dxs_cid_ntt_type2_before_data_xmit(void *arg);
+static int32_t dxs_cid_ntt_type2_data_xmit(void *arg);
+
+/**
+ dxs_cid_ntt_type2_init
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_type2_init(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pCid->timeout = pCid->tm_ntt.t2_T0;
+ pCid->cid_state = dxs_cid_ntt_type2_silence;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_type2_silence
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_type2_silence(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_config(pCh, DXS_CID_NTT_TYPE2_ATONE_LEVEL1,
+ DXS_CID_NTT_TYPE2_ATONE_LEVEL2,
+ DXS_CID_NTT_TYPE2_ATONE_FREQ1,
+ DXS_CID_NTT_TYPE2_ATONE_FREQ2, 0, 0);
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_ntt.t2_as_first;
+ pCid->cid_state = dxs_cid_ntt_type2_as_first;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_type2_as_first
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_type2_as_first(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_stop(pCh);
+ pCid->timeout = pCid->tm_ntt.t2_as_pause;
+ pCid->cid_state = dxs_cid_ntt_type2_as_pause;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_type2_as_pause
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_type2_as_pause(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_config(pCh, DXS_CID_NTT_TYPE2_ATONE_LEVEL1,
+ DXS_CID_NTT_TYPE2_ATONE_LEVEL2,
+ DXS_CID_NTT_TYPE2_ATONE_FREQ3,
+ DXS_CID_NTT_TYPE2_ATONE_FREQ2, 0, 0);
+ dxs_tone_start(pCh);
+ pCid->timeout = pCid->tm_ntt.t2_as_second;
+ pCid->cid_state = dxs_cid_ntt_type2_as_second;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_type2_as_second
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_type2_as_second(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ dxs_tone_stop(pCh);
+ pCid->timeout = pCid->tm_ntt.t2_T1;
+ pCid->cid_state = dxs_cid_ntt_type2_before_data_xmit;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_type2_before_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_type2_before_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* call FSK transmitter */
+ DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
+ pCid->xmit_length);
+
+ pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
+ pCid->cid_state = dxs_cid_ntt_type2_data_xmit;
+ return DXS_statusOk;
+}
+
+/**
+ dxs_cid_ntt_type2_data_xmit
+
+ \param arg
+
+ \return
+ - none
+*/
+static int32_t dxs_cid_ntt_type2_data_xmit(void *arg)
+{
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pCid->timeout = pCid->tm_ntt.t2_T2;
+ pCid->cid_state = dxs_cid_sm_fin;
+ return DXS_statusOk;
+}
+
+/* ========================================================================== */
+
+/**
+ CID state machine execution thread
+
+ \param arg
+
+ \return
+ - none
+*/
+static void *dxs_cid_thread (void *arg)
+{
+ int32_t err;
+ DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ sem_init(&pCid->sema, 0, 0);
+
+ pCid->complete = 0;
+ pCid->ret = DXS_statusOk;
+
+ while (!pCid->complete)
+ {
+ /* check hook state */
+ if (!(pCid->hook_state & pCid->hook_state_exp))
+ pCid->cid_state = dxs_cid_sm_err_hook;
+
+ /* action */
+ if ((err = pCid->cid_state((void *)pCh)) != DXS_statusOk)
+ {
+ pCid->complete = 1;
+ pCid->ret = err;
+
+ /* inform application on this particular error */
+ if (err == DXS_statusDcDcRingCapsExceeded)
+ {
+ DXS_Event_t dxs_event =
+ {
+ .dev = pCh->pParent->nDevNum,
+ .ch = pCh->nCh,
+ .id = DXS_EVENT_CID_SEQ_ERROR,
+ .data.cid_err = DXS_EVENT_CID_HW_RING_LIMIT
+ };
+ DXS_EventDispatch(pCh->pParent, &dxs_event);
+ }
+
+ /* Restore active line mode */
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ /* Unmute channel */
+ if (pCid->need_unmute)
+ {
+ if (dxs_pcm_ch_mute(pCh, 0) == DXS_statusOk)
+ pCid->need_unmute = 0;
+ }
+ pthread_detach(pCid->thrd);
+ break;
+ }
+
+ /* waiting */
+ dxs_cid_wait(pCid);
+ }
+ sem_destroy(&pCid->sema);
+ pthread_exit((void *)(&pCid->ret));
+}
+
+/**
+ Initialize CID context
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param std - CID standard \ref DXS_CID_Std_t
+ \param as - alert signal \ref DXS_CID_AS_t
+ \param fmt - data format \ref DXS_CID_DATA_FMT_t
+ \param dtmf_ack_idx - dtmf index for acknowledgment (type2 only)
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_Init(DXS_CHANNEL_t *pCh, DXS_CID_Std_t std, DXS_CID_AS_t as,
+ DXS_CID_DATA_FMT_t fmt, uint8_t dtmf_ack_idx)
+{
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* Block if CID SM is running already */
+ if ((pCid->magic == DXS_CID_CTX_MAGIC) && (!pCid->complete))
+ {
+ DXS_RETURN(DXS_statusCidInProgress);
+ }
+
+ switch (std)
+ {
+ case DXS_CID_STD_BT:
+ {
+ if (as != DXS_CID_AS_LR_DTAS)
+ {
+ DXS_RETURN(DXS_statusCidInvalidAlertSignal);
+ }
+ pCid->len_check = dxs_cid_param_length_check_bt;
+ break;
+ }
+
+ case DXS_CID_STD_NTT:
+ {
+ if (as != DXS_CID_AS_CAR)
+ {
+ DXS_RETURN(DXS_statusCidInvalidAlertSignal);
+ }
+ pCid->len_check = dxs_cid_param_length_check_ntt;
+ break;
+ }
+
+ case DXS_CID_STD_ETSI:
+ {
+ if ((as == DXS_CID_AS_CAR) || (as == DXS_CID_AS_OSI))
+ {
+ DXS_RETURN(DXS_statusCidInvalidAlertSignal);
+ }
+ pCid->len_check = dxs_cid_param_length_check_etsi;
+ break;
+ }
+
+ case DXS_CID_STD_TELCORDIA:
+ {
+ if ((as != DXS_CID_AS_NONE) && (as != DXS_CID_AS_OSI))
+ {
+ DXS_RETURN(DXS_statusCidInvalidAlertSignal);
+ }
+ pCid->len_check = dxs_cid_param_length_check_tc;
+ break;
+ }
+
+ default:
+ {
+ DXS_RETURN(DXS_statusCidStdNotSupported);
+ }
+ }
+
+ switch (fmt)
+ {
+ case DXS_CID_DATA_FSK:
+ case DXS_CID_DATA_DTMF:
+ break;
+
+ default:
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ }
+
+ /* refresh message containers */
+ dxs_cid_msg_clearall(pCid);
+
+ pCid->magic = DXS_CID_CTX_MAGIC;
+ pCid->complete = 1;
+ pCid->std = std;
+ pCid->as = as;
+ pCid->df = fmt;
+ pCid->dtmf_ack_idx = dtmf_ack_idx;
+
+ /* default timers for ETSI */
+ pCid->tm_etsi.lring = DXS_CID_ETSI_LONG_RING_MS;
+ pCid->tm_etsi.dtas = DXS_CID_ETSI_DTAS_MS;
+ pCid->tm_etsi.rpas = DXS_CID_ETSI_RPAS_MS;
+ pCid->tm_etsi.T0 = DXS_CID_ETSI_T0_DEFAULT;
+ pCid->tm_etsi.T1 = DXS_CID_ETSI_T1_DEFAULT;
+ pCid->tm_etsi.T2 = DXS_CID_ETSI_T2_DEFAULT;
+ pCid->tm_etsi.T3 = DXS_CID_ETSI_T3_DEFAULT;
+ pCid->tm_etsi.T4 = DXS_CID_ETSI_T4_DEFAULT;
+ pCid->tm_etsi.T5 = DXS_CID_ETSI_T5_DEFAULT;
+ pCid->tm_etsi.T6 = DXS_CID_ETSI_T6_DEFAULT;
+ pCid->tm_etsi.t2_dtas = DXS_CID_ETSI_TYPE2_DTAS_MS;
+ pCid->tm_etsi.t2_T14 = DXS_CID_ETSI_TYPE2_T14_DEFAULT;
+ pCid->tm_etsi.t2_T10 = DXS_CID_ETSI_TYPE2_T10_DEFAULT;
+ pCid->tm_etsi.t2_T12 = DXS_CID_ETSI_TYPE2_T12_DEFAULT;
+ pCid->tm_etsi.t2_T13 = DXS_CID_ETSI_TYPE2_T13_DEFAULT;
+ pCid->tm_etsi.t2_T9 = DXS_CID_ETSI_TYPE2_T9_DEFAULT;
+ pCid->tm_etsi.T0dtmf = DXS_CID_ETSI_T0dtmf_DEFAULT;
+ pCid->tm_etsi.Tdtmf = DXS_CID_ETSI_Tdtmf_DEFAULT;
+ pCid->tm_etsi.T2dtmf = DXS_CID_ETSI_T2dtmf_DEFAULT;
+
+ /* default timers for Telcordia */
+ pCid->tm_tc.lring = DXS_CID_TELCORDIA_LONG_RING_MS;
+ pCid->tm_tc.osi = DXS_CID_TELCORDIA_OSI_MS;
+ pCid->tm_tc.T0 = DXS_CID_TELCORDIA_T0_DEFAULT;
+ pCid->tm_tc.T1 = DXS_CID_TELCORDIA_T1_DEFAULT;
+ pCid->tm_tc.T2 = DXS_CID_TELCORDIA_T2_DEFAULT;
+ pCid->tm_tc.t2_osi = DXS_CID_TELCORDIA_TYPE2_OSI_MS;
+ pCid->tm_tc.t2_W = DXS_CID_TELCORDIA_TYPE2_W_MS;
+ pCid->tm_tc.t2_X = DXS_CID_TELCORDIA_TYPE2_X_MS;
+ pCid->tm_tc.t2_X1 = DXS_CID_TELCORDIA_TYPE2_X1_MS;
+ pCid->tm_tc.t2_Y = DXS_CID_TELCORDIA_TYPE2_Y_MS;
+ pCid->tm_tc.t2_T1 = DXS_CID_TELCORDIA_TYPE2_T1_MS;
+ pCid->tm_tc.t2_Q = DXS_CID_TELCORDIA_TYPE2_Q_MS;
+ pCid->tm_tc.t2_S = DXS_CID_TELCORDIA_TYPE2_S_MS;
+ pCid->tm_tc.T0dtmf = DXS_CID_TELCORDIA_T0dtmf_DEFAULT;
+ pCid->tm_tc.Tdtmf = DXS_CID_TELCORDIA_Tdtmf_DEFAULT;
+ pCid->tm_tc.T2dtmf = DXS_CID_TELCORDIA_T2dtmf_DEFAULT;
+
+ /* default timers for BT */
+ pCid->tm_bt.dtas = DXS_CID_BT_DTAS_MS;
+ pCid->tm_bt.T0 = DXS_CID_BT_T0_DEFAULT;
+ pCid->tm_bt.T1 = DXS_CID_BT_T1_DEFAULT;
+ pCid->tm_bt.T2 = DXS_CID_BT_T2_DEFAULT;
+ pCid->tm_bt.t2_dtas = DXS_CID_BT_TYPE2_DTAS_MS;
+ pCid->tm_bt.t2_ack = DXS_CID_BT_TYPE2_ACK_MS;
+ pCid->tm_bt.t2_T0 = DXS_CID_BT_TYPE2_T0_DEFAULT;
+ pCid->tm_bt.t2_T1 = DXS_CID_BT_TYPE2_T1_DEFAULT;
+ pCid->tm_bt.t2_T2 = DXS_CID_BT_TYPE2_T2_DEFAULT;
+
+ /* default timers for NTT */
+ pCid->tm_ntt.CARon = DXS_CID_NTT_CARON_MS;
+ pCid->tm_ntt.CARoff = DXS_CID_NTT_CAROFF_MS;
+ pCid->tm_ntt.T0 = DXS_CID_NTT_T0_DEFAULT;
+ pCid->tm_ntt.T1 = DXS_CID_NTT_T1_DEFAULT;
+ pCid->tm_ntt.T2 = DXS_CID_NTT_T2_DEFAULT;
+ pCid->tm_ntt.T3 = DXS_CID_NTT_T3_DEFAULT;
+ pCid->tm_ntt.T4 = DXS_CID_NTT_T4_DEFAULT;
+ pCid->tm_ntt.t2_as_first = DXS_CID_NTT_TYPE2_AS1_MS;
+ pCid->tm_ntt.t2_as_pause = DXS_CID_NTT_TYPE2_AS_PAUSE_MS;
+ pCid->tm_ntt.t2_as_second = DXS_CID_NTT_TYPE2_AS2_MS;
+ pCid->tm_ntt.t2_T0 = DXS_CID_NTT_TYPE2_T0_DEFAULT;
+ pCid->tm_ntt.t2_T1 = DXS_CID_NTT_TYPE2_T1_DEFAULT;
+ pCid->tm_ntt.t2_T2 = DXS_CID_NTT_TYPE2_T2_DEFAULT;
+
+ return DXS_statusOk;
+}
+
+/**
+ Timers configuration
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param std - CID standard \ref DXS_CID_Std_t
+ \param pTimers - timer configuration \ref DXS_CID_Timers_t
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_TimerConfig(DXS_CHANNEL_t *pCh,
+ DXS_CID_Std_t std, DXS_CID_Timers_t *pTimers)
+{
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* check if pCid is initialized */
+ if (pCid->magic != DXS_CID_CTX_MAGIC)
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (std == DXS_CID_STD_ETSI)
+ {
+ pCid->tm_etsi.lring = pTimers->etsi.lring;
+ pCid->tm_etsi.dtas = pTimers->etsi.dtas;
+ pCid->tm_etsi.rpas = pTimers->etsi.rpas;
+ pCid->tm_etsi.T0 = pTimers->etsi.T0;
+ pCid->tm_etsi.T1 = pTimers->etsi.T1;
+ pCid->tm_etsi.T2 = pTimers->etsi.T2;
+ pCid->tm_etsi.T3 = pTimers->etsi.T3;
+ pCid->tm_etsi.T4 = pTimers->etsi.T4;
+ pCid->tm_etsi.T5 = pTimers->etsi.T5;
+ pCid->tm_etsi.T6 = pTimers->etsi.T6;
+ pCid->tm_etsi.t2_dtas = pTimers->etsi.t2_dtas;
+ pCid->tm_etsi.t2_T14 = pTimers->etsi.t2_T14;
+ pCid->tm_etsi.t2_T10 = pTimers->etsi.t2_T10;
+ pCid->tm_etsi.t2_T12 = pTimers->etsi.t2_T12;
+ pCid->tm_etsi.t2_T13 = pTimers->etsi.t2_T13;
+ pCid->tm_etsi.t2_T9 = pTimers->etsi.t2_T9;
+ }
+ else if (std == DXS_CID_STD_TELCORDIA)
+ {
+ pCid->tm_tc.lring = pTimers->tc.lring;
+ pCid->tm_tc.osi = pTimers->tc.osi;
+ pCid->tm_tc.T0 = pTimers->tc.T0;
+ pCid->tm_tc.T1 = pTimers->tc.T1;
+ pCid->tm_tc.T2 = pTimers->tc.T2;
+ pCid->tm_tc.t2_osi = pTimers->tc.t2_osi;
+ pCid->tm_tc.t2_W = pTimers->tc.t2_W;
+ pCid->tm_tc.t2_X = pTimers->tc.t2_X;
+ pCid->tm_tc.t2_X1 = pTimers->tc.t2_X1;
+ pCid->tm_tc.t2_Y = pTimers->tc.t2_Y;
+ pCid->tm_tc.t2_T1 = pTimers->tc.t2_T1;
+ pCid->tm_tc.t2_Q = pTimers->tc.t2_Q;
+ pCid->tm_tc.t2_S = pTimers->tc.t2_S;
+ }
+ else if (std == DXS_CID_STD_BT)
+ {
+ pCid->tm_bt.dtas = pTimers->bt.dtas;
+ pCid->tm_bt.T0 = pTimers->bt.T0;
+ pCid->tm_bt.T1 = pTimers->bt.T1;
+ pCid->tm_bt.T2 = pTimers->bt.T2;
+ pCid->tm_bt.t2_dtas = pTimers->bt.t2_dtas;
+ pCid->tm_bt.t2_ack = pTimers->bt.t2_ack;
+ pCid->tm_bt.t2_T0 = pTimers->bt.t2_T0;
+ pCid->tm_bt.t2_T1 = pTimers->bt.t2_T1;
+ pCid->tm_bt.t2_T2 = pTimers->bt.t2_T2;
+ }
+ else if (std == DXS_CID_STD_NTT)
+ {
+ pCid->tm_ntt.CARon = pTimers->ntt.CARon;
+ pCid->tm_ntt.CARoff = pTimers->ntt.CARoff;
+ pCid->tm_ntt.T0 = pTimers->ntt.T0;
+ pCid->tm_ntt.T1 = pTimers->ntt.T1;
+ pCid->tm_ntt.T2 = pTimers->ntt.T2;
+ pCid->tm_ntt.T3 = pTimers->ntt.T3;
+ pCid->tm_ntt.T4 = pTimers->ntt.T4;
+ pCid->tm_ntt.t2_as_first = pTimers->ntt.t2_as_first;
+ pCid->tm_ntt.t2_as_pause = pTimers->ntt.t2_as_pause;
+ pCid->tm_ntt.t2_as_second = pTimers->ntt.t2_as_second;
+ pCid->tm_ntt.t2_T0 = pTimers->ntt.t2_T0;
+ pCid->tm_ntt.t2_T1 = pTimers->ntt.t2_T1;
+ pCid->tm_ntt.t2_T2 = pTimers->ntt.t2_T2;
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Update CId message
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param msg_type - message type \ref DXS_CID_MsgType_t
+ \param param - message parameter \ref DXS_CID_MsgParam_t
+ \param pData - message parameter data
+ \param length - message parameter data length
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_MsgUpdate(DXS_CHANNEL_t *pCh, DXS_CID_MsgType_t msg_type,
+ DXS_CID_MsgParam_t param, char *pData, uint8_t length)
+{
+ uint32_t i, found = 0;
+ dxs_cid_message_t *pMsg, *p;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* check if pCid is initialized */
+ if (pCid->magic != DXS_CID_CTX_MAGIC)
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ pMsg = dxs_cid_message_get(pCid, msg_type);
+
+ p = pMsg;
+
+ /* check if message parameter already exists */
+ while (p != NULL)
+ {
+ if (p->type == param)
+ {
+ found = 1;
+ break;
+ }
+ p = p->next;
+ }
+
+ if (found)
+ {
+ if (p->len != length)
+ {
+ p->data = realloc(p->data, length);
+ p->len = length;
+ }
+
+ if (pData != NULL)
+ {
+ for (i=0; i<length; i++)
+ {
+ if (p->data)
+ p->data[i] = *pData++;
+ }
+ }
+ }
+ else
+ {
+ dxs_cid_message_t *pMsgElem;
+ uint8_t updated_len = pCid->len_check(param, length);
+
+ /* allocate memory for the new element */
+ pMsgElem = calloc(1, sizeof(*pMsgElem));
+ if (pMsgElem == NULL)
+ return DXS_statusError;
+ pMsgElem->type = param;
+ /* update the length for malloc */
+ pMsgElem->data = malloc(updated_len);
+ if (pMsgElem->data == NULL)
+ {
+ free(pMsgElem);
+ return DXS_statusError;
+ }
+ if (pData != NULL)
+ {
+ for (i=0; i<updated_len; i++)
+ pMsgElem->data[i] = *pData++;
+ }
+ pMsgElem->len = updated_len;
+ pMsgElem->next = NULL;
+ /* add the new element to the bottom */
+ if (pMsg == NULL)
+ {
+ dxs_cid_message_set(pCid, msg_type, pMsgElem);
+ }
+ else
+ {
+ p = pMsg;
+
+ while (p->next != NULL)
+ p = p->next;
+
+ p->next = pMsgElem;
+ }
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Clean all messages in CID context
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_MsgCleanup(DXS_CHANNEL_t *pCh)
+{
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* check if pCid is initialized */
+ if (pCid->magic != DXS_CID_CTX_MAGIC)
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* vipe all configured messages (if any) */
+ dxs_cid_msg_clearall(pCid);
+
+ return DXS_statusOk;
+}
+
+/**
+ Start CID TypeI message playout
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param msg_type - type of message to play \ref DXS_CID_MsgType_t
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_TypeI_Play(DXS_CHANNEL_t *pCh, DXS_CID_MsgType_t msg_type,
+ uint8_t calling_instance)
+{
+ int32_t ret, line_mode = 0;
+ pthread_attr_t cid_thread_attr;
+ struct sched_param cid_thread_param;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ uint16_t unMarkBits, unSeizureBits;
+
+ if (pCid->magic != DXS_CID_CTX_MAGIC)
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (!pCid->complete)
+ {
+ DXS_RETURN(DXS_statusCidInProgress);
+ }
+
+ pCid->calling_instance = calling_instance;
+
+ switch (pCid->std)
+ {
+ case DXS_CID_STD_BT:
+ {
+ if (pCid->as != DXS_CID_AS_LR_DTAS)
+ {
+ DXS_RETURN(DXS_statusCidInvalidAlertSignal);
+ }
+ unMarkBits = DXS_CID_FSK_BT_MARK_DEFAULT;
+ unSeizureBits = DXS_CID_FSK_SEIZURE_DEFAULT;
+ pCid->cid_state = dxs_cid_bt_init;
+ break;
+ }
+
+ case DXS_CID_STD_NTT:
+ {
+ if (pCid->as != DXS_CID_AS_CAR)
+ {
+ DXS_RETURN(DXS_statusCidInvalidAlertSignal);
+ }
+ unMarkBits = DXS_CID_FSK_MARK_DEFAULT;
+ unSeizureBits = 0;
+ pCid->cid_state = dxs_cid_ntt_init;
+ break;
+ }
+
+ case DXS_CID_STD_ETSI:
+ {
+ if ((pCid->as == DXS_CID_AS_CAR) || (pCid->as == DXS_CID_AS_OSI))
+ {
+ DXS_RETURN(DXS_statusCidInvalidAlertSignal);
+ }
+ unMarkBits = DXS_CID_FSK_MARK_DEFAULT;
+ unSeizureBits = DXS_CID_FSK_SEIZURE_DEFAULT;
+ if (pCid->calling_instance == DXS_CID_CALL_FROM_RING_SM &&
+ pCid->as == DXS_CID_AS_NONE)
+ {
+ pCid->cid_state = dxs_cid_etsi_ring;
+ }
+ else
+ {
+ pCid->cid_state = dxs_cid_etsi_init;
+ }
+ break;
+ }
+
+ case DXS_CID_STD_TELCORDIA:
+ {
+ if ((pCid->as != DXS_CID_AS_NONE) && (pCid->as != DXS_CID_AS_OSI))
+ {
+ DXS_RETURN(DXS_statusCidInvalidAlertSignal);
+ }
+ unMarkBits = DXS_CID_FSK_MARK_DEFAULT;
+ unSeizureBits = DXS_CID_FSK_SEIZURE_DEFAULT;
+
+ if (pCid->calling_instance == DXS_CID_CALL_FROM_RING_SM &&
+ pCid->as == DXS_CID_AS_NONE)
+ {
+ pCid->cid_state = dxs_cid_tc_alert;
+ }
+ else
+ {
+ pCid->cid_state = dxs_cid_tc_init;
+ }
+ break;
+ }
+
+ default:
+ {
+ DXS_RETURN(DXS_statusCidStdNotSupported);
+ }
+ }
+
+ /* set expected hook state */
+ pCid->hook_state_exp = DXS_CID_HOOK_STATE_ONHOOK;
+ /* do not block off-hook events */
+ pCid->hook_block = 0;
+
+ /* prepare message for transmission */
+ if (pCid->df == DXS_CID_DATA_FSK)
+ {
+ if (pCid->std == DXS_CID_STD_NTT)
+ ret = dxs_cid_fsk_buffer_prepare_ntt(pCid, msg_type);
+ else
+ ret = dxs_cid_fsk_buffer_prepare(pCid, msg_type);
+ if (ret)
+ {
+ DXS_RETURN(ret);
+ }
+ DXS_FSK_Configure(pCh, DXS_CID_FSK_LEVEL_DEFAULT,
+ unSeizureBits, unMarkBits);
+ }
+ else
+ {
+ dxs_cid_dtmf_buffer_prepare(pCid, msg_type);
+ }
+
+ /* Verify line mode and store the polarity */
+ ret = DXS_SDD_LineModeGet(pCh, &line_mode);
+ if (ret == DXS_statusOk)
+ {
+ switch (line_mode)
+ {
+ case DXS_LINE_FEED_STANDBY:
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE);
+ pCid->polarity_initial = DXS_CID_LINE_MODE_POLARITY_FLAG_NORMAL;
+ break;
+ case DXS_LINE_FEED_ACTIVE:
+ pCid->polarity_initial = DXS_CID_LINE_MODE_POLARITY_FLAG_NORMAL;
+ break;
+ case DXS_LINE_FEED_ACTIVE_REVPOL:
+ pCid->polarity_initial = DXS_CID_LINE_MODE_POLARITY_FLAG_REVERSED;
+ break;
+ default:
+ /* Incorrect line feed mode */
+ DXS_RETURN(DXS_statusCidInvalidLineMode);
+ break;
+ }
+
+ /* TODO: verify that a telephone is on-hook */
+ /* Set on-hook */
+ pCid->hook_state = DXS_CID_HOOK_STATE_ONHOOK;
+
+ /* Set highest priority for CID thread handling */
+ pthread_attr_init(&cid_thread_attr);
+
+ cid_thread_param.sched_priority = sched_get_priority_max(SCHED_RR);
+ pthread_attr_setschedparam(&cid_thread_attr, &cid_thread_param);
+
+ pthread_attr_setschedpolicy(&cid_thread_attr, SCHED_RR);
+
+ /* roll it */
+ if (pthread_create(&pCid->thrd, &cid_thread_attr, dxs_cid_thread, (void *)pCh))
+ {
+ pthread_attr_destroy(&cid_thread_attr);
+ DXS_RETURN(DXS_statusThreadCreatError);
+ }
+ pthread_attr_destroy(&cid_thread_attr);
+ }
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Start CID TypeII message playout
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param msg_type - type of message to play \ref DXS_CID_MsgType_t
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_TypeII_Play(DXS_CHANNEL_t *pCh, DXS_CID_MsgType_t msg_type)
+{
+ int32_t ret, line_mode = 0;
+ pthread_attr_t cid_thread_attr;
+ struct sched_param cid_thread_param;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ uint16_t unMarkBits, unSeizureBits;
+
+ if (pCid->magic != DXS_CID_CTX_MAGIC)
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (!pCid->complete)
+ {
+ DXS_RETURN(DXS_statusCidInProgress);
+ }
+
+ switch (pCid->std)
+ {
+ case DXS_CID_STD_BT:
+ {
+ unMarkBits = DXS_CID_FSK_BT_MARK_DEFAULT;
+ unSeizureBits = 0;
+ pCid->cid_state = dxs_cid_bt_type2_init;
+ break;
+ }
+
+ case DXS_CID_STD_NTT:
+ {
+ unMarkBits = DXS_CID_FSK_MARK_DEFAULT;
+ unSeizureBits = 0;
+ pCid->cid_state = dxs_cid_ntt_type2_init;
+ break;
+ }
+
+ case DXS_CID_STD_ETSI:
+ {
+ unMarkBits = DXS_CID_FSK_ETSI_TYPE2_MARK_DEFAULT;
+ unSeizureBits = 0;
+ pCid->cid_state = dxs_cid_etsi_type2_init;
+ break;
+ }
+
+ case DXS_CID_STD_TELCORDIA:
+ {
+ unMarkBits = DXS_CID_FSK_MARK_DEFAULT;
+ unSeizureBits = 0;
+ pCid->cid_state = dxs_cid_tc_type2_init;
+ break;
+ }
+
+ default:
+ {
+ DXS_RETURN(DXS_statusCidStdNotSupported);
+ }
+ }
+
+ /* set expected hook state */
+ pCid->hook_state_exp = DXS_CID_HOOK_STATE_OFFHOOK;
+ /* clear ACK detection */
+ pCid->ack_detect = 0;
+ /* do not block off-hook events */
+ pCid->hook_block = 0;
+
+ /* prepare message for transmission */
+ if (pCid->df == DXS_CID_DATA_FSK)
+ {
+ if (pCid->std == DXS_CID_STD_NTT)
+ ret = dxs_cid_fsk_buffer_prepare_ntt(pCid, msg_type);
+ else
+ ret = dxs_cid_fsk_buffer_prepare(pCid, msg_type);
+ if (ret)
+ {
+ DXS_RETURN(ret);
+ }
+ DXS_FSK_Configure(pCh, DXS_CID_FSK_LEVEL_DEFAULT,
+ unSeizureBits, unMarkBits);
+ }
+ else
+ {
+ dxs_cid_dtmf_buffer_prepare(pCid, msg_type);
+ }
+
+ /* Verify line mode and store the polarity */
+ ret = DXS_SDD_LineModeGet(pCh, &line_mode);
+ if (ret == DXS_statusOk)
+ {
+ switch (line_mode)
+ {
+ case DXS_LINE_FEED_ACTIVE:
+ pCid->polarity_initial = DXS_CID_LINE_MODE_POLARITY_FLAG_NORMAL;
+ break;
+ case DXS_LINE_FEED_ACTIVE_REVPOL:
+ pCid->polarity_initial = DXS_CID_LINE_MODE_POLARITY_FLAG_REVERSED;
+ break;
+ default:
+ /* Incorrect line feed mode */
+ DXS_RETURN(DXS_statusCidInvalidLineMode);
+ break;
+ }
+
+ /* TODO: verify that a telephone is off-hook */
+ /* Set off-hook flag */
+ pCid->hook_state = DXS_CID_HOOK_STATE_OFFHOOK;
+
+ /* Mute PCM channel */
+ if (dxs_pcm_ch_mute(pCh, 1) == DXS_statusOk)
+ pCid->need_unmute = 1;
+
+ /* Set highest priority for CID thread handling */
+ pthread_attr_init(&cid_thread_attr);
+
+ cid_thread_param.sched_priority = sched_get_priority_max(SCHED_RR);
+ pthread_attr_setschedparam(&cid_thread_attr, &cid_thread_param);
+
+ pthread_attr_setschedpolicy(&cid_thread_attr, SCHED_RR);
+
+ /* roll it */
+ if (pthread_create(&pCid->thrd, &cid_thread_attr, dxs_cid_thread, (void *)pCh))
+ {
+ pthread_attr_destroy(&cid_thread_attr);
+ DXS_RETURN(DXS_statusThreadCreatError);
+ }
+ pthread_attr_destroy(&cid_thread_attr);
+ }
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Stop CID state machine
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_Stop(DXS_CHANNEL_t *pCh)
+{
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ void *ret_status;
+ int32_t err;
+
+ if (!pCid->complete)
+ {
+ pCid->complete = 1;
+
+ /* attempt to terminate all possible states of CID sequence */
+ if (pCid->cid_state == dxs_cid_ntt_car_on)
+ {
+ /* Special case, need to stop ringing with the corresponded polarity */
+ DXS_SDD_LineModeSet(pCh,
+ DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
+ }
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ DXS_CID_FSK_Stop(pCh);
+ dxs_tone_stop(pCh);
+ if (pCid->need_unmute)
+ dxs_pcm_ch_mute(pCh, 0);
+
+ sem_post(&pCid->sema);
+
+ /* wait for the thread to exit */
+ err = pthread_join (pCid->thrd, &ret_status);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusThreadStopError);
+ }
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Handle DTMF tone
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param pEvent - DXS_event_t data
+
+ \return
+ - uint_8
+*/
+uint8_t DXS_CID_EventDtmf(DXS_CHANNEL_t *pCh, DXS_Event_t *pEvent)
+{
+ uint8_t ret = 1;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (!pCid->complete)
+ {
+ if (pCid->std == DXS_CID_STD_BT)
+ {
+ /* Check if dtmf event should not be reported to the app */
+ if (pCid->cid_state == dxs_cid_bt_type2_wait_ack)
+ {
+ if (pEvent->data.dtmf.digit == pCid->dtmf_ack_idx)
+ {
+ /* Set ack flag and wake up */
+ pCid->ack_detect = 1;
+ sem_post(&pCid->sema);
+ ret = 0;
+ }
+ }
+ }
+ else if (pCid->std == DXS_CID_STD_TELCORDIA)
+ {
+ /* Check if dtmf event should not be reported to the app */
+ if (pCid->cid_state == dxs_cid_tc_type2_wait_ack)
+ {
+ if (pEvent->data.dtmf.digit == pCid->dtmf_ack_idx)
+ {
+ /* Set ack flag and wake up */
+ pCid->ack_detect = 1;
+ sem_post(&pCid->sema);
+ ret = 0;
+ }
+ }
+ }
+ else if (pCid->std == DXS_CID_STD_ETSI)
+ {
+ /* Check if dtmf event should not be reported to the app */
+ if (pCid->cid_state == dxs_cid_etsi_type2_wait_ack)
+ {
+ if (pEvent->data.dtmf.digit == pCid->dtmf_ack_idx)
+ {
+ /* Set ack flag and wake up */
+ pCid->ack_detect = 1;
+ sem_post(&pCid->sema);
+ ret = 0;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ Handle off-hook
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param timestamp - FW timestamp of hook event
+
+ \return
+ - uint_8
+*/
+uint8_t DXS_CID_EventOffhook(DXS_CHANNEL_t *pCh, uint16_t timestamp)
+{
+ uint8_t ret = 1;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if ((pCid->magic == DXS_CID_CTX_MAGIC) && (!pCid->complete))
+ {
+ if ((pCid->std == DXS_CID_STD_TELCORDIA) && (pCid->hook_block))
+ {
+ /* Hide first off-hook event at the end of OSI */
+ pCid->hook_block = 0;
+ ret = 0;
+ }
+ else
+ {
+ if (pCid->std == DXS_CID_STD_NTT)
+ {
+ /* Check if off-hook event should not be reported to the app */
+ if ((pCid->cid_state == dxs_cid_ntt_car_off) ||
+ (pCid->cid_state == dxs_cid_ntt_car_on))
+ ret = 0;
+ }
+
+ /* Set off-hook and wake up */
+ pCid->hook_state = DXS_CID_HOOK_STATE_OFFHOOK;
+ pCid->hook_timestamp = timestamp;
+ sem_post(&pCid->sema);
+ }
+ }
+
+ return ret;
+}
+
+#ifdef DXS_FEAT_HSM
+/**
+ Handle OPC for disabled
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+
+ \return
+ - uint_8
+*/
+uint8_t DXS_CID_EventOpcDisabled(DXS_CHANNEL_t *pCh)
+{
+ uint8_t ret = 1;
+ DXS_CID_Ctx_t *pCid;
+
+ if (pCh != NULL)
+ {
+ if (pCh->pParent != NULL)
+ {
+ pCid = &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ if ((pCid->magic == DXS_CID_CTX_MAGIC) && (!pCid->complete))
+ {
+ if ((pCid->std == DXS_CID_STD_TELCORDIA) &&
+ ((pCid->cid_state == dxs_cid_tc_type2_osi_first) ||
+ (pCid->cid_state == dxs_cid_tc_type2_osi_last)))
+ {
+ /* Do not report OPC to HSM */
+ ret = 0;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+#endif
+
+/**
+ Handle on-hook
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param timestamp - FW timestamp of hook event
+
+ \return
+ - uint_8
+*/
+uint8_t DXS_CID_EventOnhook(DXS_CHANNEL_t *pCh, uint16_t timestamp)
+{
+ uint8_t ret = 1;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if ((pCid->magic == DXS_CID_CTX_MAGIC) && (!pCid->complete))
+ {
+ if (pCid->std == DXS_CID_STD_NTT)
+ {
+ /* Check if on-hook event should not be reported to the app */
+ if (pCid->cid_state == dxs_cid_ntt_wait_onhook)
+ ret = 0;
+ }
+
+ /* Set on-hook and wake up */
+ pCid->hook_state = DXS_CID_HOOK_STATE_ONHOOK;
+ pCid->hook_timestamp = timestamp;
+ sem_post(&pCid->sema);
+ }
+
+ return ret;
+}
+
+/**
+ Handle FSK transmit complete
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+
+ \return
+ - none
+*/
+void DXS_CID_FSK_SendComplete(DXS_CHANNEL_t *pCh)
+{
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ sem_post(&pCid->sema);
+}
+
+/**
+ Handle FSK transmit error
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+
+ \return
+ - none
+*/
+void DXS_CID_FSK_SendError(DXS_CHANNEL_t *pCh)
+{
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+ DXS_Event_t dxs_event = {0};
+ void *ret_status;
+
+ if (!pCid->complete)
+ {
+ pCid->complete = 1;
+
+ /* attempt to terminate all possible states of CID sequence */
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
+ DXS_CID_FSK_Stop(pCh);
+ dxs_tone_stop(pCh);
+ if (pCid->need_unmute)
+ dxs_pcm_ch_mute(pCh, 0);
+
+ sem_post(&pCid->sema);
+
+ /* wait for the thread to exit */
+ pthread_join (pCid->thrd, &ret_status);
+ }
+
+ /* inform application */
+ dxs_event.dev = pCh->pParent->nDevNum;
+ dxs_event.ch = pCh->nCh;
+ dxs_event.id = DXS_EVENT_CID_SEQ_ERROR;
+ dxs_event.data.cid_err = DXS_EVENT_CID_FSK_BUF;
+ DXS_EventDispatch(pCh->pParent, &dxs_event);
+}
+
+/**
+ Cleanup CID context
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+
+ \return
+ - none
+*/
+void DXS_CID_Cleanup(DXS_CHANNEL_t *pCh)
+{
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pCid->magic = 0;
+}
+
+/**
+ Get CID sequence length in units of 50ms
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param pLen - pointer to CID sequence length (output)
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_LengthBitsGet(DXS_CHANNEL_t *pCh, int32_t *pLen)
+{
+ int32_t cid_len_ms;
+ uint16_t fsk_buffer_bytes = 0;
+ dxs_cid_message_t *p, *pMsg;
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* check if pCid is initialized */
+ if (pCid->magic != DXS_CID_CTX_MAGIC)
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ pMsg = dxs_cid_message_get(pCid, DXS_CID_MSG_TYPE_CS);
+
+ p = pMsg;
+ /* calculate total length for an FSK buffer */
+ while (p != NULL)
+ {
+ fsk_buffer_bytes += (p->len + 2); /* + parameter code + length byte */
+ p = p->next;
+ }
+ fsk_buffer_bytes += 3; /* + message type code + total length byte + checksum */
+
+ if (pCid->std == DXS_CID_STD_ETSI && pCid->as == DXS_CID_AS_NONE)
+ {
+ /* T5 + SEIZURE + MARK + FSK + T6 */
+ cid_len_ms = pCid->tm_etsi.T5 + pCid->tm_etsi.T6 +
+ (DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
+ (fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
+ }
+ else if (pCid->std == DXS_CID_STD_ETSI && pCid->as == DXS_CID_AS_DTAS)
+ {
+ /* DTAS + T4 + SEIZ + MARK + FSK + T2 */
+ cid_len_ms = pCid->tm_etsi.dtas + pCid->tm_etsi.T4 + pCid->tm_etsi.T2 +
+ (DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
+ (fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
+ }
+ else if (pCid->std == DXS_CID_STD_ETSI && pCid->as == DXS_CID_AS_RPAS)
+ {
+ /* RPAS + T3 + SEIZ + MARK + FSK + T2 */
+ cid_len_ms = pCid->tm_etsi.rpas + pCid->tm_etsi.T3 + pCid->tm_etsi.T2 +
+ (DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
+ (fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
+ }
+ else if (pCid->std == DXS_CID_STD_ETSI && pCid->as == DXS_CID_AS_LR_DTAS)
+ {
+ /* assume LR=0 + T0 + DTAS + T1 + SEIZ + MARK + FSK + T2 */
+ cid_len_ms = pCid->tm_etsi.dtas +
+ pCid->tm_etsi.T0 + pCid->tm_etsi.T1 + pCid->tm_etsi.T2 +
+ (DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
+ (fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
+ }
+ else if (pCid->std == DXS_CID_STD_TELCORDIA && pCid->as == DXS_CID_AS_NONE)
+ {
+ /* T0 + SEIZURE + MARK + FSK + T2 */
+ cid_len_ms = pCid->tm_tc.T0 + pCid->tm_tc.T2 +
+ (DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
+ (fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
+ }
+ else if (pCid->std == DXS_CID_STD_TELCORDIA && pCid->as == DXS_CID_AS_OSI)
+ {
+ /* assume DISABLED=0 + timer OSI + T1 + SEIZ + MARK + FSK + T2 */
+ cid_len_ms = pCid->tm_tc.osi + pCid->tm_tc.T1 + pCid->tm_tc.T2 +
+ (DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
+ (fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
+ }
+ else if (pCid->std == DXS_CID_STD_BT && pCid->as == DXS_CID_AS_LR_DTAS)
+ {
+ /* assume LR=0 + T0 + DTAS + T1 + SEIZ + MARK + FSK + T2 */
+ cid_len_ms = pCid->tm_bt.T0 + pCid->tm_bt.dtas + pCid->tm_bt.T1 +
+ pCid->tm_bt.T2 +
+ (DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_BT_MARK_DEFAULT +
+ (fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
+ }
+ else
+ {
+ /* FIXME: NTT standard is
+ temporarily not supported */
+ *pLen = -1;
+ return DXS_statusOk;
+ }
+
+ *pLen = ((cid_len_ms + 25) / 50);
+ return DXS_statusOk;
+}
+
+/**
+ Get CID standard
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param pStd - pointer to CID standard (output)
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_StandardGet (DXS_CHANNEL_t *pCh, DXS_CID_Std_t *pStd)
+{
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* check if pCid is initialized */
+ if (pCid->magic != DXS_CID_CTX_MAGIC)
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+ *pStd = pCid->std;
+ return DXS_statusOk;
+}
+
+/**
+ Get CID alert signal
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+ \param pAsig - pointer to CID alert signal (output)
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_AlertSigGet (DXS_CHANNEL_t *pCh, DXS_CID_AS_t *pAsig)
+{
+ DXS_CID_Ctx_t *pCid =
+ &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* check if pCid is initialized */
+ if (pCid->magic != DXS_CID_CTX_MAGIC)
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+ *pAsig = pCid->as;
+ return DXS_statusOk;
+}
+
+extern int SLICAPP_CID_Std;
+int32_t dxsapi_cid_fsk_etsi_type2 (uint8_t dxs, uint8_t line, char *cid_cli)
+{
+ int32_t ret = 0;
+
+ DXS_CID_Std_t std;
+ DXS_CID_AS_t as;
+ DXS_CID_DATA_FMT_t fmt;
+ uint8_t dtmf_ack_idx = 0;
+
+ struct tm tms = {0};
+ time_t rawtime;
+ uint8_t i = 0;
+ char timedate_buffer[8];
+ char cid_party_name[] = "CALLING";
+
+ /* select STD, format, ack DTMF digit */
+ std = SLICAPP_CID_Std;
+ fmt = DXS_CID_DATA_FSK;
+ as = DXS_CID_AS_NONE;
+ dtmf_ack_idx = 31; /* index DTMF digit */
+ ret = DxsCidInit(dxs, line, std, as, fmt, dtmf_ack_idx);
+
+ /* Prepare Call Setup message for device dev, channel line:
+ 1) Add Calling Line ID parameter
+ 2) Add Calling Party Name parameter
+ 3) Add Date Time parameter */
+
+ ret = DxsCidMsgSetup(dxs, line,
+ DXS_CID_MSG_TYPE_CS,
+ DXS_CID_MSG_PARAM_CALLING_LINE_ID,
+ cid_cli,
+ strlen(cid_cli));
+
+ ret = DxsCidMsgSetup(dxs, line,
+ DXS_CID_MSG_TYPE_CS,
+ DXS_CID_MSG_PARAM_CALLING_PARTY_NAME,
+ cid_party_name,
+ strlen(cid_party_name));
+
+ /* Date and time */
+ rawtime = time(NULL);
+ localtime_r(&rawtime, &tms);
+ /* month */
+ timedate_buffer[i++] = (tms.tm_mon + 1) / 10 + '0';
+ timedate_buffer[i++] = (tms.tm_mon + 1) % 10 + '0';
+ /* day */
+ timedate_buffer[i++] = tms.tm_mday / 10 + '0';
+ timedate_buffer[i++] = tms.tm_mday % 10 + '0';
+ /* hour */
+ timedate_buffer[i++] = tms.tm_hour / 10 + '0';
+ timedate_buffer[i++] = tms.tm_hour % 10 + '0';
+ /* minute */
+ timedate_buffer[i++] = tms.tm_min / 10 + '0';
+ timedate_buffer[i++] = tms.tm_min % 10 + '0';
+
+ ret = DxsCidMsgSetup(dxs, line,
+ DXS_CID_MSG_TYPE_CS,
+ DXS_CID_MSG_PARAM_DATE_TIME,
+ timedate_buffer,
+ sizeof(timedate_buffer));
+ /* Transmit Type2 Call Setup message */
+ ret = DxsCidTypeIIMsgStart(dxs, line, DXS_CID_MSG_TYPE_CS);
+ return ret;
+}
+
+#endif /* DXS_FEAT_CID */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_cid.h b/marvell/services/dxslic/api_lib/src/dxs_cid.h
new file mode 100644
index 0000000..1bcbdec
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_cid.h
@@ -0,0 +1,67 @@
+#ifndef __DXS_CID_H__
+#define __DXS_CID_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_cid.h
+ Caller ID module interface declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_lib.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_CID_CALL_FROM_CID_API 0
+#define DXS_CID_CALL_FROM_RING_SM 1
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* called from API */
+extern int32_t DXS_CID_Init(DXS_CHANNEL_t *pCh, DXS_CID_Std_t std,
+ DXS_CID_AS_t as, DXS_CID_DATA_FMT_t fmt, uint8_t dtmf_ack_idx);
+extern void DXS_CID_Cleanup(DXS_CHANNEL_t *pCh);
+extern int32_t DXS_CID_TimerConfig(DXS_CHANNEL_t *pCh, DXS_CID_Std_t std,
+ DXS_CID_Timers_t *pTimers);
+extern int32_t DXS_CID_MsgUpdate(DXS_CHANNEL_t *pCh,
+ DXS_CID_MsgType_t msg_type,
+ DXS_CID_MsgParam_t param, char *pData,
+ uint8_t length);
+extern int32_t DXS_CID_MsgCleanup(DXS_CHANNEL_t *pCh);
+extern int32_t DXS_CID_TypeI_Play(DXS_CHANNEL_t *pCh,
+ DXS_CID_MsgType_t msg_type,
+ uint8_t calling_instance);
+extern int32_t DXS_CID_TypeII_Play(DXS_CHANNEL_t *pCh,
+ DXS_CID_MsgType_t msg_type);
+extern int32_t DXS_CID_Stop(DXS_CHANNEL_t *pCh);
+/* called from event handler */
+extern void DXS_CID_FSK_SendComplete(DXS_CHANNEL_t *pCh);
+extern void DXS_CID_FSK_SendError(DXS_CHANNEL_t *pCh);
+extern uint8_t DXS_CID_EventOnhook(DXS_CHANNEL_t *pCh, uint16_t timestamp);
+extern uint8_t DXS_CID_EventOffhook(DXS_CHANNEL_t *pCh, uint16_t timestamp);
+extern uint8_t DXS_CID_EventDtmf(DXS_CHANNEL_t *pCh, DXS_Event_t *pEvent);
+extern uint8_t DXS_CID_EventOpcDisabled(DXS_CHANNEL_t *pCh);
+extern int32_t DXS_CID_LengthBitsGet(DXS_CHANNEL_t *pCh, int32_t *pLen);
+extern int32_t DXS_CID_StandardGet (DXS_CHANNEL_t *pCh, DXS_CID_Std_t *pStd);
+extern int32_t DXS_CID_AlertSigGet (DXS_CHANNEL_t *pCh, DXS_CID_AS_t *pAsig);
+extern int32_t dxsapi_cid_fsk_etsi_type2 (uint8_t dxs, uint8_t line, char *cid_cli);
+
+#endif /* __DXS_CID_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_cid_fsk.c b/marvell/services/dxslic/api_lib/src/dxs_cid_fsk.c
new file mode 100644
index 0000000..a226a7a
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_cid_fsk.c
@@ -0,0 +1,168 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_cid_fsk.c
+ FSK interface functions for CID state machine and event handler
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdlib.h>
+
+#include "dxs.h"
+#include "dxs_config.h"
+#include "dxs_lib.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_cid.h"
+#include "dxs_cid_fsk.h"
+#include "dxs_sig.h"
+
+#ifdef DXS_FEAT_CID
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_CID_FSK_MAX_FRAFMENT_SZ 27
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* FSK data buffer */
+typedef struct
+{
+ uint8_t *data;
+ uint16_t len;
+ uint16_t pos;
+} DXS_FSK_Buffer_t;
+
+/* FSK data buffers are as many as channels */
+static DXS_FSK_Buffer_t fsk_buffers[DXS_MAX_DEVICES * CH_PER_DEVICE] = {0};
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/**
+ Retrieve the next data fragment size
+
+ \param pBuf - pointer to \ref DXS_FSK_Buffer_t structure
+
+ \return
+ - fragment size
+*/
+static uint16_t dxs_cid_fsk_fragment_size_get(DXS_FSK_Buffer_t *pBuf)
+{
+ uint16_t full_blocks = (pBuf->len - pBuf->pos) / DXS_CID_FSK_MAX_FRAFMENT_SZ;
+
+ if (full_blocks)
+ return DXS_CID_FSK_MAX_FRAFMENT_SZ;
+
+ return ((pBuf->len - pBuf->pos) % DXS_CID_FSK_MAX_FRAFMENT_SZ);
+}
+
+/**
+ Start the FSK state machine
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t structure
+ \param spec - FSK spec (Bell202 or ITU-T)
+ \param ad - auto-deactivate flag
+ \param pData - data buffer
+ \param len - length of data buffer
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_FSK_Start (DXS_CHANNEL_t *pCh, int32_t spec, int32_t ad,
+ uint8_t *pData, uint16_t len)
+{
+ DXS_FSK_Buffer_t *pBuf =
+ &fsk_buffers[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ /* prepare buffer */
+ pBuf->data = pData;
+ pBuf->len = len;
+ pBuf->pos = 0;
+
+ return DXS_FSK_Enable(pCh, spec, ad);
+}
+
+/**
+ Inform FSK state machine about device event
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t structure
+ \param event - event information from device
+
+ \return
+ - DXS_status_t
+*/
+void DXS_CID_FSK_EventInfo (DXS_CHANNEL_t *pCh, int32_t event)
+{
+ DXS_FSK_Buffer_t *pBuf =
+ &fsk_buffers[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ switch (event)
+ {
+ case DXS_CID_FSK_DATA_REQUEST:
+ {
+ uint8_t *p = &pBuf->data[pBuf->pos];
+ uint16_t fragment_sz = dxs_cid_fsk_fragment_size_get(pBuf);
+
+ if (fragment_sz > 0)
+ {
+ DXS_FSK_Data(pCh, fragment_sz, p);
+ pBuf->pos += fragment_sz;
+ }
+ else
+ {
+ DXS_FSK_Disable(pCh, 1);
+ }
+ }
+ break;
+
+ case DXS_CID_FSK_DATA_BUF:
+ /* usage is not clear, it looks like FW
+ sends up this event also after FSK deactivation with AD=1 */
+ break;
+
+ case DXS_CID_FSK_DATA_FINISH:
+ {
+ /* inform CID state machine */
+ DXS_CID_FSK_SendComplete(pCh);
+ }
+ break;
+
+ default:
+ {
+ /* inform CID state machine */
+ DXS_CID_FSK_SendError(pCh);
+ }
+ }
+}
+
+/**
+ Stop the FSK transmitter
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CID_FSK_Stop(DXS_CHANNEL_t *pCh)
+{
+ /* disable FSK immediately */
+ return DXS_FSK_Disable(pCh, 0);
+}
+
+#endif /* DXS_FEAT_CID */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_cid_fsk.h b/marvell/services/dxslic/api_lib/src/dxs_cid_fsk.h
new file mode 100644
index 0000000..e64d4da
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_cid_fsk.h
@@ -0,0 +1,46 @@
+#ifndef __DXS_CID_FSK_H__
+#define __DXS_CID_FSK_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_cid_fsk.h
+ Caller ID FSK module interface declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_lib.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* FSK spec options */
+#define DXS_CID_FSK_V23_BEL202 0
+#define DXS_CID_FSK_V23_ITU_T 1
+
+/* device events */
+#define DXS_CID_FSK_DATA_REQUEST 1
+#define DXS_CID_FSK_DATA_FINISH 2
+#define DXS_CID_FSK_DATA_BUF 3
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern int32_t DXS_CID_FSK_Start(DXS_CHANNEL_t *pCh, int32_t spec, int32_t ad,
+ uint8_t *pData, uint16_t len);
+extern int32_t DXS_CID_FSK_Stop(DXS_CHANNEL_t *pCh);
+extern void DXS_CID_FSK_EventInfo(DXS_CHANNEL_t *pCh, int32_t event);
+
+
+#endif /* __DXS_CID_FSK_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_dcdc_hw.c b/marvell/services/dxslic/api_lib/src/dxs_dcdc_hw.c
new file mode 100644
index 0000000..ad458ec
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_dcdc_hw.c
@@ -0,0 +1,419 @@
+/*******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, 2017, 2018 Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+*******************************************************************************/
+
+/**
+ \file dxs_dcdc_hw.c
+ Implementation of DXS DC/DC hardware specific limitations.
+ Example limitation:
+ \ref DXS_DCDC_IFB12CH8 can provide the ringing voltage
+ only for two channels at a time.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_config.h"
+#include "dxs_dcdc_hw.h"
+#include "dxs_error.h"
+#include "dxs_errno.h"
+#include "dxs_sdd.h"
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* total channel count */
+#define DXS_HW_CHANNELS (DXS_MAX_DEVICES * CH_PER_DEVICE)
+/* channels per DCDC */
+#define DXS_HW_CH_PER_DCDC 8
+/* maximum simultaneous ring bursts */
+#define DXS_MAX_SIMULTANEOUS_RINGS 2
+/* devices per DCDC */
+#define DXS_HW_DEV_PER_DCDC (DXS_HW_CH_PER_DCDC / CH_PER_DEVICE)
+/* total DCDC count */
+#define DXS_HW_DCDC_COUNT (DXS_HW_CHANNELS / DXS_HW_CH_PER_DCDC)
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+struct __dxs_hw_dcdc
+{
+ /*pthread_mutex_t mtx;*/
+ DXS_CHANNEL_t *pCh[DXS_HW_CH_PER_DCDC], *pChMaster;
+};
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+static uint32_t init_channels = 0;
+static struct __dxs_hw_dcdc dcdc_hw[DXS_HW_DCDC_COUNT];
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/**
+ Get the DCDC descriptor from channel
+
+ \param pCh - pointer to DXS channel structure
+ \return
+ - pointer to DCDC structure to which the channel belongs
+*/
+static struct __dxs_hw_dcdc *dxs_hw_get_dcdc (DXS_CHANNEL_t *pCh)
+{
+ struct __dxs_hw_dcdc *pDCDC;
+ uint8_t dcdc, ch;
+
+ for (dcdc=0, pDCDC=NULL; dcdc<DXS_HW_DCDC_COUNT && pDCDC==NULL; dcdc++)
+ {
+ for (ch=0; ch<DXS_HW_CH_PER_DCDC && pDCDC==NULL; ch++)
+ {
+ if (dcdc_hw[dcdc].pCh[ch] == pCh)
+ pDCDC = &dcdc_hw[dcdc];
+ }
+ }
+ return pDCDC;
+}
+
+/**
+ Add DXS channel to the DCDC channel table
+
+ \param pCh - pointer to DXS channel structure
+ \param nDcDcNum - DCDC number to which the channel belongs
+ \return none
+*/
+static void dxs_hw_channel_add (DXS_CHANNEL_t *pCh, uint8_t nDcDcNum)
+{
+ uint8_t dcdc, ch, found;
+
+ if (!init_channels)
+ {
+ for (dcdc=0; dcdc<DXS_HW_DCDC_COUNT; dcdc++)
+ {
+ dcdc_hw[dcdc].pChMaster = NULL;
+ /*pthread_mutex_init(&dcdc_hw[dcdc].mtx, NULL);*/
+ for (ch=0; ch<DXS_HW_CH_PER_DCDC; ch++)
+ dcdc_hw[dcdc].pCh[ch] = NULL;
+ }
+ }
+ ++init_channels;
+
+ for (ch=0, found=0; ch<DXS_HW_CH_PER_DCDC && !found; ch++)
+ {
+ /* channel was already entered */
+ if (dcdc_hw[nDcDcNum].pCh[ch] == pCh)
+ break;
+
+ if (dcdc_hw[nDcDcNum].pCh[ch] == NULL)
+ {
+ found = 1;
+ dcdc_hw[nDcDcNum].pCh[ch] = pCh;
+ }
+ }
+}
+
+/**
+ Delete DXS channel from the DCDC channel table
+
+ \param pCh - pointer to DXS channel structure
+ \return none
+*/
+static void dxs_hw_channel_delete (DXS_CHANNEL_t *pCh)
+{
+ uint8_t dcdc, ch, found;
+#if 0
+ int32_t err;
+#endif
+
+ for (dcdc=0, found=0; dcdc<DXS_HW_DCDC_COUNT && !found; dcdc++)
+ {
+ for (ch=0; ch<DXS_HW_CH_PER_DCDC && !found; ch++)
+ {
+ if (dcdc_hw[dcdc].pCh[ch] == pCh)
+ {
+ found = 1;
+ dcdc_hw[dcdc].pCh[ch] = NULL;
+ }
+ }
+ }
+
+ if (found)
+ {
+ --init_channels;
+ if (!init_channels)
+ {
+ for (dcdc=0; dcdc<DXS_HW_DCDC_COUNT; dcdc++)
+ {
+#if 0
+ err = pthread_mutex_unlock(&dcdc_hw[dcdc].mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ err = pthread_mutex_destroy(&dcdc_hw[dcdc].mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+#endif
+ for (ch=0; ch<DXS_HW_CH_PER_DCDC; ch++)
+ dcdc_hw[dcdc].pCh[ch] = NULL;
+ }
+ }
+ }
+}
+
+/**
+ Check the DC/DC ringing capabilities
+
+ \param pCh - pointer to DXS channel structure
+ \return
+ DXS_statusOk - success
+ DXS_statusDcDcRingCapsExceeded - maximum allowed
+ simultaneous ringing capacity reached
+ DXS_statusNotInitResource - channel not initialized
+*/
+int32_t DXS_DCDC_HW_RingingCapsCheck (DXS_CHANNEL_t *pCh)
+{
+ if (pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ struct __dxs_hw_dcdc *pDCDC;
+ uint8_t ch;
+
+ if ((pDCDC = dxs_hw_get_dcdc(pCh)) != NULL)
+ {
+ uint8_t ringing = 0;
+#if 0
+ int32_t err;
+
+ err = pthread_mutex_lock (&pDCDC->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+#endif
+
+ for (ch=0; ch<DXS_HW_CH_PER_DCDC; ch++)
+ if (DXS_SDD_IsRingingUnprot(pDCDC->pCh[ch]))
+ ++ringing;
+
+#if 0
+ err = pthread_mutex_unlock (&pDCDC->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+#endif
+
+ if (ringing >= DXS_MAX_SIMULTANEOUS_RINGS)
+ {
+ return DXS_statusDcDcRingCapsExceeded;
+ }
+ }
+ else
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+ }
+ return DXS_statusOk;
+}
+
+/**
+ Initialize DCDC HW channels
+
+ \param pDev - pointer to DXS device structure
+ \return none
+*/
+void DXS_DCDC_HW_Init (DXS_DEVICE_t *pDev)
+{
+ if (pDev->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ uint8_t ch = 0,
+ /* nDevNum must be contiguous for a DCDC */
+ dcdc = pDev->nDevNum/DXS_HW_DEV_PER_DCDC;
+
+ while (ch < pDev->nChannels)
+ {
+ DXS_CHANNEL_t *pCh = &pDev->pChannel[ch++];
+
+ dxs_hw_channel_add(pCh, dcdc);
+ }
+ }
+}
+
+/**
+ De-initialize DCDC HW channels
+
+ \param pDev - pointer to DXS device structure
+ \return none
+*/
+void DXS_DCDC_HW_Exit (DXS_DEVICE_t *pDev)
+{
+ if (pDev->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ uint8_t ch = 0;
+
+ while (ch < pDev->nChannels)
+ {
+ DXS_CHANNEL_t *pCh = &pDev->pChannel[ch++];
+
+ dxs_hw_channel_delete(pCh);
+ }
+ }
+}
+
+#if 0
+/**
+ Lock the DCDC resource
+
+ \param pCh - pointer to DXS channel structure
+ \return none
+*/
+void DXS_DCDC_HW_Lock (DXS_CHANNEL_t *pCh)
+{
+ if (pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ struct __dxs_hw_dcdc *pDCDC;
+ int32_t err;
+
+ if ((pDCDC = dxs_hw_get_dcdc(pCh)) != NULL)
+ {
+ err = pthread_mutex_lock (&pDCDC->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ }
+ }
+}
+
+/**
+ Unlock the DCDC resource
+
+ \param pCh - pointer to DXS channel structure
+ \return none
+*/
+void DXS_DCDC_HW_UnLock (DXS_CHANNEL_t *pCh)
+{
+ if (pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ struct __dxs_hw_dcdc *pDCDC;
+ int32_t err;
+
+ if ((pDCDC = dxs_hw_get_dcdc(pCh)) != NULL)
+ {
+ err = pthread_mutex_unlock (&pDCDC->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ }
+ }
+}
+#endif
+
+/**
+ Set the shared DC/DC master channel.
+
+ \param pCh - pointer to DXS channel structure
+ \return
+ - DXS_statusOk
+ - DXS_statusInvalidParam
+*/
+int32_t DXS_DCDC_HW_SharedDcDcMasterChSet (DXS_CHANNEL_t *pCh)
+{
+ if (pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ struct __dxs_hw_dcdc *pDCDC;
+
+ if ((pDCDC = dxs_hw_get_dcdc(pCh)) != NULL)
+ {
+ if (pDCDC->pChMaster != NULL && pDCDC->pChMaster != pCh)
+ {
+ /* error msg: different channel was
+ already set as master */
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ else if (pDCDC->pChMaster == NULL)
+ pDCDC->pChMaster = pCh;
+ }
+ else
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+ }
+ return DXS_statusOk;
+}
+
+/**
+ Get the master channel of a DC/DC to which the device belongs
+
+ \param pDev - pointer to DXS device structure
+ \return
+ pointer to DXS master channel structure or NULL
+*/
+DXS_CHANNEL_t *DXS_DCDC_HW_SharedDcDcMasterChGetInt (DXS_DEVICE_t *pDev)
+{
+ if (pDev->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ DXS_CHANNEL_t *pCh = &pDev->pChannel[0];
+ struct __dxs_hw_dcdc *pDCDC;
+
+ if ((pDCDC = dxs_hw_get_dcdc(pCh)) != NULL)
+ return pDCDC->pChMaster;
+ }
+ return NULL;
+}
+
+/**
+ Get the number of channels supported by the DC/DC
+ to which the pCh belongs
+
+ \param pCh - pointer to DXS channel structure
+ \return
+ number of channels or 0 if the DC/DC is not covered
+*/
+uint8_t DXS_DCDC_HW_SharedDcDcChannelNumGet (DXS_CHANNEL_t *pCh)
+{
+ if (pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ return DXS_HW_CH_PER_DCDC;
+
+ return 0;
+}
+
+/**
+ Get the number of the DC/DC to which the pCh belongs
+
+ \param pCh - pointer to DXS channel structure
+ \return
+ the number of the DC/DC or negative in case if pCh
+ was not found in any of the DC/DC
+*/
+int32_t DXS_DCDC_HW_SharedDcDcNumberGet (DXS_CHANNEL_t *pCh)
+{
+ int8_t dcdc, ch;
+
+ for (dcdc=0; dcdc<DXS_HW_DCDC_COUNT; dcdc++)
+ {
+ for (ch=0; ch<DXS_HW_CH_PER_DCDC; ch++)
+ {
+ if (dcdc_hw[dcdc].pCh[ch] == pCh)
+ return dcdc;
+ }
+ }
+ return -1;
+}
+
+/**
+ Get the DXS channel structure for the given DC/DC
+ number and channel offset
+
+ \param dcdc - DC/DC number from 0
+ \param ch - channel number from 0 within the DC/DC
+ \return
+ the DXS channel structure or NULL if the channel stucture
+ cannot be found in a given DC/DC
+*/
+DXS_CHANNEL_t *DXS_DCDC_HW_SharedDcDcChannelGet (uint8_t dcdc, uint8_t ch)
+{
+ if (dcdc >= DXS_HW_DCDC_COUNT || ch >= DXS_HW_CH_PER_DCDC)
+ return NULL;
+
+ return dcdc_hw[dcdc].pCh[ch];
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_dcdc_hw.h b/marvell/services/dxslic/api_lib/src/dxs_dcdc_hw.h
new file mode 100644
index 0000000..5bfbb25
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_dcdc_hw.h
@@ -0,0 +1,42 @@
+#ifndef __DXS_DCDC_HW_H__
+#define __DXS_DCDC_HW_H__
+/*******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, 2017, 2018 Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+*******************************************************************************/
+
+/**
+ \file dxs_dcdc_hw.h
+ API functions for handling of DC/DC hardware specific limitations.
+ Example limitation:
+ \ref DXS_DCDC_IFB12CH8 can provide the ringing voltage
+ only for two channels at a time.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs.h"
+#include "dxs_lib.h"
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern int32_t DXS_DCDC_HW_RingingCapsCheck (DXS_CHANNEL_t *);
+extern void DXS_DCDC_HW_Init (DXS_DEVICE_t *);
+extern void DXS_DCDC_HW_Exit (DXS_DEVICE_t *);
+extern void DXS_DCDC_HW_Lock (DXS_CHANNEL_t *);
+extern void DXS_DCDC_HW_UnLock (DXS_CHANNEL_t *);
+extern DXS_CHANNEL_t *DXS_DCDC_HW_SharedDcDcMasterChGetInt (DXS_DEVICE_t *pDev);
+extern int32_t DXS_DCDC_HW_SharedDcDcMasterChSet (DXS_CHANNEL_t *pCh);
+extern uint8_t DXS_DCDC_HW_SharedDcDcChannelNumGet (DXS_CHANNEL_t *pCh);
+extern int32_t DXS_DCDC_HW_SharedDcDcNumberGet (DXS_CHANNEL_t *pCh);
+extern DXS_CHANNEL_t* DXS_DCDC_HW_SharedDcDcChannelGet (uint8_t dcdc, uint8_t ch);
+
+#endif /* __DXS_DCDC_HW_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_debug_api.c b/marvell/services/dxslic/api_lib/src/dxs_debug_api.c
new file mode 100644
index 0000000..cda9144
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_debug_api.c
@@ -0,0 +1,175 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_debug_api.c
+ Implementation of debug API functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_config.h"
+#include "dxs_lib.h"
+#include "dxs_access.h"
+#include "dxs_mbx.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+#ifdef DXS_FEAT_DEBUG_API
+
+/**
+ Function dxs_reg_read
+
+ \param pDev - pointer to DXS device structure
+ \param offset - offset
+ \param pValue - pointer to value
+ \param count - count
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_reg_read ( DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t *pValue,
+ uint8_t count)
+{
+ int32_t ret, err;
+
+ err = pthread_mutex_lock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ ret = DXS_RegReadMulti(pDev, offset, pValue, count);
+
+ err = pthread_mutex_unlock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ /* TODO: howto handle error? */
+ return ret;
+}
+
+/**
+ Function dxs_reg_write
+
+ \param pDev - pointer to DXS device structure
+ \param offset - offset
+ \param pValue - pointer to value
+ \param count - count
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_reg_write ( DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t *pValue,
+ uint8_t count)
+{
+ int32_t ret, err;
+
+ err = pthread_mutex_lock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ ret = DXS_RegWriteMulti(pDev, offset, pValue, count);
+
+ err = pthread_mutex_unlock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ /* TODO: howto handle error? */
+ return ret;
+}
+
+/**
+ Function dxs_cmd_read
+
+ \param pDev - pointer to DXS device structure
+ \param hdr - header
+ \param pData - pointer to command data
+ \param pLength - pointer to length
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_cmd_read ( DXS_DEVICE_t *pDev,
+ uint32_t hdr,
+ uint32_t *pData,
+ uint8_t *pLength)
+{
+ uint8_t cmd_length;
+ int32_t ret;
+
+ cmd_length = hdr & 0xFF;
+
+ if ((cmd_length > (0xFF-4)) || ((cmd_length+4) > *pLength))
+ {
+ DXS_RETURN(DXS_statusCmdLengthInvalid);
+ }
+
+ ret = CmdRead(pDev, &hdr, pData);
+
+ *pLength = 4 + cmd_length; /* including the size of the command header */
+ return ret;
+}
+
+/**
+ Function dxs_cmd_write
+
+ \param pDev - pointer to DXS device structure
+ \param pCmd - pointer to command data
+ \param length - length
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_cmd_write ( DXS_DEVICE_t *pDev,
+ uint32_t *pCmd,
+ uint8_t length)
+{
+ uint8_t cmd_length;
+
+ if (length < 4)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ cmd_length = *pCmd & 0xFF;
+
+ if ((cmd_length > (0xFF-4)) || ((cmd_length+4) > length))
+ {
+ DXS_RETURN(DXS_statusCmdLengthInvalid);
+ }
+
+ return CmdWrite(pDev, pCmd);
+}
+
+#endif /* DXS_FEAT_DEBUG_API */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_debug_api.h b/marvell/services/dxslic/api_lib/src/dxs_debug_api.h
new file mode 100644
index 0000000..4aa2c89
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_debug_api.h
@@ -0,0 +1,57 @@
+#ifndef __DXS_DEBUG_API_H__
+#define __DXS_DEBUG_API_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_debug_api.h
+ Debug API functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern int32_t dxs_reg_read (
+ DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t *pValue,
+ uint8_t count);
+
+extern int32_t dxs_reg_write (
+ DXS_DEVICE_t *pDev,
+ uint8_t offset,
+ uint16_t *pValue,
+ uint8_t count);
+
+extern int32_t dxs_cmd_read (
+ DXS_DEVICE_t *pDev,
+ uint32_t hdr,
+ uint32_t *pData,
+ uint8_t *pLength);
+
+extern int32_t dxs_cmd_write (
+ DXS_DEVICE_t *pDev,
+ uint32_t *pCmd,
+ uint8_t length);
+
+#endif /* __DXS_DEBUG_API_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_dwld.c b/marvell/services/dxslic/api_lib/src/dxs_dwld.c
new file mode 100644
index 0000000..1c615ce
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_dwld.c
@@ -0,0 +1,508 @@
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_dwld.c
+ Implementation of download functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "dxs_lib.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_access.h"
+#include "dxs_init.h"
+#include "dxs_mbx.h"
+#include "dxs_pollint.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_PRAM_MAGIC_DXS1 0x44585331
+#define DXS_PRAM_MAGIC_DXS2 0x44585332
+
+#define DXS_ROM_MASK_1_0 1
+#define DXS_ROM_MASK_2_0 2
+
+#define DXS_CRC32_POLY 0xEDB88320
+#define DXS_SWAP32(a) ((((a) >> 24) & 0xFF) | (((a) >> 8) & 0xFF00) | \
+ (((a) & 0xFF00) << 8) | (((a) & 0xFF) << 24))
+
+/* FW download container header struct values */
+#define DXS_FW_TYPE_GLOBAL_V1 0xD0000001 /* type 0xD000, version 0x0001 */
+#define DXS_FW_GLOBAL_MAGIC 0x44585346 /* 'DXSF' character sequence */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+struct pram_footer
+{
+ /* version information */
+ uint32_t fw_vers;
+ /* unix compilation timestamp */
+ uint32_t timestamp;
+ /* 'DXS1' or 'DXS2' */
+ uint32_t magic;
+ /* image size */
+ uint32_t mem;
+ /* CRC32 */
+ uint32_t crc;
+};
+
+/* FW download container header (big endian) */
+struct fw_container_header
+{
+ /* Type and Version identifier */
+ uint32_t nType;
+ /* Length of the payload following this header */
+ uint32_t nLength;
+ /* MAGIC value for endianess checking */
+ uint32_t nMagic;
+ /* Version, each of the 4 bytes represents a digit */
+ uint32_t nVersion;
+ /* Epoch timestamp */
+ uint32_t nTimestamp;
+ /* Offset of the DXS V11 FW within the payload section */
+ uint32_t nDxsV11FwOffset;
+ /* Length of the DXS V11 FW within the payload section */
+ uint32_t nDxsV11FwLength;
+ /* Offset of the DXS1 V12 FW within the payload section */
+ uint32_t nDxs1V12FwOffset;
+ /* Length of the DXS1 V12 FW within the payload section */
+ uint32_t nDxs1V12FwLength;
+ /* Offset of the DXS2 V12 FW within the payload section */
+ uint32_t nDxs2V12FwOffset;
+ /* Length of the DXS2 V12 FW within the payload section */
+ uint32_t nDxs2V12FwLength;
+};
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/**
+ Update CRC32 checksum
+
+ \param pData - data buffer
+ \param len - data buffer size in bytes
+ \param prev - previous CRC32 checksum (initial should be 0)
+
+ \return
+ Newly calculated CRC32 value
+*/
+static uint32_t dxs_crc32_le(const void *pData, size_t len, uint32_t prev)
+{
+ uint32_t crc = ~prev;
+ uint8_t *pByte = (uint8_t *)pData;
+ uint32_t j;
+
+ while (len--)
+ {
+ crc ^= (uint32_t) *pByte++;
+ for (j = 0; j < 8; j++)
+ {
+ if (crc & 1)
+ crc = (crc >> 1) ^ DXS_CRC32_POLY;
+ else
+ crc = crc >> 1;
+ }
+ }
+ return ~crc;
+}
+
+/**
+ Verify PRAM image CRC checksum
+
+ \param pData - pointer to image data
+ \param size - size of the image in bytes
+ \param cksum - CRC checksum from image footer
+
+ \return
+ 0 - verification failed
+ 1 - verification passed
+*/
+static int32_t pram_cksum_verify(uint8_t *pData, uint32_t size, uint32_t ftr_cksum)
+{
+ uint32_t calc_cksum = 0, words32 = size/sizeof(uint32_t);
+
+ while (words32--)
+ {
+ int32_t i = 1;
+ /* make 32-bit word of 4 bytes */
+ uint32_t word = (*pData << 24)|(*(pData+1) << 16)|(*(pData+2) << 8)|(*(pData+3));
+
+ if (!(*((int8_t *)&i)))
+ {
+ /* to use LE CRC32 calculation on BE system -
+ swap bytes in a word */
+ word = DXS_SWAP32(word);
+ }
+
+ calc_cksum = dxs_crc32_le((void *)&word, sizeof(word), calc_cksum);
+ pData += sizeof(word);
+ }
+
+ if (calc_cksum == ftr_cksum)
+ return 1;
+
+ return 0;
+}
+
+/**
+ Read the footer from PRAM patch file
+
+ \param pData - pointer to PRAM image
+ \param size - size of the PRAM image
+ \param f - pointer to footer structure
+
+ \return
+ - none
+*/
+static void pram_footer_read(uint8_t *pData, uint32_t size,
+ struct pram_footer *f)
+{
+ uint32_t offset = size - sizeof(*f), word, i;
+
+ for (i=0; i<(sizeof(*f)/sizeof(uint32_t)); i++)
+ {
+ word = 0;
+
+ word |= (uint32_t) (pData[offset++]) << 24;
+ word |= (uint32_t) (pData[offset++]) << 16;
+ word |= (uint32_t) (pData[offset++]) << 8;
+ word |= (uint32_t) (pData[offset++]);
+
+ *((uint32_t *)f + i) = word;
+ }
+}
+
+/**
+ Function dxs_fw_download
+
+ \param pDev - pointer to DXS device structure
+ \param pPatch - pointer to data buffer
+ \param nBytes - size of the buffer
+
+ \return
+ - DXS_status_t
+*/
+static int32_t dxs_fw_download(DXS_DEVICE_t *pDev,
+ uint8_t *pPatch, uint32_t nBytes)
+{
+ int32_t ret = DXS_statusOk;
+ uint16_t nDxsRegBootCfg = 0,
+ nDxsRegBootInfo = 0,
+ nDxsRegCfg = 0;
+ struct pram_footer ft;
+
+ /* read PRAM patch footer */
+ pram_footer_read(pPatch, nBytes, &ft);
+
+ /* if the image has a footer, verify the checksum */
+ if (ft.magic == DXS_PRAM_MAGIC_DXS1 || ft.magic == DXS_PRAM_MAGIC_DXS2)
+ {
+ /* do not pass the footer for checksum verification */
+ nBytes -= sizeof(struct pram_footer);
+
+ if (!pram_cksum_verify(pPatch, nBytes, ft.crc))
+ {
+ DXS_RETURN(DXS_statusPramPatchCksumError);
+ }
+
+ /* prepare image size for download -
+ minus one word of block delimiter */
+ nBytes -= sizeof(uint32_t);
+ }
+
+ /* stop polling timer */
+ if (pDev->irqNumber == -1)
+ {
+ dxs_polling_timer_stop();
+ }
+
+ /* Set the controller startup configuration in the Boot Configuration
+ Register to boot from HOST_DATA inbox. */
+ nDxsRegBootCfg = DXS_REG_BCFG_ASC_SPI;
+ ret = DXS_RegWrite(pDev, DXS_REG_BCFG, nDxsRegBootCfg);
+ if (ret != DXS_statusOk)
+ {
+ /* errmsg: Setting of boot configuration register failed. */
+ ret = DXS_statusSetBootCfgErr;
+ }
+
+ /* Reset controller to start the boot process from HOST_DATA inbox. */
+ if (ret == DXS_statusOk)
+ {
+ nDxsRegCfg = DXS_REG_CFG_RST_RSTCORE|DXS_REG_CFG_8BIT_EN;
+ ret = DXS_RegWrite(pDev, DXS_REG_CFG, nDxsRegCfg);
+ if (ret != DXS_statusOk)
+ {
+ /* errmsg: Controller reset failed. */
+ ret = DXS_statusCtrlResErr;
+ }
+ }
+
+ /* setup waiting flag */
+ pDev->bWaitingInPatchDwld = 1;
+
+ /* Download firmware patch. */
+ if (ret == DXS_statusOk)
+ {
+ ret = DXS_DwldPatch (pDev, pPatch, nBytes);
+ if (ret != DXS_statusOk)
+ {
+ /* errmsg: Download of the firmware binary failed. */
+ ret = DXS_statusDwldBinErr;
+ }
+ }
+
+ /* Check success of the download by reading the boot info register. */
+ if (ret == DXS_statusOk)
+ {
+ uint8_t loop = 10;
+
+ while (loop > 0)
+ {
+ struct timespec ts = {0, 2000000}; /* 2 ms */
+
+ nanosleep(&ts, NULL);
+
+ /* read the boot state indication */
+ ret = DXS_RegRead(pDev, DXS_REG_BINF, &nDxsRegBootInfo);
+
+ if ((ret == DXS_statusOk) &&
+ ((nDxsRegBootInfo & DXS_REG_BINF_BOOTSTATE_MASK) >= 0x10))
+ {
+ break;
+ }
+
+ loop--;
+ }
+
+ if (loop == 0)
+ {
+ /* errmsg: Firmware download timeout. */
+ ret = DXS_statusFwDwldTimeout;
+ }
+ }
+
+ /* Set bootmode back to ROM in case a recovery is needed. */
+ if (ret == DXS_statusOk)
+ {
+ nDxsRegBootCfg = DXS_REG_BCFG_ASC_ROM;
+ ret = DXS_RegWrite(pDev, DXS_REG_BCFG, nDxsRegBootCfg);
+
+ if (ret != DXS_statusOk)
+ {
+ /* errmsg: Setting of boot configuration register failed. */
+ ret = DXS_statusSetBootCfgErr;
+ }
+ }
+
+ /* restart polling timer */
+ if (pDev->irqNumber == -1)
+ {
+ dxs_polling_timer_start();
+ }
+
+ /* handle special test mode */
+ if (pDev->irqNumber == 255)
+ {
+ sem_post(&pDev->obxSemaphore);
+ }
+
+ /* wait for boot finished event */
+ ret = sem_wait(&pDev->mtxPatchDwld);
+ if (ret)
+ DXS_RETURN(ret);
+
+ /* enable interrupt self-clearing */
+ if (ret == DXS_statusOk)
+ {
+ ret = DXS_RegRead(pDev, DXS_REG_CFG, &nDxsRegCfg);
+ if (ret == DXS_statusOk)
+ {
+ nDxsRegCfg |= DXS_REG_CFG_SC_MD;
+ ret = DXS_RegWrite(pDev, DXS_REG_CFG, nDxsRegCfg);
+ if (ret != DXS_statusOk)
+ {
+ ret = DXS_statusRegWriteError;
+ }
+ }
+ else
+ {
+ ret = DXS_statusRegReadError;
+ }
+ }
+
+ /* read caps and version from the device, mark caps and
+ version structures updated */
+ if (ret == DXS_statusOk)
+ {
+ ret = dxs_caps_vers_update(pDev);
+ }
+
+ /* set default clock failure handling */
+ if (ret == DXS_statusOk)
+ {
+ ret = DXS_CfEsdSwitch(pDev, 1);
+ }
+
+ if (ret == DXS_statusOk)
+ {
+ pDev->flags |= DXS_DEV_PRAM_PATCH_DOWNLOADED;
+ }
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function DXS_FW_Select
+
+ \param pDev - pointer to DXS device structure
+ \param pPatch - pointer to data buffer (container)
+ \param nBytes - size of the buffer
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_FW_Select(DXS_DEVICE_t *pDev, uint8_t *pPatch, uint32_t nBytes)
+{
+ struct fw_container_header header;
+ struct fw_container_header *pHeaderNew = (struct fw_container_header*) pPatch;
+ uint32_t header_length = sizeof(header);
+ int32_t ret;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ int32_t i = 0;
+#endif
+
+ if ((pPatch == NULL) || (nBytes == 0) || (nBytes % 4) ||
+ (nBytes < header_length))
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ header = *pHeaderNew;
+
+ /* on LE systems - swap bytes in every 32-bit word
+ of the header */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ while (i < header_length/sizeof(uint32_t))
+ {
+ uint32_t *pWord = (uint32_t *)&header + i;
+
+ *pWord = DXS_SWAP32(*pWord);
+ i++;
+ }
+#endif
+
+ /* Process the container after verifying the header. */
+ if (header.nType == DXS_FW_TYPE_GLOBAL_V1 &&
+ header.nLength + header_length == nBytes &&
+ header.nMagic == DXS_FW_GLOBAL_MAGIC &&
+ header.nVersion != 0 &&
+ header.nTimestamp != 0 &&
+ header.nLength == header.nDxsV11FwLength +
+ header.nDxs1V12FwLength +
+ header.nDxs2V12FwLength)
+ {
+ uint8_t rom = 0, channels = 0;
+
+ DXS_DevInfoGet(pDev, &rom, &channels);
+
+ switch (rom)
+ {
+
+ case 1:
+ /* ROM 1.x.x */
+ if (header.nDxsV11FwLength > 0)
+ {
+ /* ROM 1.x.x devices are not allowed
+ for some types of DCDC */
+ if (pDev->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ DXS_RETURN(DXS_statusPramPatchDwldFail);
+ }
+
+ ret = dxs_fw_download(pDev,
+ pPatch + header_length + header.nDxsV11FwOffset,
+ header.nDxsV11FwLength);
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(ret);
+ }
+ }
+ break;
+
+ case 2:
+ /* ROM 2.x.x */
+ switch (channels)
+ {
+ case 1:
+ /* DXS 1-channel device */
+ if (header.nDxs1V12FwLength > 0)
+ {
+ ret = dxs_fw_download(pDev,
+ pPatch + header_length + header.nDxs1V12FwOffset,
+ header.nDxs1V12FwLength);
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(ret);
+ }
+ }
+ break;
+ case 2:
+ /* DXS 2-channel device */
+ if (header.nDxs2V12FwLength > 0)
+ {
+ ret = dxs_fw_download(pDev,
+ pPatch + header_length + header.nDxs2V12FwOffset,
+ header.nDxs2V12FwLength);
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(ret);
+ }
+ }
+ break;
+ default:
+ DXS_RETURN(DXS_statusPramPatchDwldFail);
+ break;
+ }
+ break;
+
+ default:
+ {
+ DXS_RETURN(DXS_statusPramPatchDwldFail);
+ }
+ }
+ }
+ else
+ {
+ /* provided buffer has no header */
+ DXS_RETURN(DXS_statusPramPatchInvalid);
+ }
+
+ return DXS_statusOk;
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_dwld.h b/marvell/services/dxslic/api_lib/src/dxs_dwld.h
new file mode 100644
index 0000000..8985a75
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_dwld.h
@@ -0,0 +1,39 @@
+#ifndef __DXS_DWLD_H__
+#define __DXS_DWLD_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_dwld.h
+ Download functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+extern int32_t DXS_FW_Select(DXS_DEVICE_t *pDev,
+ uint8_t *pPatch, uint32_t nBytes);
+
+
+#endif /* __DXS_DWLD_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_error.c b/marvell/services/dxslic/api_lib/src/dxs_error.c
new file mode 100644
index 0000000..9648c8b
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_error.c
@@ -0,0 +1,46 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_error.c
+ Implementation of error handling functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/* on success, "return" C statement is used */
+/* on error, RETURN_ERROR(code) macro is used */
+/* - add code, file and line info to the stack */
+
+
+
diff --git a/marvell/services/dxslic/api_lib/src/dxs_error.h b/marvell/services/dxslic/api_lib/src/dxs_error.h
new file mode 100644
index 0000000..72c2015
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_error.h
@@ -0,0 +1,55 @@
+#ifndef __DXS_ERROR_H__
+#define __DXS_ERROR_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_error.h
+ Error handling functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdio.h>
+#include <dxs_errno.h>
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+/* temporary */
+#define DXS_ERROR_PUSH(ret) \
+ do \
+ {\
+ fprintf(stderr, "ERROR code:%i (0x%02X) %s:%d\n", ret, ret, __FILE__, __LINE__); \
+ } while (0)
+
+#define DXS_RETURN(ret) \
+ do \
+ {\
+ if (ret != DXS_statusOk) { \
+ DXS_ERROR_PUSH(ret); \
+ } \
+ return ret; \
+ } while (0)
+
+/* TODO: fill in */
+#define DXS_ERROR_RESET
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+#endif /* __DXS_ERROR_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_event.c b/marvell/services/dxslic/api_lib/src/dxs_event.c
new file mode 100644
index 0000000..e62e332
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_event.c
@@ -0,0 +1,304 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_event.c
+ Implementation of event handling functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdio.h>
+#include <string.h>
+
+#include "dxs.h"
+#include "dxs_config.h"
+#include "dxs_mempool.h"
+#include "dxs_lib.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_wait.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_EVENTS_PER_DEVICE 10
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+/** memory placeholder for the events, all devices */
+static DXS_Event_t event_memory[DXS_MAX_DEVICES * DXS_EVENTS_PER_DEVICE];
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/**
+ Function dxs_event_bit_set
+
+ \param pCh - pointer to DXS channel structure
+ \param ev - event id
+
+ \return
+ none
+*/
+static void dxs_event_bit_set (DXS_CHANNEL_t *pCh, DXS_Event_id_t ev)
+{
+ /* the code assumes byte is 8 bits */
+ uint8_t bit = ev % (sizeof(uint32_t) << 3);
+ /* set event bit */
+ pCh->event_mask[ev/(sizeof(uint32_t) << 3)] |= (1UL << bit);
+}
+
+/**
+ Function dxs_event_bit_clear
+
+ \param pCh - pointer to DXS channel structure
+ \param ev - event id
+
+ \return
+ none
+*/
+static void dxs_event_bit_clear (DXS_CHANNEL_t *pCh, DXS_Event_id_t ev)
+{
+ /* the code assumes byte is 8 bits */
+ uint8_t bit = ev % (sizeof(uint32_t) << 3);
+ /* clear event bit */
+ pCh->event_mask[ev/(sizeof(uint32_t) << 3)] &= ~(1UL << bit);
+}
+
+/**
+ Function dxs_event_bit_test
+
+ \param pCh - pointer to DXS channel structure
+ \param ev - event id
+
+ \return
+ zero or non-zero value depending on bit setting
+*/
+static uint32_t dxs_event_bit_test (DXS_CHANNEL_t *pCh, DXS_Event_id_t ev)
+{
+ /* the code assumes byte is 8 bits */
+ uint8_t bit = ev % (sizeof(uint32_t) << 3);
+ return (pCh->event_mask[ev/(sizeof(uint32_t) << 3)] & (1UL << bit));
+}
+
+/**
+ Function dxs_event_pool_init
+
+ \param pDev - pointer to DXS device structure
+
+ \return
+ DXS_MPOOL_OK success
+ DXS_MPOOL_PARAMS invalid parameters
+ DXS_MPOOL_NOT_ENOUGH not enough memory for a pool
+ DXS_MPOOL_NO_FREE_POOLS cannot allocate a pool
+*/
+int32_t dxs_event_pool_init(DXS_DEVICE_t *pDev)
+{
+ if (pDev->nDevNum < DXS_MAX_DEVICES)
+ {
+ return mempool_init(&event_memory[pDev->nDevNum * DXS_EVENTS_PER_DEVICE],
+ DXS_EVENTS_PER_DEVICE * sizeof (DXS_Event_t),
+ DXS_EVENTS_PER_DEVICE, sizeof(DXS_Event_t),
+ &pDev->event_pool);
+ }
+ else
+ return DXS_statusInvalidParam;
+}
+
+/**
+ Function dxs_event_pool_exit
+
+ \param pDev - pointer to DXS device structure
+
+*/
+void dxs_event_pool_exit(DXS_DEVICE_t *pDev)
+{
+ return mempool_destroy(pDev->event_pool);
+}
+
+/**
+ Function dxs_event_get
+
+ \param pDev - pointer to DXS device structure
+ \param pEvent - pointer to event
+
+ \return
+ - the remaining element count of the fifo or DXS_statusError
+*/
+int32_t dxs_event_get(DXS_DEVICE_t *pDev, DXS_Event_t *pEvent)
+{
+ /*
+ 1) get one event buffer out of the event fifo and memcopy to pEvent
+ 2) return event buffer to the event buffer pool
+ 3) return the remaining element count of the fifo
+ */
+ uint32_t size;
+ DXS_Event_t *pEvt;
+
+ if (0 < fifo_count(pDev->event_queue))
+ {
+ if (DXS_FIFO_OK == fifo_get(pDev->event_queue, (void **)(&pEvt), &size))
+ {
+ *pEvent=*pEvt;
+ mempool_put(pDev->event_pool, (void *)pEvt);
+ }
+ else
+ {
+ return DXS_statusError;
+ }
+ }
+
+ return fifo_count(pDev->event_queue);
+}
+
+/**
+ Function DXS_EventDispatch
+
+ \param pDev - pointer to DXS device structure
+ \param pEvent - pointer to event
+
+*/
+void DXS_EventDispatch (DXS_DEVICE_t *pDev, DXS_Event_t *pEvent)
+{
+ DXS_Event_t *pEventBuffer;
+ DXS_CHANNEL_t *pCh = &pDev->pChannel[pEvent->ch];
+
+ /* check if the event is not masked */
+ if (!dxs_event_bit_test(pCh, pEvent->id))
+ return;
+
+ pEventBuffer = (DXS_Event_t *)mempool_get(pDev->event_pool);
+
+ if (pEventBuffer == NULL)
+ {
+ fprintf (stderr, "ERROR: Out of event memory. Event(id=%d) discarded.\n",
+ pEvent->id);
+ return;
+ }
+
+ /* copy event into the allocated buffer */
+ *pEventBuffer = *pEvent;
+
+ /* push the buffer to the event queue */
+ if (DXS_FIFO_OK == fifo_put(pDev->event_queue,
+ (void *)pEventBuffer, sizeof (*pEventBuffer)))
+ {
+ /* wake up user task */
+ dxs_wakeup(pDev);
+ }
+ else
+ {
+ fprintf (stderr, "ERROR: Cannot enqueue event(dev=%d ch=%d id=%d), discarding...\n",
+ pEventBuffer->dev, pEventBuffer->ch, pEventBuffer->id);
+ mempool_put(pDev->event_pool, (void *)pEventBuffer);
+ }
+}
+
+/**
+ Function DXS_EventEnable
+
+ \param pCh - pointer to DXS channel structure
+ \param ev - event id
+
+ \return
+ value of \ref DXS_status_t
+*/
+int32_t DXS_EventEnable(DXS_CHANNEL_t *pCh, DXS_Event_id_t ev)
+{
+ if (ev <= DXS_EVENT_NONE || ev >= DXS_EVENT_MAX)
+ {
+ DXS_RETURN(DXS_statusEventEnableNotAllowed);
+ }
+ dxs_event_bit_set(pCh, ev);
+ return DXS_statusOk;
+}
+
+/**
+ Function DXS_EventDisable
+
+ \param pCh - pointer to DXS channel structure
+ \param ev - event id
+
+ \return
+ value of \ref DXS_status_t
+*/
+int32_t DXS_EventDisable(DXS_CHANNEL_t *pCh, DXS_Event_id_t ev)
+{
+ if (ev <= DXS_EVENT_NONE || ev >= DXS_EVENT_MAX ||
+ /* error events cannot be disabled */
+ ev == DXS_EVENT_OVERTEMP || ev == DXS_EVENT_OVERTEMP_END ||
+ ev == DXS_EVENT_GROUND_FAULT || ev == DXS_EVENT_GROUND_FAULT_END ||
+ ev == DXS_EVENT_FAULT_FW_WATCHDOG ||
+ ev == DXS_EVENT_NLT_ABORT ||
+ ev == DXS_EVENT_DEBUG_CERR ||
+ ev == DXS_EVENT_CID_BUF_UNDERFLOW ||
+ ev == DXS_EVENT_CID_SEQ_ERROR)
+ {
+ DXS_RETURN(DXS_statusEventDisableNotAllowed);
+ }
+ dxs_event_bit_clear(pCh, ev);
+ return DXS_statusOk;
+}
+
+/**
+ Function DXS_EventMaskSetDefault
+
+ \param pCh - pointer to DXS channel structure
+
+ \return none
+*/
+void DXS_EventMaskSetDefault(DXS_CHANNEL_t *pCh)
+{
+ /* events enabled by default: */
+ dxs_event_bit_set(pCh, DXS_EVENT_FXS_ONHOOK);
+ dxs_event_bit_set(pCh, DXS_EVENT_FXS_OFFHOOK);
+ dxs_event_bit_set(pCh, DXS_EVENT_FXS_FLASH);
+ dxs_event_bit_set(pCh, DXS_EVENT_NLT_END);
+ dxs_event_bit_set(pCh, DXS_EVENT_NLT_ABORT);
+ dxs_event_bit_set(pCh, DXS_EVENT_PULSE_DIGIT);
+ dxs_event_bit_set(pCh, DXS_EVENT_PULSE_START);
+ dxs_event_bit_set(pCh, DXS_EVENT_DTMF_DIGIT);
+ dxs_event_bit_set(pCh, DXS_EVENT_CALIBRATION_END);
+ dxs_event_bit_set(pCh, DXS_EVENT_METERING_END);
+ dxs_event_bit_set(pCh, DXS_EVENT_OVERTEMP);
+ dxs_event_bit_set(pCh, DXS_EVENT_OVERTEMP_END);
+ dxs_event_bit_set(pCh, DXS_EVENT_GROUND_FAULT);
+ dxs_event_bit_set(pCh, DXS_EVENT_GROUND_FAULT_END);
+ dxs_event_bit_set(pCh, DXS_EVENT_TONE_DET_CPT);
+ dxs_event_bit_set(pCh, DXS_EVENT_TONE_DET_CPT_END);
+ dxs_event_bit_set(pCh, DXS_EVENT_DEBUG_CERR);
+ dxs_event_bit_set(pCh, DXS_EVENT_CID_REQ_DATA);
+ dxs_event_bit_set(pCh, DXS_EVENT_CID_BUF_UNDERFLOW);
+ dxs_event_bit_set(pCh, DXS_EVENT_CID_END);
+ dxs_event_bit_set(pCh, DXS_EVENT_CID_SEQ_END);
+ dxs_event_bit_set(pCh, DXS_EVENT_CID_SEQ_ERROR);
+ dxs_event_bit_set(pCh, DXS_EVENT_GROUND_KEY);
+ dxs_event_bit_set(pCh, DXS_EVENT_GROUND_KEY_END);
+ dxs_event_bit_set(pCh, DXS_EVENT_FAULT_FW_WATCHDOG);
+ dxs_event_bit_set(pCh, DXS_EVENT_T2G_TIMER_EXPIRED);
+ /* events not enabled by default: */
+#if 0
+ dxs_event_bit_set(pCh, DXS_EVENT_FXS_RAW_ONHOOK);
+ dxs_event_bit_set(pCh, DXS_EVENT_FXS_RAW_OFFHOOK);
+#endif
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_event.h b/marvell/services/dxslic/api_lib/src/dxs_event.h
new file mode 100644
index 0000000..1b06fb6
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_event.h
@@ -0,0 +1,43 @@
+#ifndef __DXS_EVENT_H__
+#define __DXS_EVENT_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_event.h
+ Event handling functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+extern int32_t dxs_event_pool_init(DXS_DEVICE_t *pDev);
+extern int32_t dxs_event_get(DXS_DEVICE_t *pDev, DXS_Event_t *pEvent);
+
+extern void DXS_EventDispatch (DXS_DEVICE_t *pDev, DXS_Event_t *pEvent);
+extern void dxs_event_pool_exit(DXS_DEVICE_t *pDev);
+extern int32_t DXS_EventEnable(DXS_CHANNEL_t *pCh, DXS_Event_id_t ev);
+extern int32_t DXS_EventDisable(DXS_CHANNEL_t *pCh, DXS_Event_id_t ev);
+extern void DXS_EventMaskSetDefault(DXS_CHANNEL_t *pCh);
+#endif /* __DXS_EVENT_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_fifo.c b/marvell/services/dxslic/api_lib/src/dxs_fifo.c
new file mode 100644
index 0000000..d474ff6
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_fifo.c
@@ -0,0 +1,229 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_fifo.c
+ Implementation of DxS fifo functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+
+#include "dxs_config.h"
+#include "dxs_fifo.h"
+#include "dxs_error.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+/* two fifos per device:
+ one for messages, one for command outbox data */
+#define FIFOS_PER_DEVICE 2
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+/** placeholder for the fifos */
+FIFO_t dxs_fifos[DXS_MAX_DEVICES * FIFOS_PER_DEVICE];
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+/**
+ Function fifo_init
+
+ \param elements - elements
+
+ \return
+ - FIFO_t
+*/
+FIFO_t* fifo_init (uint32_t elements)
+{
+ FIFO_t *p;
+ int idx;
+
+ for (idx=0; idx<(DXS_MAX_DEVICES * FIFOS_PER_DEVICE); idx++)
+ {
+ p = &dxs_fifos[idx];
+ if (!p->in_use)
+ break;
+ }
+ if (idx == (DXS_MAX_DEVICES * FIFOS_PER_DEVICE))
+ {
+ return NULL;
+ }
+
+ p->magic = DXS_FIFO_MAGIC_CODE;
+
+ if (elements > MAX_FIFO_SIZE)
+ elements = MAX_FIFO_SIZE;
+
+ p->fifo_size = elements;
+ p->count = p->wr_idx = p->rd_idx = 0;
+
+ pthread_mutex_init(&p->mtx, NULL);
+
+ p->in_use = 1;
+
+ return p;
+}
+
+/**
+ Function fifo_destroy
+
+ \param fifo - pointer to FIFO_t
+
+*/
+void fifo_destroy (FIFO_t *fifo)
+{
+ int err;
+ err = pthread_mutex_unlock(&fifo->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ err = pthread_mutex_destroy(&fifo->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ fifo->in_use = 0;
+ fifo->magic = 0;
+}
+
+/**
+ Function fifo_flush
+
+ \param fifo - pointer to FIFO_t
+
+*/
+void fifo_flush (FIFO_t *fifo)
+{
+ int err;
+ err = pthread_mutex_lock (&fifo->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ fifo->count = fifo->wr_idx = fifo->rd_idx = 0;
+
+ err = pthread_mutex_unlock (&fifo->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+}
+
+/**
+ Function fifo_count
+
+ \param fifo - pointer to FIFO_t
+
+ \return
+ - uint32_t count
+*/
+uint32_t fifo_count (FIFO_t *fifo)
+{
+ return fifo->count;
+}
+
+/**
+ Function fifo_put
+
+ \param fifo - pointer to FIFO_t
+ \param data - pointer to data
+ \param size - size
+
+ \return
+ DXS_FIFO_INV
+ DXS_FIFO_FULL
+ DXS_FIFO_OK
+*/
+int32_t fifo_put (FIFO_t *fifo, void *data, uint32_t size)
+{
+ FIFO_Elem_t *p;
+ int err;
+
+ if (fifo->magic != DXS_FIFO_MAGIC_CODE)
+ return DXS_FIFO_INV;
+
+ if (fifo->count == fifo->fifo_size)
+ return DXS_FIFO_FULL;
+
+ err = pthread_mutex_lock (&fifo->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ p = &fifo->elem[fifo->wr_idx];
+
+ p->data = data;
+ p->size = size;
+ fifo->count++;
+
+ if (++fifo->wr_idx == fifo->fifo_size)
+ fifo->wr_idx = 0;
+
+ err = pthread_mutex_unlock (&fifo->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ return DXS_FIFO_OK;
+}
+
+/**
+ Function fifo_get
+
+ \param fifo - pointer to FIFO_t
+ \param data - pointer to data
+ \param size - pointer size
+
+ \return
+ DXS_FIFO_INV
+ DXS_FIFO_EMPTY
+ DXS_FIFO_OK
+*/
+int32_t fifo_get (FIFO_t *fifo, void **data, uint32_t *size)
+{
+ FIFO_Elem_t *p;
+ int err;
+
+ if (fifo->magic != DXS_FIFO_MAGIC_CODE)
+ return DXS_FIFO_INV;
+
+ if (fifo->count == 0)
+ return DXS_FIFO_EMPTY;
+
+ err = pthread_mutex_lock (&fifo->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ p = &fifo->elem[fifo->rd_idx];
+
+ *data = p->data;
+ *size = p->size;
+ fifo->count--;
+
+ if (++fifo->rd_idx == fifo->fifo_size)
+ fifo->rd_idx = 0;
+
+ err = pthread_mutex_unlock (&fifo->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ return DXS_FIFO_OK;
+}
+
diff --git a/marvell/services/dxslic/api_lib/src/dxs_fifo.h b/marvell/services/dxslic/api_lib/src/dxs_fifo.h
new file mode 100644
index 0000000..4a62d40
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_fifo.h
@@ -0,0 +1,77 @@
+#ifndef __DXS_FIFO_H__
+#define __DXS_FIFO_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_fifo.h
+ DxS fifo declarations.
+*/
+
+/*
+| header | elem 0 | elem 1 | elem 2 | ...
++------------+-------+--------+--------+---+------+---+------+---+------+-------
+| magic code | count | wr_idx | rd_idx | p | size | p | size | p | size | ...
++------------+-------+--------+--------+-+-+------+-+-+------+-+-+------+-------
+ | | |
+ V V V
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define MAX_FIFO_SIZE 200 /* in elements */
+#define DXS_FIFO_MAGIC_CODE 0x41464946
+/* return codes */
+#define DXS_FIFO_OK 0
+#define DXS_FIFO_FULL (-1)
+#define DXS_FIFO_EMPTY (-2)
+#define DXS_FIFO_INV (-3)
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+/** FIFO_Elem_t */
+typedef struct
+{
+ void *data;
+ uint32_t size;
+} FIFO_Elem_t;
+
+/** FIFO_t */
+typedef struct
+{
+ uint32_t magic;
+ uint32_t in_use;
+ uint32_t fifo_size;
+ uint32_t count;
+ uint32_t wr_idx;
+ uint32_t rd_idx;
+ pthread_mutex_t mtx;
+ FIFO_Elem_t elem[MAX_FIFO_SIZE];
+} FIFO_t;
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+FIFO_t* fifo_init (uint32_t elememts);
+void fifo_flush (FIFO_t *fifo);
+uint32_t fifo_count (FIFO_t *fifo);
+int32_t fifo_put (FIFO_t *fifo, void *data, uint32_t size);
+int32_t fifo_get (FIFO_t *fifo, void **data, uint32_t *size);
+
+extern void fifo_destroy (FIFO_t *fifo);
+
+#endif /* __DXS_FIFO_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_fw_cmd.h b/marvell/services/dxslic/api_lib/src/dxs_fw_cmd.h
new file mode 100644
index 0000000..8c2d1ab
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_fw_cmd.h
@@ -0,0 +1,576 @@
+#ifndef __DXS_FW_CMD_H__
+#define __DXS_FW_CMD_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_fw_cmd.h
+ This file contains the type definitions specific to the DXS
+ firmware commands.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_mbx.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+/** Command header definition (big endian) */
+#define CMD_HEAD_BE \
+ /* Read/Write */ \
+ uint32_t RW : 1; \
+ /* Reserved */ \
+ uint32_t Res00 : 2; \
+ /* Command */ \
+ uint32_t CMD : 5; \
+ /* Reserved */ \
+ uint32_t Res01 : 4; \
+ /* Channel */ \
+ uint32_t CHAN : 4; \
+ /* Module */ \
+ uint32_t MOD : 3; \
+ /* Command Sub-Mode */ \
+ uint32_t ECMD : 5; \
+ /* Length of Message */ \
+ uint32_t LENGTH : 8
+
+/** Command header definition (little endian) */
+#define CMD_HEAD_LE \
+ /* Length of Message */ \
+ uint32_t LENGTH : 8; \
+ /* Command Sub-Mode */ \
+ uint32_t ECMD : 5; \
+ /* Module */ \
+ uint32_t MOD : 3; \
+ /* Channel */ \
+ uint32_t CHAN : 4; \
+ /* Reserved */ \
+ uint32_t Res01 : 4; \
+ /* Command */ \
+ uint32_t CMD : 5; \
+ /* Reserved */ \
+ uint32_t Res00 : 2; \
+ /* Read/Write */ \
+ uint32_t RW : 1
+
+#define CMD_EOP 6
+#define CMD_SDD 1
+
+#define MOD_EOP_GPIO 0
+#define MOD_SDD_PCM 0
+#define MOD_SIG_GEN 3
+#define MOD_SIG_DET 6
+#define MOD_SYS 7
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+/** DXS firmware command header type. */
+struct DXS_FW_Cmd_Header
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+#else
+ CMD_HEAD_LE;
+#endif
+} __attribute__ ((packed));
+
+/** This structure contains data specific to BBD basic config fw command. */
+struct DXS_FW_SDD_BasicConfig
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Reserved */
+ uint32_t Res01 : 4;
+ /* DUP Time for Hook Debouncing in ACT Mode */
+ uint32_t ActiveDup : 4;
+ /* DUP Time for Hook Debouncing in GS Mode */
+ uint32_t GsDup : 4;
+ /* Reserved */
+ uint32_t Res02 : 4;
+ /* DUP Time for Ground Key Debouncing */
+ uint32_t GndkDup : 4;
+ /* Emergency Shut Down Debounce Time */
+ uint32_t EsdDup : 4;
+ /* Reserved */
+ uint32_t Res03 : 2;
+ /* Automatic Sense Bias Enable */
+ uint32_t AutoBiasEn : 1;
+ /* Reserved */
+ uint32_t Res04 : 5;
+ /* Reserved */
+ uint32_t Res05 : 4;
+ /* DC/DC Overhead Voltage */
+ uint32_t DcDcOvh : 4;
+ /* Reserved */
+ uint32_t Res06 : 5;
+ /* Standby Voltage */
+ uint32_t StbyVolt : 2;
+ /* Reserved */
+ uint32_t Res07 : 1;
+ /* TTX Burst Length */
+ uint32_t TtxBurstLength : 16;
+ /* Current gain for PID regulator */
+ uint32_t DcPidGain : 16;
+ /* On-Hook Threshold in ACT Mode */
+ uint32_t ActOnhookThresh : 16;
+ /* Off-Hook Threshold in ACT Mode */
+ uint32_t ActOffhookThresh : 16;
+ /* Reserved */
+ uint32_t Res08 : 16;
+ /* Open Loop Voltage Limit */
+ uint32_t VoltageLimit : 16;
+ /* Closed Loop Current Limit */
+ uint32_t CurrentLimit : 16;
+#else
+ /* Reserved */
+ uint32_t Res04 : 5;
+ /* Automatic Sense Bias Enable */
+ uint32_t AutoBiasEn : 1;
+ /* Reserved */
+ uint32_t Res03 : 2;
+ /* Emergency Shut Down Debounce Time */
+ uint32_t EsdDup : 4;
+ /* DUP Time for Ground Key Debouncing */
+ uint32_t GndkDup : 4;
+ /* Reserved */
+ uint32_t Res02 : 4;
+ /* DUP Time for Hook Debouncing in GS Mode */
+ uint32_t GsDup : 4;
+ /* DUP Time for Hook Debouncing in ACT Mode */
+ uint32_t ActiveDup : 4;
+ /* Reserved */
+ uint32_t Res01 : 4;
+ /* TTX Burst Length */
+ uint32_t TtxBurstLength : 16;
+ /* Reserved */
+ uint32_t Res07 : 1;
+ /* Standby Voltage */
+ uint32_t StbyVolt : 2;
+ /* Reserved */
+ uint32_t Res06 : 5;
+ /* DC/DC Overhead Voltage */
+ uint32_t DcDcOvh : 4;
+ /* Reserved */
+ uint32_t Res05 : 4;
+ /* On-Hook Threshold in ACT Mode */
+ uint32_t ActOnhookThresh : 16;
+ /* Current gain for PID regulator */
+ uint32_t DcPidGain : 16;
+ /* Reserved */
+ uint32_t Res08 : 16;
+ /* Off-Hook Threshold in ACT Mode */
+ uint32_t ActOffhookThresh : 16;
+ /* Closed Loop Current Limit */
+ uint32_t CurrentLimit : 16;
+ /* Open Loop Voltage Limit */
+ uint32_t VoltageLimit : 16;
+#endif
+} __attribute__ ((packed));
+
+/** This structure contains data specific to
+ SDD_BasicConfig firmware command, IFB12CH8 family. */
+struct DXS_FW_DX8_SDD_BasicConfig
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Reserved */
+ uint32_t Res00 : 4;
+ /* DUP Time for Hook Debouncing in ACT Mode */
+ uint32_t ActiveDup : 4;
+ /* DUP Time for Hook Debouncing in GS Mode */
+ uint32_t GsDup : 4;
+ /* DUP Time for Hook Debouncing in Standby Mode */
+ uint32_t StbyDup : 4;
+ /* DUP Time for Ground Key Debouncing */
+ uint32_t GndkDup : 4;
+ /* Emergency Shut Down Debounce Time */
+ uint32_t EsdDup : 4;
+ /* Reserved */
+ uint32_t Res01 : 2;
+ /* Automatic Sense Bias Enable */
+ uint32_t AutoBiasEn : 1;
+ /* Reserved */
+ uint32_t Res02 : 5;
+ /* Standby Offhook Overhead Voltage */
+ uint32_t StbyOffhOvh : 4;
+ /* DC/DC Overhead Voltage */
+ uint32_t DcDcOvh : 4;
+ /* Reserved */
+ uint32_t Res03 : 8;
+ /* TTX Burst Length (not supported by DXC) */
+ uint32_t TtxBurstLength : 16;
+ /* Current gain for PID regulator */
+ uint32_t DcPidGain : 16;
+ /* On-Hook Threshold in ACT Mode */
+ uint32_t ActOnhookThresh : 16;
+ /* Off-Hook Threshold in ACT Mode */
+ uint32_t ActOffhookThresh : 16;
+ /* Voltage Threshold for Battery Switch */
+ uint32_t VoltageThresh : 16;
+ /* Open Loop Voltage Limit */
+ uint32_t VoltageLimit : 16;
+ /* Closed Loop Current Limit */
+ uint32_t CurrentLimit : 16;
+#else
+ /* Reserved */
+ uint32_t Res02 : 5;
+ /* Automatic Sense Bias Enable */
+ uint32_t AutoBiasEn : 1;
+ /* Reserved */
+ uint32_t Res01 : 2;
+ /* Emergency Shut Down Debounce Time */
+ uint32_t EsdDup : 4;
+ /* DUP Time for Ground Key Debouncing */
+ uint32_t GndkDup : 4;
+ /* DUP Time for Hook Debouncing in Standby Mode */
+ uint32_t StbyDup : 4;
+ /* DUP Time for Hook Debouncing in GS Mode */
+ uint32_t GsDup : 4;
+ /* DUP Time for Hook Debouncing in ACT Mode */
+ uint32_t ActiveDup : 4;
+ /* Reserved */
+ uint32_t Res00 : 4;
+ /* TTX Burst Length (not supported by DXC) */
+ uint32_t TtxBurstLength : 16;
+ /* Reserved */
+ uint32_t Res03 : 8;
+ /* DC/DC Overhead Voltage */
+ uint32_t DcDcOvh : 4;
+ /* Standby Offhook Overhead Voltage */
+ uint32_t StbyOffhOvh : 4;
+ /* On-Hook Threshold in ACT Mode */
+ uint32_t ActOnhookThresh : 16;
+ /* Current gain for PID regulator */
+ uint32_t DcPidGain : 16;
+ /* Voltage Threshold for Battery Switch */
+ uint32_t VoltageThresh : 16;
+ /* Off-Hook Threshold in ACT Mode */
+ uint32_t ActOffhookThresh : 16;
+ /* Closed Loop Current Limit */
+ uint32_t CurrentLimit : 16;
+ /* Open Loop Voltage Limit */
+ uint32_t VoltageLimit : 16;
+#endif
+} __attribute__ ((packed));
+
+struct DXS_basicConfigData{
+ uint32_t data_u32[sizeof(struct DXS_FW_SDD_BasicConfig)/sizeof(uint32_t)];
+} __attribute__ ((packed));
+
+/** Union for accessing data as uint32_t. */
+union DXS_FW_SDD_BasicConfig_u
+{
+ struct DXS_basicConfigData bc_data;
+ struct DXS_FW_SDD_BasicConfig fwmsg;
+ struct DXS_FW_DX8_SDD_BasicConfig dx8fwmsg;
+};
+
+/** This structure contains data specific to ring config firmware command. */
+struct DXS_FW_SDD_RingConfig
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Reserved */
+ uint32_t Res02 : 2;
+ /* Ring Trip Type */
+ uint32_t RingTripType : 2;
+ /* Wave Form of Ringing Signal */
+ uint32_t WaveForm : 1;
+ /* Ring Crest Factor */
+ uint32_t CrestFact : 3;
+ /* Reserved */
+ uint32_t Res03 : 8;
+ /* Ringing Frequency */
+ uint32_t Frequency : 16;
+ /* Ringing Amplitude */
+ uint32_t Amplitude : 16;
+ /* Ringing Hook Threshold */
+ uint32_t Thresh : 16;
+ /* Ringing DC Offset */
+ uint32_t DcOffset : 16;
+ /* Maximum Ring Current */
+ uint32_t Imax : 16;
+ /* Ringing Regulation Coefficient */
+ uint32_t RegCoeff : 16;
+ /* Minimum Ringing Voltage (peak) */
+ uint32_t Vmin : 16;
+ /* Reserved */
+ uint32_t Res04 : 16;
+ /* Fast Hook Threshold */
+ uint32_t FastThresh : 16;
+#else
+ /* Ringing Frequency */
+ uint32_t Frequency : 16;
+ /* Reserved */
+ uint32_t Res03 : 8;
+ /* Ring Crest Factor */
+ uint32_t CrestFact : 3;
+ /* Wave Form of Ringing Signal */
+ uint32_t WaveForm : 1;
+ /* Ring Trip Type */
+ uint32_t RingTripType : 2;
+ /* Reserved */
+ uint32_t Res02 : 2;
+ /* Ringing Hook Threshold */
+ uint32_t Thresh : 16;
+ /* Ringing Amplitude */
+ uint32_t Amplitude : 16;
+ /* Maximum Ring Current */
+ uint32_t Imax : 16;
+ /* Ringing DC Offset */
+ uint32_t DcOffset : 16;
+ /* Minimum Ringing Voltage (peak) */
+ uint32_t Vmin : 16;
+ /* Ringing Regulation Coefficient */
+ uint32_t RegCoeff : 16;
+ /* Fast Hook Threshold */
+ uint32_t FastThresh : 16;
+ /* Reserved */
+ uint32_t Res04 : 16;
+#endif
+} __attribute__ ((packed));
+
+
+/** Union for acccessing data as uint32_t. */
+union DXS_FW_SDD_RingConfig_u
+{
+ uint32_t u32[sizeof(struct DXS_FW_SDD_RingConfig)/sizeof(uint32_t)];
+ struct DXS_FW_SDD_RingConfig fwmsg;
+};
+
+/** This structure contains data specific to DC/DC config firmware command. */
+struct DXS_FW_SDD_DcDcConfig
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Reserved */
+ uint32_t Res00 : 4;
+ /* DC/DC Capacitance */
+ uint32_t DcDcCap : 4;
+ /* DC/DC Hardware Option */
+ uint32_t DcDcHw : 4;
+ /* Reserved */
+ uint32_t Res01 : 1;
+ /* DC/DC Switch Output Enable */
+ uint32_t DcDcSwEn : 1;
+ /* Combined Low Power Mode */
+ uint32_t CombLP : 1;
+ /* DC/DC Switch Output Inverted */
+ uint32_t DcDcSwInv : 1;
+ /* Power Value for Boost Calculation */
+ uint32_t P1 : 16;
+ /* DC/DC Maximum On Time of Switching Transistor */
+ uint32_t MaxOnTime : 8;
+ /* Maximum Frequency of DC/DC Converter */
+ uint32_t MaxFreq : 8;
+ /* DC/DC On Time of Switching Transistor in STANDBY Mode */
+ uint32_t OnTimeStby : 8;
+ /* Maximum Frequency of DC/DC Converter in STANDBY Mode */
+ uint32_t MaxFreqStby : 8;
+#else
+ /* Power Value for Boost Calculation */
+ uint32_t P1 : 16;
+ /* DC/DC Switch Output Inverted */
+ uint32_t DcDcSwInv : 1;
+ /* Combined Low Power Mode */
+ uint32_t CombLP : 1;
+ /* DC/DC Switch Output Enable */
+ uint32_t DcDcSwEn : 1;
+ /* Reserved */
+ uint32_t Res01 : 1;
+ /* DC/DC Hardware Option */
+ uint32_t DcDcHw : 4;
+ /* DC/DC Capacitance */
+ uint32_t DcDcCap : 4;
+ /* Reserved */
+ uint32_t Res00 : 4;
+ /* Maximum Frequency of DC/DC Converter in STANDBY Mode */
+ uint32_t MaxFreqStby : 8;
+ /* DC/DC On Time of Switching Transistor in STANDBY Mode */
+ uint32_t OnTimeStby : 8;
+ /* Maximum Frequency of DC/DC Converter */
+ uint32_t MaxFreq : 8;
+ /* DC/DC Maximum On Time of Switching Transistor */
+ uint32_t MaxOnTime : 8;
+#endif
+} __attribute__ ((packed));
+
+/** This structure contains data specific to
+ DC/DC config firmware command, IFB12CH8 family. */
+struct DXS_FW_DX8_SDD_DcDcConfig
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* DC/DC Minimum On Time of Switching Transistor */
+ uint32_t MinOnTime : 8;
+ /* Reserved */
+ uint32_t Res00 : 5;
+ /* DC/DC Switch Output Enable */
+ uint32_t DcDcSwEn : 1;
+ /* Reserved */
+ uint32_t Res01 : 1;
+ /* DC/DC Switch Output Inverted */
+ uint32_t DcDcSwInv : 1;
+ /* Reserved */
+ uint32_t Res02 : 16;
+ /* DC/DC Maximum On Time of Switching Transistor */
+ uint32_t MaxOnTime : 8;
+ /* Maximum Frequency of DC/DC Converter */
+ uint32_t MaxFreq : 8;
+ /* DC/DC Voltage */
+ uint32_t DcDcVoltage : 16;
+#else
+ /* Reserved */
+ uint32_t Res02 : 16;
+ /* DC/DC Switch Output Inverted */
+ uint32_t DcDcSwInv : 1;
+ /* Reserved */
+ uint32_t Res01 : 1;
+ /* DC/DC Switch Output Enable */
+ uint32_t DcDcSwEn : 1;
+ /* Reserved */
+ uint32_t Res00 : 5;
+ /* DC/DC Minimum On Time of Switching Transistor */
+ uint32_t MinOnTime : 8;
+ /* DC/DC Voltage */
+ uint32_t DcDcVoltage : 16;
+ /* Maximum Frequency of DC/DC Converter */
+ uint32_t MaxFreq : 8;
+ /* DC/DC Maximum On Time of Switching Transistor */
+ uint32_t MaxOnTime : 8;
+#endif
+} __attribute__ ((packed));
+
+struct DXS_DcDcConfigData
+{
+ uint32_t data_u32[sizeof(struct DXS_FW_SDD_DcDcConfig)/sizeof(uint32_t)];
+} __attribute__ ((packed));
+
+/** Union for acccessing data as uint32_t. */
+union DXS_FW_SDD_DcDcConfig_u
+{
+ struct DXS_DcDcConfigData dcdc_data;
+ struct DXS_FW_SDD_DcDcConfig fwmsg;
+ struct DXS_FW_DX8_SDD_DcDcConfig dx8fwmsg;
+};
+
+/** This structure contains data specific to MWL config firmware command. */
+struct DXS_FW_SDD_MwlConfig
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Message Waiting Lamp Voltage */
+ uint32_t Voltage : 16;
+ /* Message Waiting Hook Threshold */
+ uint32_t Thresh : 16;
+ /* Message Waiting Slope */
+ uint32_t Slope : 16;
+ /* Message Waiting On-time (Lamp ON) */
+ uint32_t OnTime : 8;
+ /* Message Waiting Off-time (Lamp OFF) */
+ uint32_t OffTime :8;
+#else
+ /* Message Waiting Hook Threshold */
+ uint32_t Thresh : 16;
+ /* Message Waiting Lamp Voltage */
+ uint32_t Voltage : 16;
+ /* Message Waiting Off-time (Lamp OFF) */
+ uint32_t OffTime :8;
+ /* Message Waiting On-time (Lamp ON) */
+ uint32_t OnTime : 8;
+ /* Message Waiting Slope */
+ uint32_t Slope : 16;
+#endif
+} __attribute__ ((packed));
+
+/** Union for acccessing data as uint32_t. */
+union DXS_FW_SDD_MwlConfig_u
+{
+ uint32_t u32[sizeof(struct DXS_FW_SDD_MwlConfig)/sizeof(uint32_t)];
+ struct DXS_FW_SDD_MwlConfig fwmsg;
+};
+
+/** This structure contains data specific to UTD coefficients fw command. */
+struct DXS_FW_SIG_UtdCoeff
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Bandwidth */
+ uint32_t BW : 16;
+ /* Center Frequency */
+ uint32_t CF : 16;
+ /* Noise Level */
+ uint32_t NLEV : 16;
+ /* Signal Level */
+ uint32_t SLEV : 16;
+ /* Delta Level */
+ uint32_t DLEV : 16;
+ /* Low Pass Coefficient */
+ uint32_t LPCOEFF : 16;
+ /* Data Upstream Persistence Counter */
+ uint32_t DUP : 8;
+ /* Reserved */
+ uint32_t Res02 : 24;
+#else
+ /* Center Frequency */
+ uint32_t CF : 16;
+ /* Bandwidth */
+ uint32_t BW : 16;
+ /* Signal Level */
+ uint32_t SLEV : 16;
+ /* Noise Level */
+ uint32_t NLEV : 16;
+ /* Low Pass Coefficient */
+ uint32_t LPCOEFF : 16;
+ /* Delta Level */
+ uint32_t DLEV : 16;
+ /* Reserved */
+ uint32_t Res02 : 24;
+ /* Data Upstream Persistence Counter */
+ uint32_t DUP : 8;
+#endif
+} __attribute__ ((packed));
+
+/** Union for acccessing data as uint32_t. */
+union DXS_FW_SIG_UtdCoeff_u
+{
+ uint32_t u32[sizeof(struct DXS_FW_SIG_UtdCoeff)/sizeof(uint32_t)];
+ struct DXS_FW_SIG_UtdCoeff fwmsg;
+};
+#define COEF_SIZE_UINT_32 6
+/** This structure contains data specific to SDD coefficients fw command. */
+struct DXS_FW_SDD_Coeff
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Destination */
+ uint32_t Dest : 1;
+ /* Offset of Coefficient Block */
+ uint32_t BlockOffset : 10;
+ /* Length of Coefficient Block */
+ uint32_t BlockLength : 5;
+ /* Coefficient 0 */
+ uint32_t Coefficient0 : 16;
+#else
+ /* Coefficient 0 */
+ uint32_t Coefficient0 : 16;
+ /* Length of Coefficient Block */
+ uint32_t BlockLength : 5;
+ /* Offset of Coefficient Block */
+ uint32_t BlockOffset : 10;
+ /* Destination */
+ uint32_t Dest : 1;
+#endif
+ union
+ {
+ uint32_t Coefficients_32[COEF_SIZE_UINT_32];
+ };
+} __attribute__ ((packed));
+#define DXS_FW_SDD_Coeff_ECMD 13
+#define DXS_FW_SDD_Coeff_MAXLENGTH 28
+
+
+#endif /* __DXS_FW_CMD_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_gpio.c b/marvell/services/dxslic/api_lib/src/dxs_gpio.c
new file mode 100644
index 0000000..e33b77e
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_gpio.c
@@ -0,0 +1,324 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_gpio.c
+ Implementation of GPIO functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_config.h"
+
+#ifdef DXS_FEAT_GPIO
+
+#include "dxs.h"
+#include "dxs_fw_cmd.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+/** Data structure for GPIO configuration firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Reserved */
+ uint32_t Res02 : 4;
+ /** Enable GPIO Pull-up Resistor */
+ uint32_t GPIO_PULL_UP : 4;
+ /** Reserved */
+ uint32_t Res03 : 4;
+ /** Direction of GPIO Bits */
+ uint32_t GPIO_DIR : 4;
+ /** Reserved */
+ uint32_t Res04 : 16;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res04 : 16;
+ /** Direction of GPIO Bits */
+ uint32_t GPIO_DIR : 4;
+ /** Reserved */
+ uint32_t Res03 : 4;
+ /** Enable GPIO Pull-up Resistor */
+ uint32_t GPIO_PULL_UP : 4;
+ /** Reserved */
+ uint32_t Res02 : 4;
+#endif
+} __attribute__ ((packed)) DXS_FW_GPIO_Config_t;
+#define DXS_FW_GPIO_Config_ECMD 2
+#define DXS_FW_GPIO_Config_LENGTH 4
+
+/** Data structure for GPIO control firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Reserved */
+ uint32_t Res02 : 4;
+ /** Write Mask for GPIO */
+ uint32_t GPIO_WR_MSK : 4;
+ /** Reserved */
+ uint32_t Res03 : 4;
+ /** Value of GPIO Bits */
+ uint32_t GPIO_VAL : 4;
+ /** Reserved */
+ uint32_t Res04 : 16;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res04 : 16;
+ /** Value of GPIO Bits */
+ uint32_t GPIO_VAL : 4;
+ /** Reserved */
+ uint32_t Res03 : 4;
+ /** Write Mask for GPIO */
+ uint32_t GPIO_WR_MSK : 4;
+ /** Reserved */
+ uint32_t Res02 : 4;
+#endif
+} __attribute__ ((packed)) DXS_FW_GPIO_Data_t;
+#define DXS_FW_GPIO_Data_ECMD 3
+#define DXS_FW_GPIO_Data_LENGTH 4
+
+/** GPIO device resource structure */
+typedef struct
+{
+ /** status flag */
+ uint32_t flag;
+#define GPIO_DEV_INITIALIZED 0x00000001
+#define GPIO_CTRL_CONFIGURED 0x80000000
+ /** DXS_FW_GPIO_Config command */
+ DXS_FW_GPIO_Config_t cfg;
+ /** DXS_FW_GPIO_Data command */
+ DXS_FW_GPIO_Data_t data;
+} DXS_GPIO_Dev_Resource_t;
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+static DXS_GPIO_Dev_Resource_t gpio_devs[DXS_MAX_DEVICES] = {0};
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+/**
+ Function to initialize GPIO device resource
+
+ \param devnum - device number
+
+*/
+void *DXS_GPIO_DevInit(uint8_t devnum)
+{
+ DXS_GPIO_Dev_Resource_t *p;
+
+ if (devnum >= DXS_MAX_DEVICES)
+ return (void *)NULL;
+
+ p = &gpio_devs[devnum];
+
+ p->flag = 0;
+
+ p->cfg.CMD = CMD_EOP;
+ p->cfg.MOD = MOD_EOP_GPIO;
+ p->cfg.ECMD = DXS_FW_GPIO_Config_ECMD;
+ p->cfg.LENGTH = DXS_FW_GPIO_Config_LENGTH;
+
+ p->data.CMD = CMD_EOP;
+ p->data.MOD = MOD_EOP_GPIO;
+ p->data.ECMD = DXS_FW_GPIO_Data_ECMD;
+ p->data.LENGTH = DXS_FW_GPIO_Data_LENGTH;
+
+ p->flag |= GPIO_DEV_INITIALIZED;
+
+ return (void *)p;
+}
+
+/**
+ Function to configure GPIO
+
+ \param pDev - pointer to DXS device structure
+ \param pGpioConf - pointer to GPIO config structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_GPIO_Config(DXS_DEVICE_t *pDev, DXS_GpioConfig_t *pGpioConf)
+{
+ int32_t err = DXS_statusOk;
+ DXS_GPIO_Dev_Resource_t *p;
+ uint8_t new_gpio_PU, new_gpio_dir, param_check;
+
+ if (pDev == NULL || pGpioConf == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_GPIO_Dev_Resource_t *)pDev->gpio;
+
+ if (!(p->flag & GPIO_DEV_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ param_check = (pGpioConf->gpio0_PU | pGpioConf->gpio1_PU |
+ pGpioConf->gpio2_PU | pGpioConf->gpio3_PU |
+ pGpioConf->gpio0_DIR | pGpioConf->gpio1_DIR |
+ pGpioConf->gpio2_DIR | pGpioConf->gpio3_DIR);
+ if (param_check > 1)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ if (!(p->flag & GPIO_CTRL_CONFIGURED))
+ {
+ /* read configuration from the device */
+ err = DXS_CmdRead(pDev, (uint32_t *)&p->cfg, (uint32_t *)&p->cfg);
+ if (err)
+ {
+ DXS_RETURN(err);
+ }
+ }
+
+ /* Set the parameters */
+ new_gpio_PU = 0xF & (pGpioConf->gpio0_PU | (pGpioConf->gpio1_PU << 1) |
+ (pGpioConf->gpio2_PU << 2) | (pGpioConf->gpio3_PU << 3));
+ new_gpio_dir = 0xF & (pGpioConf->gpio0_DIR | (pGpioConf->gpio1_DIR << 1) |
+ (pGpioConf->gpio2_DIR << 2) | (pGpioConf->gpio3_DIR << 3));
+
+ if (new_gpio_PU != p->cfg.GPIO_PULL_UP || new_gpio_dir != p->cfg.GPIO_DIR)
+ {
+ /* write new values */
+ p->cfg.GPIO_PULL_UP = new_gpio_PU;
+ p->cfg.GPIO_DIR = new_gpio_dir;
+ err = CmdWrite(pDev, (uint32_t *)&p->cfg);
+ if (err)
+ {
+ DXS_RETURN(err);
+ }
+ }
+
+ p->flag |= GPIO_CTRL_CONFIGURED;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function DXS_GPIO_Write
+
+ \param pDev - pointer to DXS device structure
+ \param pin - pin number
+ \param val - value
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_GPIO_Write(DXS_DEVICE_t *pDev, uint8_t pin, uint8_t val)
+{
+ int32_t err = DXS_statusOk;
+ DXS_GPIO_Dev_Resource_t *p;
+ uint8_t pin_mask;
+
+ if (pDev == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_GPIO_Dev_Resource_t *)pDev->gpio;
+
+ if (!(p->flag & GPIO_DEV_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (!(p->flag & GPIO_CTRL_CONFIGURED))
+ {
+ /* GPIO port not configured yet */
+ DXS_RETURN(DXS_statusGpioNotConfigured);
+ }
+
+ pin_mask = 1 << pin;
+ /* If the specified pin is configured as input - return error */
+ if (p->cfg.GPIO_DIR & pin_mask)
+ {
+ DXS_RETURN(DXS_statusGpioWriteAccessIgnored);
+ }
+
+ /* Set the parameters */
+ p->data.GPIO_WR_MSK = ~pin_mask;
+ if (val)
+ p->data.GPIO_VAL = 0xF;
+ else
+ p->data.GPIO_VAL = 0;
+
+ /* write new values */
+ err = CmdWrite(pDev, (uint32_t *)&p->data);
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function DXS_GPIO_Read
+
+ \param pDev - pointer to DXS device structure
+ \param pin - pin number
+ \param pVal - pointer to value
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_GPIO_Read(DXS_DEVICE_t *pDev, uint8_t pin, uint8_t *pVal)
+{
+ int32_t err = DXS_statusOk;
+ DXS_GPIO_Dev_Resource_t *p;
+
+ if (pDev == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_GPIO_Dev_Resource_t *)pDev->gpio;
+
+ if (!(p->flag & GPIO_DEV_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (!(p->flag & GPIO_CTRL_CONFIGURED))
+ {
+ /* GPIO port not configured yet */
+ DXS_RETURN(DXS_statusGpioNotConfigured);
+ }
+
+ err = DXS_CmdRead(pDev, (uint32_t *)&p->data, (uint32_t *)&p->data);
+ if (err)
+ {
+ DXS_RETURN(err);
+ }
+
+ /* Set the parameters */
+ if (p->data.GPIO_VAL & (1 << pin))
+ *pVal = 1;
+ else
+ *pVal = 0;
+
+ DXS_RETURN(err);
+}
+#endif /* DXS_FEAT_GPIO */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_gpio.h b/marvell/services/dxslic/api_lib/src/dxs_gpio.h
new file mode 100644
index 0000000..d547aa7
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_gpio.h
@@ -0,0 +1,40 @@
+#ifndef __DXS_GPIO_H__
+#define __DXS_GPIO_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_gpio.h
+ GPIO functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_lib.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern void *DXS_GPIO_DevInit(uint8_t dev);
+extern int32_t DXS_GPIO_Config(DXS_DEVICE_t *pDev, DXS_GpioConfig_t *pGpioConf);
+extern int32_t DXS_GPIO_Write(DXS_DEVICE_t *pDev, uint8_t pin, uint8_t val);
+extern int32_t DXS_GPIO_Read(DXS_DEVICE_t *pDev, uint8_t pin, uint8_t *pVal);
+
+#endif /* __DXS_GPIO_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_hsm.c b/marvell/services/dxslic/api_lib/src/dxs_hsm.c
new file mode 100644
index 0000000..c39778f
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_hsm.c
@@ -0,0 +1,804 @@
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_hsm.c
+
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_config.h"
+#include "dxs_lib.h"
+#include "dxs.h"
+#include "dxs_error.h"
+#include "dxs_timer.h"
+#include "dxs_event.h"
+
+/* ============================= */
+/* Configuration */
+/* ============================= */
+/* Scatter the times used for timeout over the given period with the given
+ increment between each timer start. This can help to distribute the load
+ in systems with multiple devices when hook events happen on all lines in
+ parallel. The increment must be smaller than half the maximum time.
+ To use this option set DXS_DIAL_SCATTER_MAX to a positive time in ms and
+ DXS_DIAL_SCATTER_INC to a positive time in ms of maximum half the max time.
+ Using this option degrades the precision of the timeouts for the on-hook,
+ off-hook, flash-holdoff and interdigit. The precision of the times for
+ flash and pulse detection will stay unaffected. */
+#define DXS_DIAL_SCATTER_MAX 0 /* ms */
+#define DXS_DIAL_SCATTER_INC 0 /* ms */
+#if (DXS_DIAL_SCATTER_MAX / 2) < DXS_DIAL_SCATTER_INC
+#error Configuration of DIAL_SCATTER incorrect
+#endif
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+#if (DXS_DIAL_SCATTER_MAX > 0)
+ #define DXS_DIAL_SCATTER_INCREASE \
+ do { \
+ nScatter += DXS_DIAL_SCATTER_INC; \
+ if (nScatter > DXS_DIAL_SCATTER_MAX) \
+ nScatter = 0; \
+ } while (0)
+#else
+ #define DXS_DIAL_SCATTER_INCREASE
+#endif
+
+#if 0
+//origin code
+#define DXS_MIN_FLASH 80
+#define DXS_MAX_FLASH 400
+#define DXS_MIN_FLASH_MAKE 200
+#define DXS_MIN_DIGIT_LOW 30
+#define DXS_MAX_DIGIT_LOW 80
+#define DXS_MIN_DIGIT_HIGH 30
+#define DXS_MAX_DIGIT_HIGH 80
+#define DXS_MIN_OFF_HOOK 40
+#define DXS_MIN_ON_HOOK 400
+#define DXS_MIN_INTERDIGIT 300
+#else
+#define DXS_MIN_FLASH 150
+#define DXS_MAX_FLASH 700
+#define DXS_MIN_FLASH_MAKE 400
+#define DXS_MIN_DIGIT_LOW 30
+#define DXS_MAX_DIGIT_LOW 80
+#define DXS_MIN_DIGIT_HIGH 30
+#define DXS_MAX_DIGIT_HIGH 80
+#define DXS_MIN_OFF_HOOK 40
+#define DXS_MIN_ON_HOOK 710
+#define DXS_MIN_INTERDIGIT 300
+#endif
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+#ifdef DXS_FEAT_HSM
+
+/**
+ Process an action in the state machines.
+
+ In this function the hook, digit and flash state machines are all handled
+ one after the other. The hook state machine needs to be the first because it
+ directly changes the on-hook/off-hook states of the other state machines.
+ This reduces the complexity of code of the other state machines.
+
+ \param pChannel Pointer to DXS channel structure.
+ \param nAction Action to be executed.
+ \param nTime If action is make or break this parameter holds the
+ duration since the last hook event in milliseconds.
+ If the action is timeout this parameter is unused.
+*/
+static void dxs_dial_Action(DXS_CHANNEL_t * pChannel,
+ enum ACTION nAction,
+ uint16_t nTime)
+{
+ DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData;
+ DXS_DEVICE_t *pDev = pChannel->pParent;
+ DXS_Event_t dxs_event;
+ int32_t bSendPulseEvent;
+ static uint32_t nScatter = 0; /* library global */
+
+#if 0 /* hook state machine tracing */
+ printf(" ACTION: %d (hook %d, digit %d, flash %d) time %d\n", nAction,
+ pDXS_DialData->nHookState,
+ pDXS_DialData->nDigitState,
+ pDXS_DialData->nFlashState,
+ nTime);
+#endif
+
+ /* Handle the hook-state detection finite state machine. */
+ switch (pDXS_DialData->nHookState)
+ {
+ case HOOK_STATE_ONHOOK:
+ if (nAction == ACTION_MAKE)
+ {
+ pDXS_DialData->nHookState = HOOK_STATE_VALIDATE_OFFHOOK;
+ DXS_TimerSet(pDXS_DialData->HookTimerID,
+ pDXS_DialData->nTimeOffhook + nScatter, 0, 1);
+ DXS_DIAL_SCATTER_INCREASE;
+ }
+ break;
+
+ case HOOK_STATE_OFFHOOK:
+ if (nAction == ACTION_BREAK)
+ {
+ pDXS_DialData->nHookState = HOOK_STATE_VALIDATE_ONHOOK;
+ DXS_TimerSet(pDXS_DialData->HookTimerID,
+ pDXS_DialData->nTimeOnhook + nScatter, 0, 1);
+ DXS_DIAL_SCATTER_INCREASE;
+ }
+ break;
+
+ case HOOK_STATE_VALIDATE_OFFHOOK:
+ if (nAction == ACTION_BREAK)
+ {
+ pDXS_DialData->nHookState = HOOK_STATE_ONHOOK;
+ DXS_TimerStop(pDXS_DialData->HookTimerID);
+ }
+ else
+ if (nAction == ACTION_TIMEOUT_HOOK)
+ {
+ pDXS_DialData->nHookState = HOOK_STATE_OFFHOOK;
+ /* Attention: change of the digit and flash state machine data! */
+ pDXS_DialData->nDigitState = DIGIT_STATE_OFFHOOK;
+ pDXS_DialData->nFlashState = FLASH_STATE_OFFHOOK;
+ pDXS_DialData->nPulseDigit = 0;
+ pDXS_DialData->bPulseStartSent = 0;
+ /* DXS event: off-hook */
+ dxs_event.dev = pDev->nDevNum;
+ dxs_event.ch = pChannel->nCh;
+ dxs_event.id = DXS_EVENT_FXS_OFFHOOK;
+ DXS_EventDispatch(pDev, &dxs_event);
+ }
+ break;
+
+ case HOOK_STATE_VALIDATE_ONHOOK:
+ if (nAction == ACTION_MAKE)
+ {
+ pDXS_DialData->nHookState = HOOK_STATE_OFFHOOK;
+ DXS_TimerStop(pDXS_DialData->HookTimerID);
+ }
+ else
+ if (nAction == ACTION_TIMEOUT_HOOK)
+ {
+ pDXS_DialData->nHookState = HOOK_STATE_ONHOOK;
+ /* Attention: change of the digit and flash state machine data! */
+ pDXS_DialData->nDigitState = DIGIT_STATE_ONHOOK;
+ pDXS_DialData->nFlashState = FLASH_STATE_ONHOOK;
+ /* TAPI event: on-hook */
+ dxs_event.dev = pDev->nDevNum;
+ dxs_event.ch = pChannel->nCh;
+ dxs_event.id = DXS_EVENT_FXS_ONHOOK;
+ DXS_EventDispatch(pDev, &dxs_event);
+ }
+ break;
+ }
+
+ /* Handle the pulse dialing detection finite state machine. */
+ /* Attention: the hook state machine above will do the transitions into and
+ out of the off-hook state. */
+ switch (pDXS_DialData->nDigitState)
+ {
+ case DIGIT_STATE_ONHOOK:
+ /* ignore all */
+ break;
+
+ case DIGIT_STATE_OFFHOOK:
+ if (nAction == ACTION_BREAK)
+ pDXS_DialData->nDigitState = DIGIT_STATE_VALIDATE_DIGIT_BREAK;
+ break;
+
+ case DIGIT_STATE_VALIDATE_DIGIT_BREAK:
+ if (nAction == ACTION_MAKE)
+ {
+ if ((nTime >= pDXS_DialData->nTimeDigitBreakMin) &&
+ (nTime <= pDXS_DialData->nTimeDigitBreakMax))
+ {
+ pDXS_DialData->nDigitState = DIGIT_STATE_VALIDATE_DIGIT_MAKE;
+ pDXS_DialData->nPulseDigit += 1;
+ DXS_TimerSet(pDXS_DialData->InterdigitTimerID,
+ pDXS_DialData->nTimeInterdigit + nScatter, 0, 1);
+ DXS_DIAL_SCATTER_INCREASE;
+ if ((pDXS_DialData->nPulseDigit == 1) &&
+ (pDXS_DialData->bPulseStartSent == 0))
+ {
+ /* report the first validated pulse dial break */
+ /* Use this to stop a dial tone right after the first pulse. */
+ dxs_event.dev = pDev->nDevNum;
+ dxs_event.ch = pChannel->nCh;
+ dxs_event.id = DXS_EVENT_PULSE_START;
+ DXS_EventDispatch(pDev, &dxs_event);
+ /* Do this only for the first pulse after off-hook or flash. */
+ pDXS_DialData->bPulseStartSent = 1;
+ }
+ }
+ else
+ {
+ pDXS_DialData->nDigitState = DIGIT_STATE_OFFHOOK;
+ pDXS_DialData->nPulseDigit = 0;
+ }
+ }
+ break;
+
+ case DIGIT_STATE_VALIDATE_DIGIT_MAKE:
+ bSendPulseEvent = 0;
+ if (nAction == ACTION_BREAK)
+ {
+ pDXS_DialData->nDigitState = DIGIT_STATE_VALIDATE_DIGIT_BREAK;
+ DXS_TimerStop(pDXS_DialData->InterdigitTimerID);
+ if (nTime >= pDXS_DialData->nTimeInterdigit)
+ {
+ /* Accept also the time from the hook event for the inter-digit
+ timeout condition. */
+ bSendPulseEvent = 1;
+ }
+ else
+ if ((nTime < pDXS_DialData->nTimeDigitMakeMin) ||
+ (nTime > pDXS_DialData->nTimeDigitMakeMax))
+ {
+ pDXS_DialData->nPulseDigit = 0;
+ }
+ }
+ else
+ if (nAction == ACTION_TIMEOUT_INTERDIGIT)
+ {
+ pDXS_DialData->nDigitState = DIGIT_STATE_OFFHOOK;
+ bSendPulseEvent = 1;
+ }
+ /* _no_ else here */
+ if (bSendPulseEvent)
+ {
+ if (pDXS_DialData->nPulseDigit <= 10)
+ {
+ /* TAPI event: digit */
+ dxs_event.dev = pDev->nDevNum;
+ dxs_event.ch = pChannel->nCh;
+ dxs_event.id = DXS_EVENT_PULSE_DIGIT;
+ dxs_event.data.pulse.digit = pDXS_DialData->nPulseDigit;
+ /* 10 pulses represent digit 0 which has TAPI code 0xB */
+ if (dxs_event.data.pulse.digit == 10)
+ dxs_event.data.pulse.digit = 0x0B;
+ DXS_EventDispatch(pDev, &dxs_event);
+ }
+ pDXS_DialData->nPulseDigit = 0;
+ }
+ break;
+ }
+
+ /* Handle the flash hook detection finite state machine. */
+ /* Attention: the hook state machine above will do the transitions into and
+ out of the off-hook state. */
+ switch (pDXS_DialData->nFlashState)
+ {
+ case FLASH_STATE_ONHOOK:
+ /* ignore all */
+ break;
+
+ case FLASH_STATE_OFFHOOK:
+ if (nAction == ACTION_BREAK)
+ pDXS_DialData->nFlashState = FLASH_STATE_VALIDATE_FLASH_BREAK;
+ break;
+
+ case FLASH_STATE_VALIDATE_FLASH_BREAK:
+ if (nAction == ACTION_MAKE)
+ {
+ if ((nTime >= pDXS_DialData->nTimeFlashBreakMin) &&
+ (nTime <= pDXS_DialData->nTimeFlashBreakMax))
+ {
+ pDXS_DialData->nFlashState = FLASH_STATE_VALIDATE_FLASH_HOLDOFF;
+ DXS_TimerSet(pDXS_DialData->FlashHoldoffTimerID,
+ pDXS_DialData->nTimeFlashHoldoff + nScatter, 0, 1);
+ DXS_DIAL_SCATTER_INCREASE;
+ }
+ else
+ {
+ pDXS_DialData->nFlashState = FLASH_STATE_OFFHOOK;
+ }
+ }
+ break;
+
+ case FLASH_STATE_VALIDATE_FLASH_HOLDOFF:
+ if (nAction == ACTION_BREAK)
+ {
+ pDXS_DialData->nFlashState = FLASH_STATE_VALIDATE_FLASH_BREAK;
+ DXS_TimerStop(pDXS_DialData->FlashHoldoffTimerID);
+ }
+ else
+ if (nAction == ACTION_TIMEOUT_FLASHHOLDOFF)
+ {
+ pDXS_DialData->nFlashState = FLASH_STATE_OFFHOOK;
+ pDXS_DialData->bPulseStartSent = 0;
+ /* TAPI event: flash */
+ dxs_event.dev = pDev->nDevNum;
+ dxs_event.ch = pChannel->nCh;
+ dxs_event.id = DXS_EVENT_FXS_FLASH;
+ DXS_EventDispatch(pDev, &dxs_event);
+ }
+ break;
+ }
+
+#if 0 /* hook state machine tracing */
+ printf(" (hook %d, digit %d, flash %d) digit %d\n",
+ pDXS_DialData->nHookState,
+ pDXS_DialData->nDigitState,
+ pDXS_DialData->nFlashState,
+ pDXS_DialData->nPulseDigit);
+#endif
+}
+
+
+/**
+ Hook state machine timer callback function.
+
+ \param nArg Argument of timer. This argument is a pointer to the
+ DXS_CHANNEL_t structure.
+*/
+void dxs_dial_OnHookTimer(Timer_ID tm, void *arg)
+{
+ DXS_CHANNEL_t *pChannel = (DXS_CHANNEL_t *)arg;
+
+ dxs_dial_Action(pChannel, ACTION_TIMEOUT_HOOK, /*dummy*/0);
+ return;
+}
+
+
+/**
+ Inter-digit timer callback function.
+
+ \param nArg Argument of timer. This argument is a pointer to the
+ DXS_CHANNEL_t structure.
+*/
+void dxs_dial_OnInterdigitTimer(Timer_ID tm, void *arg)
+{
+ DXS_CHANNEL_t *pChannel = (DXS_CHANNEL_t *)arg;
+
+ dxs_dial_Action(pChannel, ACTION_TIMEOUT_INTERDIGIT, /*dummy*/0);
+ return;
+}
+
+/**
+ Flash holdoff timer callback function.
+
+ \param nArg Argument of timer. This argument is a pointer to the
+ DXS_CHANNEL_t structure.
+*/
+void dxs_dial_OnFlashHoldoffTimer(Timer_ID tm, void *arg)
+{
+ DXS_CHANNEL_t *pChannel = (DXS_CHANNEL_t *)arg;
+
+ dxs_dial_Action(pChannel, ACTION_TIMEOUT_FLASHHOLDOFF, /*dummy*/0);
+ return;
+}
+
+
+/**
+ Flash holdoff timer callback function.
+
+ \param nArg Argument of timer. This argument is a pointer to the
+ DXS_CHANNEL_t structure.
+*/
+void dxs_dial_OnHookWindowTimer(Timer_ID tm, void *arg)
+{
+ DXS_CHANNEL_t *pChannel = (DXS_CHANNEL_t *)arg;
+ DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData;
+
+ pDXS_DialData->bHookWindow = 0;
+ return;
+}
+
+/**
+ Initialize the analog line state machines on the given channel.
+ Initialize the data structures and resources needed for the
+ hook state machine.
+
+ \param pChannel Pointer to DXS_CHANNEL_t structure.
+
+ \return
+ DXS_statusOk - if successful
+ DXS_statusTimerCreateError - timer creation failed
+
+ \remarks This function is not protected.
+*/
+int32_t DXS_Dial_Initialise_Unprot (DXS_CHANNEL_t *pChannel)
+{
+ DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData;
+ DXS_status_t ret = DXS_statusError;
+
+ if (pChannel->flags & DXS_CH_DIAL_DATA_INITIALIZED)
+ return DXS_statusOk;
+
+ /* set default values for the validation times */
+ pDXS_DialData->nTimeOnhook = DXS_MIN_ON_HOOK;
+ pDXS_DialData->nTimeOffhook = DXS_MIN_OFF_HOOK;
+ pDXS_DialData->nTimeInterdigit = DXS_MIN_INTERDIGIT;
+ pDXS_DialData->nTimeFlashHoldoff = DXS_MIN_FLASH_MAKE;
+ pDXS_DialData->nTimeDigitMakeMin = DXS_MIN_DIGIT_HIGH;
+ pDXS_DialData->nTimeDigitMakeMax = DXS_MAX_DIGIT_HIGH;
+ pDXS_DialData->nTimeDigitBreakMin = DXS_MIN_DIGIT_LOW;
+ pDXS_DialData->nTimeDigitBreakMax = DXS_MAX_DIGIT_LOW;
+ pDXS_DialData->nTimeFlashBreakMin = DXS_MIN_FLASH;
+ pDXS_DialData->nTimeFlashBreakMax = DXS_MAX_FLASH;
+
+ /* start all three HSMs in on-hook state */
+ pDXS_DialData->nHookState = HOOK_STATE_ONHOOK;
+ pDXS_DialData->nDigitState = DIGIT_STATE_ONHOOK;
+ pDXS_DialData->nFlashState = FLASH_STATE_ONHOOK;
+ pDXS_DialData->nPulseDigit = 0;
+ pDXS_DialData->bPulseStartSent = 0;
+
+ /* create hook-state-machine validation timer */
+ pDXS_DialData->HookTimerID =
+ DXS_TimerCreate(dxs_dial_OnHookTimer, (void *)pChannel);
+ if (NULL == pDXS_DialData->HookTimerID)
+ {
+ perror("ERROR: Creation of hook-state-machine validation timer failed");
+ DXS_RETURN(ret);
+ }
+ /* create inter-digit timer */
+ pDXS_DialData->InterdigitTimerID =
+ DXS_TimerCreate(dxs_dial_OnInterdigitTimer, (void *)pChannel);
+ if (NULL == pDXS_DialData->InterdigitTimerID)
+ {
+ perror("ERROR: Creation of inter-digit timer failed");
+ DXS_Dial_Cleanup(pChannel);
+ DXS_RETURN(ret);
+ }
+ /* create flash holdoff timer */
+ pDXS_DialData->FlashHoldoffTimerID =
+ DXS_TimerCreate(dxs_dial_OnFlashHoldoffTimer, (void *)pChannel);
+ if (NULL == pDXS_DialData->FlashHoldoffTimerID)
+ {
+ perror("ERROR: Creation of flash holdoff timer failed");
+ DXS_Dial_Cleanup(pChannel);
+ DXS_RETURN(ret);
+ }
+ /* create hook event timestamp wraparound timer */
+ pDXS_DialData->HookWindowTimerId =
+ DXS_TimerCreate(dxs_dial_OnHookWindowTimer, (void *)pChannel);
+ if (NULL == pDXS_DialData->HookWindowTimerId)
+ {
+ perror("ERROR: Creation of hook event timestamp wraparound timer failed");
+ DXS_Dial_Cleanup(pChannel);
+ DXS_RETURN(ret);
+ }
+
+ pDXS_DialData->bHookWindow = 0;
+ pDXS_DialData->nLastHookEvtTimestamp = 0;
+ pDXS_DialData->nTimeOffhookBackup = 0;
+
+ pChannel->flags |= DXS_CH_DIAL_DATA_INITIALIZED;
+ return DXS_statusOk;
+}
+
+
+/**
+ Cleanup the analog line state machines on the given channel.
+
+ Free the resources needed for the hook state machine and
+ the ground-key state machine.
+
+ \param pChannel Pointer to DXS_CHANNEL_t structure.
+*/
+void DXS_Dial_Cleanup(DXS_CHANNEL_t *pChannel)
+{
+ DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData;
+
+ if (!(pChannel->flags & DXS_CH_DIAL_DATA_INITIALIZED))
+ return;
+ /* unconditionally delete all timers */
+ DXS_TimerDestroy(pDXS_DialData->HookTimerID);
+ DXS_TimerDestroy(pDXS_DialData->InterdigitTimerID);
+ DXS_TimerDestroy(pDXS_DialData->FlashHoldoffTimerID);
+ DXS_TimerDestroy(pDXS_DialData->HookWindowTimerId);
+ pChannel->flags &= ~DXS_CH_DIAL_DATA_INITIALIZED;
+}
+
+
+/**
+ Process hook events in the state machines.
+
+ \param pChannel Pointer to DXS_CHANNEL_t structure.
+ \param bHookState - 1: make (off-hook),
+ - 0: break (on-hook)
+ \param nTime Duration since the last hook event in ms.
+*/
+void DXS_Dial_HookEvent (DXS_CHANNEL_t* pChannel,
+ uint32_t bHookState,
+ uint16_t nTime)
+{
+ /* make sure dial is initialised on this channel */
+ if (!(pChannel->flags & DXS_CH_DIAL_DATA_INITIALIZED))
+ {
+ /* silently ignore event - this case can happen during startup or
+ shutdown when an interrupt occurs but DXS_DialData is not initialized.
+ */
+ return;
+ }
+
+ nTime = DXS_Dial_ElapsedTimeSinceLastHook(pChannel, nTime);
+
+ /* Note: The hook events actually report a change between the make and break
+ status of the line. The action reports the new line status. This implies
+ that before this event the opposite line status was present and that the
+ time that is reported is the duration that this status was present.
+ Here make and break is used to make it clear that this is not the hook
+ status of the phone but the line state which will also change from
+ pulse dialing and flash hook. */
+ dxs_dial_Action(pChannel, bHookState ? ACTION_MAKE : ACTION_BREAK, nTime);
+
+ return;
+}
+
+
+/**
+ Set the given hook state unconditionally.
+
+ This is used after certain CID sequences which use hook for signaling
+ purposes. There the hook is not given to this state machine and so the
+ state needs to be corrected in case of an abort.
+
+ \param pChannel Pointer to DXS_CHANNEL_t structure.
+ \param bHookState - 1: make (off-hook),
+ - 0: break (on-hook)
+*/
+void DXS_Dial_HookSet (DXS_CHANNEL_t *pChannel, int32_t bHookState)
+{
+ DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData;
+
+ /* make sure dial is initialised on this channel */
+ if (!(pChannel->flags & DXS_CH_DIAL_DATA_INITIALIZED))
+ {
+ /* silently ignore */
+ return;
+ }
+
+ /* Handle the hook-state detection finite state machine. */
+ switch(pDXS_DialData->nHookState)
+ {
+ case HOOK_STATE_OFFHOOK:
+ if (bHookState == 0)
+ {
+ pDXS_DialData->nHookState = HOOK_STATE_ONHOOK;
+ pDXS_DialData->nDigitState = DIGIT_STATE_ONHOOK;
+ pDXS_DialData->nFlashState = FLASH_STATE_ONHOOK;
+ /* Do not send a TAPI event here. */
+ }
+ break;
+
+ case HOOK_STATE_ONHOOK:
+ if (bHookState == 1)
+ {
+ pDXS_DialData->nHookState = HOOK_STATE_OFFHOOK;
+ pDXS_DialData->nDigitState = DIGIT_STATE_OFFHOOK;
+ pDXS_DialData->nFlashState = FLASH_STATE_OFFHOOK;
+ pDXS_DialData->nPulseDigit = 0;
+ pDXS_DialData->bPulseStartSent = 0;
+ /* Do not send a TAPI event here. */
+ }
+ break;
+
+ default:
+ /* Do nothing in the validation states. */
+ break;
+ }
+
+ return;
+}
+
+
+/**
+ Overrides the user configured off-hook time.
+
+ This is used by the phone detection to set an off-hook time to suppress
+ transient hook events that can occur in the off-hook detection state.
+
+ \param pChannel Pointer to DXS_CHANNEL_t structure.
+ \param nTime DXS_DIAL_TIME_NORMAL for normal user configured
+ value. All other values are used as off-hook time
+ in milliseconds.
+ \remarks
+ The value 0 is invalid for the off-hook time. Here it is used as a marker.
+*/
+void DXS_Dial_OffhookTime_Override(DXS_CHANNEL_t *pChannel,
+ uint32_t const nTime)
+{
+ DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData;
+
+ /* make sure that dial is initialised on this channel */
+ if (pChannel->flags & DXS_CH_DIAL_DATA_INITIALIZED)
+ {
+ if (nTime == DXS_DIAL_TIME_NORMAL)
+ {
+ if (pDXS_DialData->nTimeOffhookBackup != 0)
+ {
+ /* Restore the backed up time value. */
+ pDXS_DialData->nTimeOffhook = pDXS_DialData->nTimeOffhookBackup;
+ pDXS_DialData->nTimeOffhookBackup = 0;
+ }
+ }
+ else
+ {
+ /* Switch to override - backup time value and set from parameter. */
+ if (pDXS_DialData->nTimeOffhookBackup == 0)
+ {
+ pDXS_DialData->nTimeOffhookBackup = pDXS_DialData->nTimeOffhook;
+ }
+ pDXS_DialData->nTimeOffhook = nTime;
+ }
+ }
+}
+
+/**
+ Calculate the elapsed time since the last hook event.
+
+ This function is to be called with each hook event. It calculates the
+ elapsed time since the last hook event.
+
+ The DxS provides a timestamp with each FW event. However, this timestamp
+ has a wraparound after ~66 seconds. So an addtional timer is used to prevent
+ calculation after a wraparound. This function wraps the calculation and
+ also restarts the timer.
+
+ \param pCh Pointer to DxS channel structure.
+ \param nCurrentTimestamp Current timestamp value from the FW event.
+
+ \return
+ Elapsed time since the last hook event in 1 ms steps.
+ If the last event happened too long ago or dial is not initialised 0xFFFF is
+ returned.
+*/
+uint16_t DXS_Dial_ElapsedTimeSinceLastHook(DXS_CHANNEL_t *pChannel,
+ uint16_t nCurrentTimestamp)
+{
+ DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData;
+ uint16_t elapsedTime;
+
+ if (pDXS_DialData->bHookWindow)
+ {
+ /* Calculate elapsed time since the saved timestamp. In case the 16-bit
+ counter had a wraparound since the saved timestamp the calculation
+ will still be correct because the calculation is done with 16-bit
+ unsigned data type. This will always result in the positive distance
+ between the two timestamps. */
+ elapsedTime = nCurrentTimestamp - pDXS_DialData->nLastHookEvtTimestamp;
+ }
+ else
+ {
+ elapsedTime = 0xFFFF;
+ }
+
+ /* Start timer, length of timer nominal 65000 ms. A random component is
+ added to distribute the expiration of the timers in systems with multiple
+ devices using polling where a lot of timers might be started in parallel.
+ This time needs to be below the wraparound of the HW timestamp. */
+ pDXS_DialData->bHookWindow = 1;
+ DXS_TimerSet(pDXS_DialData->HookWindowTimerId,
+ 65000 + (nCurrentTimestamp & 0x00FF), 0, 1);
+ /* store the timestamp from this event */
+ pDXS_DialData->nLastHookEvtTimestamp = nCurrentTimestamp;
+
+ return elapsedTime;
+}
+
+
+/**
+ Sets the validation times for hook, pulse digit and flashhook.
+
+ \param pChannel - pointer to DXS channel structure
+ \param pTime - type of validation setting, min and max time in
+ milliseconds.
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_Dial_HookValTimeSet(DXS_CHANNEL_t *pChannel,
+ DXS_HookValTime_t *pTime)
+{
+ DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData;
+
+ /* zero timer value is not allowed -- except for the flash holdoff time */
+ if ((pTime->nMinTime == 0) &&
+ (pTime->nType != DXS_HOOK_VT_FLASH_HOLDOFF_TIME))
+ {
+ DXS_RETURN(DXS_statusDialZeroParam);
+ }
+
+ /* For the times hook-off, hook-on, interdigit and flash holdoff just
+ the minimum time is relevant. So do not check the maximum time. */
+ if ((pTime->nType != DXS_HOOK_VT_HOOKOFF_TIME) &&
+ (pTime->nType != DXS_HOOK_VT_HOOKON_TIME) &&
+ (pTime->nType != DXS_HOOK_VT_INTERDIGIT_TIME) &&
+ (pTime->nType != DXS_HOOK_VT_FLASH_HOLDOFF_TIME))
+ {
+ /* check whether min timer value > max timer value */
+ if (pTime->nMinTime > pTime->nMaxTime)
+ {
+ DXS_RETURN(DXS_statusDialMaxMinParam);
+ }
+ /* Note: the max timer value cannot be 0 because min > 0 and
+ min <= max entails that max > 0. */
+ }
+
+ /* set the validation times */
+ switch (pTime->nType)
+ {
+ case DXS_HOOK_VT_HOOKOFF_TIME:
+ if (pDXS_DialData->nTimeOffhookBackup == 0)
+ pDXS_DialData->nTimeOffhook = pTime->nMinTime;
+ else
+ pDXS_DialData->nTimeOffhookBackup= pTime->nMinTime;
+ break;
+
+ case DXS_HOOK_VT_HOOKON_TIME:
+ pDXS_DialData->nTimeOnhook = pTime->nMinTime;
+ break;
+
+ case DXS_HOOK_VT_HOOKFLASH_TIME:
+ pDXS_DialData->nTimeFlashBreakMin = pTime->nMinTime;
+ pDXS_DialData->nTimeFlashBreakMax = pTime->nMaxTime;
+ break;
+
+ case DXS_HOOK_VT_DIGITLOW_TIME:
+ pDXS_DialData->nTimeDigitBreakMin = pTime->nMinTime;
+ pDXS_DialData->nTimeDigitBreakMax = pTime->nMaxTime;
+ break;
+
+ case DXS_HOOK_VT_DIGITHIGH_TIME:
+ pDXS_DialData->nTimeDigitMakeMin = pTime->nMinTime;
+ pDXS_DialData->nTimeDigitMakeMax = pTime->nMaxTime;
+ break;
+
+ case DXS_HOOK_VT_INTERDIGIT_TIME:
+ pDXS_DialData->nTimeInterdigit = pTime->nMinTime;
+ break;
+
+ case DXS_HOOK_VT_FLASH_HOLDOFF_TIME:
+ pDXS_DialData->nTimeFlashHoldoff = pTime->nMinTime;
+ break;
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Sets the nHookState to HOOK_STATE_ONHOOK.
+
+ \param pChannel - pointer to DXS channel structure
+
+*/
+extern void DXS_Dial_HookStateSetOnhook(DXS_CHANNEL_t *pChannel)
+{
+ DXS_DIAL_DATA_t *pDXS_DialData;
+
+ if (pChannel != NULL)
+ {
+ pDXS_DialData = &pChannel->DXS_DialData;
+ pDXS_DialData->nHookState = HOOK_STATE_ONHOOK;
+ }
+}
+#endif /* DXS_FEAT_HSM */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_hsm.h b/marvell/services/dxslic/api_lib/src/dxs_hsm.h
new file mode 100644
index 0000000..6564d32
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_hsm.h
@@ -0,0 +1,147 @@
+#ifndef __DXS_HSM_H__
+#define __DXS_HSM_H__
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_hsm.h
+
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+#include "dxs.h"
+#include "dxs_timer.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* Used as parameter to DXS_Dial_OffhookTime_Override(). */
+#define DXS_DIAL_TIME_NORMAL 0
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+struct DXS_DIAL_DATA;
+typedef struct DXS_DIAL_DATA DXS_DIAL_DATA_t;
+
+/** states of the hook-state detection finite state machine */
+enum HOOK_STATE
+{
+ /** phone is on-hook */
+ HOOK_STATE_ONHOOK,
+ /** make detected - wait for off-hook timeout */
+ HOOK_STATE_VALIDATE_OFFHOOK,
+ /** phone is off-hook */
+ HOOK_STATE_OFFHOOK,
+ /** break detected - wait for on-hook timeout */
+ HOOK_STATE_VALIDATE_ONHOOK
+};
+
+/** states of the pulse dialing detection finite state machine */
+enum DIGIT_STATE
+{
+ /** phone is on-hook */
+ DIGIT_STATE_ONHOOK,
+ /** phone is off-hook */
+ DIGIT_STATE_OFFHOOK,
+ /** wait for make to validate the digit break time */
+ DIGIT_STATE_VALIDATE_DIGIT_BREAK,
+ /** wait for break to validate the digit make time or inter-digit timeout */
+ DIGIT_STATE_VALIDATE_DIGIT_MAKE
+};
+
+/** states of the flash hook detection finite state machine */
+enum FLASH_STATE
+{
+ /** phone is on-hook */
+ FLASH_STATE_ONHOOK,
+ /** phone is off-hook */
+ FLASH_STATE_OFFHOOK,
+ /** wait for make to validate the flash break time */
+ FLASH_STATE_VALIDATE_FLASH_BREAK,
+ /** wait for flash holdoff timeout before reporting the flash event */
+ FLASH_STATE_VALIDATE_FLASH_HOLDOFF
+};
+
+/** actions to all state machines */
+enum ACTION
+{
+ /** make reported from analog line */
+ ACTION_MAKE,
+ /** break reported from analog line */
+ ACTION_BREAK,
+ /** timer expired */
+ ACTION_TIMEOUT_HOOK,
+ /** timer expired */
+ ACTION_TIMEOUT_INTERDIGIT,
+ /** timer expired */
+ ACTION_TIMEOUT_FLASHHOLDOFF
+};
+
+/** Data of the hook state machine. */
+struct DXS_DIAL_DATA
+{
+ /** state of the hook-state detection finite state machine */
+ enum HOOK_STATE nHookState;
+ /** state of the pulse dialing detection finite state machine */
+ enum DIGIT_STATE nDigitState;
+ /** state of the flash hook detection finite state machine */
+ enum FLASH_STATE nFlashState;
+ /** timer for hook state machine timeouts */
+ Timer_ID HookTimerID;
+ /** timer for the inter-digit timeout */
+ Timer_ID InterdigitTimerID;
+ /** timer for the flash holdoff timeout */
+ Timer_ID FlashHoldoffTimerID;
+ /** counter for the pulses of the pulse digit */
+ uint8_t nPulseDigit;
+ /* indicates that pulse start event was sent, reset by on-hook or
+ * flash-hook */
+ uint8_t bPulseStartSent;
+ /* validation times for all state machines */
+ uint32_t nTimeOnhook,
+ nTimeOffhook,
+ nTimeOffhookBackup,
+ nTimeInterdigit,
+ nTimeFlashHoldoff,
+ nTimeDigitMakeMin,
+ nTimeDigitMakeMax,
+ nTimeDigitBreakMin,
+ nTimeDigitBreakMax,
+ nTimeFlashBreakMin,
+ nTimeFlashBreakMax;
+ /* elapsed time since last hook event */
+ uint16_t nLastHookEvtTimestamp;
+ /* timer for hook event timestamp wraparound */
+ Timer_ID HookWindowTimerId;
+ volatile uint8_t bHookWindow;
+};
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern int32_t DXS_Dial_Initialise_Unprot(DXS_CHANNEL_t *pChannel);
+extern void DXS_Dial_Cleanup(DXS_CHANNEL_t *pChannel);
+extern void DXS_Dial_HookEvent(DXS_CHANNEL_t* pChannel, uint32_t bHookState,
+ uint16_t nTime);
+extern void DXS_Dial_OffhookTime_Override(DXS_CHANNEL_t *pChannel,
+ uint32_t const nTime);
+extern uint16_t DXS_Dial_ElapsedTimeSinceLastHook(DXS_CHANNEL_t *pChannel,
+ uint16_t nCurrentTimestamp);
+extern int32_t DXS_Dial_HookValTimeSet(DXS_CHANNEL_t *pChannel,
+ DXS_HookValTime_t *pTime);
+extern void DXS_Dial_HookStateSetOnhook(DXS_CHANNEL_t *pChannel);
+#endif /* __DXS_HSM_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_init.c b/marvell/services/dxslic/api_lib/src/dxs_init.c
new file mode 100644
index 0000000..e5ab2eb
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_init.c
@@ -0,0 +1,1241 @@
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_init.c
+ Implementation of initialization functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdlib.h>
+
+#include "dxs_config.h"
+#include "dxs_version.h"
+#include "dxs_init.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_fw_cmd.h"
+#include "dxs_pcm.h"
+#include "dxs_sdd.h"
+#include "dxs_sig.h"
+#include "dxs_gpio.h"
+#include "dxs_access.h"
+#include "dxs_cid.h"
+#include "dxs_pollint.h"
+#include "dxs_outbox.h"
+#include "dxs_event.h"
+#include "dxs_spi.h"
+#include "dxs_dcdc_hw.h"
+#include "dxs_ring.h"
+#ifdef EVENT_LOGGER_DEBUG
+#include <sys/ioctl.h>
+#endif
+
+const char DXS_WHATVERSION[] = DXS_WHAT_STR;
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+/** Data structure for DXS_FW_SYS_VERS_ECMD firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Device Number */
+ uint32_t DEVNR : 11;
+ /** Calender Week */
+ uint32_t CW : 6;
+ /** Production Year */
+ uint32_t YEAR : 6;
+ /** Channel */
+ uint32_t CH : 1;
+ /** Device ID Representing PEB Number */
+ uint32_t DEV : 8;
+ /** Major */
+ uint32_t MAJ : 8;
+ /** Minor */
+ uint32_t MIN : 8;
+ /** Hotfix */
+ uint32_t HF : 8 ;
+ /** Reserved */
+ uint32_t Res02 : 8;
+ /** Time Stamp */
+ uint32_t TIME;
+#else
+ CMD_HEAD_LE;
+ /** Device ID Representing PEB Number */
+ uint32_t DEV : 8;
+ /** Channel */
+ uint32_t CH : 1;
+ /** Production Year */
+ uint32_t YEAR : 6;
+ /** Calender Week */
+ uint32_t CW : 6;
+ /** Device Number */
+ uint32_t DEVNR : 11;
+ /** Reserved */
+ uint32_t Res02 : 8;
+ /** Hotfix */
+ uint32_t HF : 8 ;
+ /** Minor */
+ uint32_t MIN : 8;
+ /** Major */
+ uint32_t MAJ : 8;
+ /** Time Stamp */
+ uint32_t TIME;
+#endif
+} __attribute__ ((packed)) DXS_FW_SYS_VERS_t;
+#define DXS_FW_SYS_VERS_ECMD 6
+#define DXS_FW_SYS_VERS_LENGTH 12
+
+/** Data structure for system capabilities firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /* Reserved */
+ uint32_t Res02 : 25;
+ /* Howler Support Available */
+ uint32_t HOWLER : 1;
+ /* Caller ID Available */
+ uint32_t CID : 1;
+ /* Universal Tone Detector Available */
+ uint32_t UTD : 1;
+ /* Teletax Support Available */
+ uint32_t TTX : 1;
+ /* Reserved */
+ uint32_t Res03 : 1;
+ /* AC Level Meter Support Available */
+ uint32_t ACLM : 1;
+ /* GR909 available */
+ uint32_t GR909 : 1;
+#else
+ CMD_HEAD_LE;
+ /* GR909 available */
+ uint32_t GR909 : 1;
+ /* AC Level Meter Support Available */
+ uint32_t ACLM : 1;
+ /* Reserved */
+ uint32_t Res03 : 1;
+ /* Teletax Support Available */
+ uint32_t TTX : 1;
+ /* Universal Tone Detector Available */
+ uint32_t UTD : 1;
+ /* Caller ID Available */
+ uint32_t CID : 1;
+ /* Howler Support Available */
+ uint32_t HOWLER : 1;
+ /* Reserved */
+ uint32_t Res02 : 25;
+#endif
+} __attribute__ ((packed)) DXS_FW_SYS_CAPS_t;
+#define DXS_FW_SYS_CAPS_ECMD 7
+#define DXS_FW_SYS_CAPS_LENGTH 4
+
+/** Data structure for DXS_FW_SYS_Control_ECMD firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /* Reserved */
+ uint32_t Res02 : 25;
+ /* Sync-Fail/ Clock-Fail Handling Enable */
+ uint32_t SYCLKE : 1;
+ /* PLL Limiter Enable */
+ uint32_t PLIM : 1;
+ /* Charge Pump Voltage Level */
+ uint32_t CP_VOLT : 3;
+ /* Charge Pump Enable */
+ uint32_t CP_EN : 1;
+ /* Sleep Enable */
+ uint32_t SE : 1;
+#else
+ CMD_HEAD_LE;
+ /* Sleep Enable */
+ uint32_t SE : 1;
+ /* Charge Pump Enable */
+ uint32_t CP_EN : 1;
+ /* Charge Pump Voltage Level */
+ uint32_t CP_VOLT : 3;
+ /* PLL Limiter Enable */
+ uint32_t PLIM : 1;
+ /* Sync-Fail/ Clock-Fail Handling Enable */
+ uint32_t SYCLKE : 1;
+ /* Reserved */
+ uint32_t Res02 : 25;
+#endif
+} __attribute__ ((packed)) DXS_FW_SYS_Control_t;
+#define DXS_FW_SYS_Control_ECMD 8
+#define DXS_FW_SYS_Control_LENGTH 4
+#define DXS_FW_SYS_Control_CP_VOLT_5_0V 3
+
+/** Device capabilities */
+typedef struct
+{
+ /* status flag */
+ uint32_t flag;
+#define DXS_DEV_CAPS_INITIALIZED 1
+#define DXS_DEV_CAPS_UPDATED 2
+#define DXS_DEV_SYS_CTRL_UPDATED 4
+ /* device version */
+ DXS_Dev_t dev;
+ /* device package */
+ DXS_Package_t pack;
+ /* firmware version */
+ DXS_FW_SYS_VERS_t fw_vers;
+ /* firmware capabilities */
+ DXS_FW_SYS_CAPS_t fw_caps;
+ /* firmware system control */
+ DXS_FW_SYS_Control_t fw_sys_ctrl;
+} DXS_Dev_Caps_t;
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+/* static data */
+static DXS_DEVICE_t dxs_devices[DXS_MAX_DEVICES] = {0};
+static DXS_Dev_Caps_t dxs_caps[DXS_MAX_DEVICES] = {0};
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+static int32_t dxs_controller_reset(DXS_DEVICE_t *pDev);
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+#ifdef EVENT_LOGGER_DEBUG
+static void dxs_el_register(DXS_DEVICE_t *pDev)
+{
+ EL_IoctlRegister_t el_reg;
+ int ret;
+
+ pDev->el_fd = open(EL_DEVICE_NAME, 2, 0644);
+ if (pDev->el_fd < 0)
+ {
+ return;
+ }
+ else
+ {
+ snprintf(el_reg.sName, sizeof(el_reg.sName), "dxs_lib");
+
+ el_reg.nType = DXS_LIB_DEV_TYPE;
+ el_reg.nDevNum = pDev->nDevNum;
+
+ ret = ioctl(pDev->el_fd, EL_REGISTER, (int32_t)&el_reg);
+ if (ret == IFX_SUCCESS)
+ {
+ IFX_char_t *pCmd ="echo \"*\" > /proc/driver/el/logs/all";
+ FILE *el_pipe_fd;
+
+ el_pipe_fd = popen(pCmd, "r");
+ if (!el_pipe_fd)
+ {
+ return;
+ }
+ pclose(el_pipe_fd);
+ }
+ }
+}
+
+static void dxs_el_unregister(DXS_DEVICE_t *pDev)
+{
+ EL_IoctlRegister_t el_reg;
+
+ snprintf(el_reg.sName, sizeof(el_reg.sName), "dxs_lib");
+ el_reg.nType = DXS_LIB_DEV_TYPE;
+ el_reg.nDevNum = pDev->nDevNum;
+
+ if (pDev->el_fd > 0)
+ {
+ ioctl(pDev->el_fd, EL_UNREGISTER, (int32_t)&el_reg);
+ }
+}
+#endif
+
+/**
+ Function dxs_caps_init
+
+ \param dev - device number
+
+*/
+static void *dxs_caps_init(uint8_t dev)
+{
+ DXS_Dev_Caps_t *p;
+
+ if (dev >= DXS_MAX_DEVICES)
+ return (void *)NULL;
+
+ p = &dxs_caps[dev];
+
+ p->flag = 0;
+
+ p->fw_vers.CMD = CMD_EOP;
+ p->fw_vers.MOD = MOD_SYS;
+ p->fw_vers.ECMD = DXS_FW_SYS_VERS_ECMD;
+ p->fw_vers.LENGTH = DXS_FW_SYS_VERS_LENGTH;
+
+ p->fw_caps.CMD = CMD_EOP;
+ p->fw_caps.MOD = MOD_SYS;
+ p->fw_caps.ECMD = DXS_FW_SYS_CAPS_ECMD;
+ p->fw_caps.LENGTH = DXS_FW_SYS_CAPS_LENGTH;
+
+ p->fw_sys_ctrl.CMD = CMD_EOP;
+ p->fw_sys_ctrl.MOD = MOD_SYS;
+ p->fw_sys_ctrl.ECMD = DXS_FW_SYS_Control_ECMD;
+ p->fw_sys_ctrl.LENGTH = DXS_FW_SYS_Control_LENGTH;
+
+ p->flag |= DXS_DEV_CAPS_INITIALIZED;
+
+ return (void *)p;
+}
+
+/**
+ Function dxs_caps_vers_update
+
+ \param pDev - pointer to DXS device structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_caps_vers_update(DXS_DEVICE_t *pDev)
+{
+ DXS_Dev_Caps_t *p;
+ int32_t err;
+
+ if (pDev == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_Dev_Caps_t *)pDev->caps;
+
+ if (!(p->flag & DXS_DEV_CAPS_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (!(p->flag & DXS_DEV_CAPS_UPDATED))
+ {
+ err = CmdRead(pDev, (uint32_t *)&p->fw_caps, (uint32_t *)&p->fw_caps);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusCapVersUpdateError);
+ }
+ err = CmdRead(pDev, (uint32_t *)&p->fw_vers, (uint32_t *)&p->fw_vers);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusCapVersUpdateError);
+ }
+ /* update device ROM version */
+ pDev->rom_mask_ver = p->fw_vers.MAJ & 0x7F;
+
+ if (p->fw_vers.DEV == 0x9)
+ {
+ /* XS_VQFN-68_ES DXS Engineering Sample (A11 design)
+ in PG-VQFN-68 package */
+ p->pack = DXS_PACKAGE_VQFN68;
+ if (p->fw_vers.CH == 0)
+ {
+ p->dev = DXS_DEV_PEF32002_A11;
+ pDev->nChannels = 2;
+ }
+ else
+ {
+ p->dev = DXS_DEV_PEF32001_A11;
+ pDev->nChannels = 1;
+ }
+ }
+ else if (p->fw_vers.DEV == 0xA)
+ {
+ /* XS_VQFN-68_V11 DXS V1.1 (A12 design)
+ in PG-VQFN-68 package */
+ p->pack = DXS_PACKAGE_VQFN68;
+ if (p->fw_vers.CH == 0)
+ {
+ p->dev = DXS_DEV_PEF32002_A12;
+ pDev->nChannels = 2;
+ }
+ else
+ {
+ p->dev = DXS_DEV_PEF32001_A12;
+ pDev->nChannels = 1;
+ }
+ }
+ else if (p->fw_vers.DEV == 0x2A)
+ {
+ /* XC_VQFN-68_V11 DXC2 V1.1 (A12 design)
+ in PG-VQFN-68 package, only 2 channel version */
+ p->pack = DXS_PACKAGE_VQFN68;
+ p->dev = DXC_DEV_PEF31002_A12;
+ pDev->nChannels = 2;
+ }
+ else if (p->fw_vers.DEV == 0x49)
+ {
+ /* XS_VQFN-48_ES DXS1 Engineering Sample (A11 design)
+ in PG-VQFN-48 package */
+ p->pack = DXS_PACKAGE_VQFN48;
+ p->dev = DXS_DEV_PEF32001_A11;
+ pDev->nChannels = 1;
+ }
+ else if (p->fw_vers.DEV == 0x4A)
+ {
+ /* XS_VQFN-48_V11 DXS1 V1.1 (A12 design)
+ in PG-VQFN-48 package */
+ p->pack = DXS_PACKAGE_VQFN48;
+ p->dev = DXS_DEV_PEF32001_A12;
+ pDev->nChannels = 1;
+ }
+ else if (p->fw_vers.DEV == 0x6A)
+ {
+ /* XC_VQFN-48_V11 DXC1 V1.1 (A12 design)
+ in PG-VQFN-48 package */
+ p->pack = DXS_PACKAGE_VQFN48;
+ p->dev = DXC_DEV_PEF31001_A12;
+ pDev->nChannels = 1;
+ }
+ else if (p->fw_vers.DEV == 0x0B)
+ {
+ /* XS_VQFN-68_V12 DXS2 V1.2 (A13 design)
+ in PG-VQFN-68 package */
+ p->pack = DXS_PACKAGE_VQFN68;
+ p->dev = DXS_DEV_PEF32002_V12_A13;
+ pDev->nChannels = 2;
+ }
+ else if (p->fw_vers.DEV == 0x2B)
+ {
+ /* XC_VQFN-68_V12 DXC2 V1.2 (A13 design)
+ in PG-VQFN-68 package */
+ p->pack = DXS_PACKAGE_VQFN68;
+ p->dev = DXC_DEV_PEF31002_V12_A13;
+ pDev->nChannels = 2;
+ }
+ else if (p->fw_vers.DEV == 0x8C)
+ {
+ /* XS_VQFN-44_V12 DXS1 V1.2
+ (A11 new codec design) in PG-VQFN-44 package */
+ p->pack = DXS_PACKAGE_VQFN44;
+ p->dev = DXS_DEV_PEF32001_V12_A11;
+ pDev->nChannels = 1;
+ }
+ else if (p->fw_vers.DEV == 0xAC)
+ {
+ /* XC_VQFN-44_V12 DXC1 V1.2
+ (A11 new codec design) in PG-VQFN-44 package */
+ p->pack = DXS_PACKAGE_VQFN44;
+ p->dev = DXC_DEV_PEF31001_V12_A11;
+ pDev->nChannels = 1;
+ }
+ else if (p->fw_vers.DEV == 0x4C)
+ {
+ /* XS_VQFN-48_V12 DXS1 V1.2
+ (A11 new codec design) in PG-VQFN-48 package */
+ p->pack = DXS_PACKAGE_VQFN48;
+ p->dev = DXS_DEV_PEF32001_V12_A11;
+ pDev->nChannels = 1;
+
+ }
+ else if (p->fw_vers.DEV == 0x6C)
+ {
+ /* XC_VQFN-48_V12 DXC1 V1.2
+ (A11 new codec design) in PG-VQFN-48 package */
+ p->pack = DXS_PACKAGE_VQFN48;
+ p->dev = DXC_DEV_PEF31001_V12_A11;
+ pDev->nChannels = 1;
+ }
+ else if (p->fw_vers.DEV == 0x0C)
+ {
+ /* XS_VQFN-68_V12 DXS1 V1.2
+ (A11 new codec design) in PG-VQFN-68 package */
+ p->pack = DXS_PACKAGE_VQFN68;
+ p->dev = DXS_DEV_PEF32001_V12_A11;
+ pDev->nChannels = 1;
+ }
+ else if (p->fw_vers.DEV == 0x2C)
+ {
+ /* XC_VQFN-68_V12 DXC1 V1.2
+ (A11 new codec design) in PG-VQFN-68 package */
+ p->pack = DXS_PACKAGE_VQFN68;
+ p->dev = DXC_DEV_PEF31001_V12_A11;
+ pDev->nChannels = 1;
+ }
+ else
+ {
+ p->pack = DXS_PACKAGE_UNKNOWN;
+ p->dev = DXS_DEV_UNKNOWN;
+ /* default for unfused device */
+ pDev->nChannels = 1;
+ }
+
+ p->flag |= DXS_DEV_CAPS_UPDATED;
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Function dxs_caps_vers_forget
+
+ \param pDev - pointer to DXS device structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_caps_vers_forget(DXS_DEVICE_t *pDev)
+{
+ DXS_Dev_Caps_t *p;
+
+ if (pDev == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_Dev_Caps_t *)pDev->caps;
+
+ p->flag &= ~DXS_DEV_CAPS_UPDATED;
+
+ return DXS_statusOk;
+}
+
+/**
+ Function dxs_get_dev
+
+ \param dxs - device number
+
+ \return
+ - pointer to DxS device structure
+*/
+DXS_DEVICE_t *dxs_get_dev (uint8_t dxs)
+{
+ if (dxs >= DXS_MAX_DEVICES)
+ return NULL;
+
+ return &dxs_devices[dxs];
+}
+
+
+/**
+ Calculate CRC-8-CCITT. POLYNOMIAL = 0x07
+
+ \param pData Pointer to data for CRC calculation
+ \param nLength Length of data buffer
+
+ \return
+ Calculated CRC value.
+*/
+uint8_t dxs_CRC_8_CCITT(uint8_t *pData, uint32_t nLength)
+{
+ uint8_t nCRC = 0;
+ int32_t i, j;
+
+ /* Perform modulo-2 division, a byte at a time. */
+ for (i = 0; i < nLength; i++)
+ {
+ /* Bring the next byte into the nCRC. */
+ nCRC ^= pData[i];
+
+ /* Perform modulo-2 division, a bit at a time. */
+ for (j = 8; j > 0; j--)
+ {
+ /* Try to divide the current data bit. */
+ if (nCRC & 0x80)
+ nCRC = (nCRC << 1) ^ 0x07;
+ else
+ nCRC = (nCRC << 1);
+ }
+ }
+ return nCRC;
+}
+
+
+/**
+ Function dxs_exit
+
+ \param pDev - pointer to DXS device structure
+
+*/
+int32_t dxs_exit(DXS_DEVICE_t *pDev)
+{
+ uint8_t ch;
+ int32_t ret = DXS_statusOk;
+
+ if (pDev->flags & DXS_DEV_INITIALIZED)
+ {
+ /* DCDC HW specific deinit */
+ DXS_DCDC_HW_Exit(pDev);
+
+ if (pDev->irqNumber == -1)
+ {
+ /* stop polling */
+ dxs_polling_timer_stop();
+ }
+ else
+ {
+ /* uninstall interrupt handler */
+ dxs_interrupt_exit();
+ }
+
+ /* stop obx handling thread */
+ dxs_outbox_handler_exit(pDev);
+ pDev->flags &= ~DXS_DEV_OBX_HND_INITIALIZED;
+
+ /* uninitialize event memory pool */
+ dxs_event_pool_exit(pDev);
+
+ /* uninitialize message queues */
+ fifo_destroy(pDev->event_queue);
+ fifo_destroy(pDev->cmd_obx_queue);
+
+ /* close SPI interface */
+ dxs_spi_linux_exit(pDev->spidev);
+ pDev->flags &= ~DXS_DEV_ACCESS_INITIALIZED;
+
+ /* delete mbx access mutex */
+ ret = pthread_mutex_unlock(&pDev->mtxMbxAcc);
+ if (ret != 0)
+ DXS_ERROR_PUSH(ret);
+ ret = pthread_mutex_destroy(&pDev->mtxMbxAcc);
+ if (ret != 0)
+ DXS_ERROR_PUSH(ret);
+
+ sem_destroy(&pDev->mtxPatchDwld);
+
+#ifdef DXS_FEAT_UTD
+ /* delete UTD mutex */
+ dxs_sig_utd_mtx_destroy();
+#endif /* DXS_FEAT_UTD */
+
+ /* close channel resources */
+ for (ch = 0; ch < pDev->nChannels; ch++)
+ {
+ DXS_CHANNEL_t *pCh = &pDev->pChannel[ch];
+
+#ifdef DXS_FEAT_HSM
+ DXS_Dial_Cleanup(pCh);
+#endif
+ /* cleanup only for SDD resource */
+ ret = DXS_SDD_ChExit(pCh);
+ if (ret != DXS_statusOk)
+ DXS_ERROR_PUSH(ret);
+ }
+
+#ifdef EVENT_LOGGER_DEBUG
+ dxs_el_unregister(pDev);
+#endif /* EVENT_LOGGER_DEBUG */
+
+ pDev->flags &= ~DXS_DEV_INITIALIZED;
+ }
+ DXS_RETURN(ret);
+}
+
+/**
+ Default initialization of DXS registers.
+
+ Enable the required interrupts in the register interface.
+
+ \param pDev pointer to the device structure
+
+ \return
+ - DXS_statusOk
+ - DXS_statusSpiAccError
+*/
+static int32_t dxs_default_reg_init(DXS_DEVICE_t *pDev)
+{
+ int32_t ret = DXS_statusOk;
+ uint16_t nRegHostIen1, nRegHostIen2;
+
+ /*
+ Enable the interrupts OBX_RDY and ERR.
+ */
+ nRegHostIen1 = DXS_REG_IEN1_RESET;
+ nRegHostIen1 |= DXS_REG_IEN1_OBX_RDY;
+ nRegHostIen1 |= DXS_REG_IEN1_ERR;
+ ret = DXS_RegWrite(pDev, DXS_REG_IEN1, nRegHostIen1);
+ if (ret != DXS_statusOk)
+ DXS_RETURN(ret);
+
+ /*
+ Enable the interrupts OBX_UFL and IBX_OFL.
+ */
+ nRegHostIen2 = DXS_REG_IEN2_RESET;
+ nRegHostIen2 |= DXS_REG_IEN2_OBX_UFL;
+ nRegHostIen2 |= DXS_REG_IEN2_IBX_OFL;
+ ret = DXS_RegWrite(pDev, DXS_REG_IEN2, nRegHostIen2);
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function dxs_init
+
+ \param pDev - pointer to DXS device structure
+ \param chipSelect - CS number
+ \param irqNumber - IRQ line number
+ \param dcdcType - DCDC variant handled by DXS_DCDC_Var_t type
+ \param dev - device number
+
+ \return
+ - DXS_status_t
+*/
+/*
+ * should return either 0 or -1
+ */
+int32_t dxs_init(DXS_DEVICE_t *pDev, uint8_t chipSelect, int32_t irqNumber,
+ uint8_t dcdcType, uint8_t access, uint8_t dev)
+{
+ int32_t ret = DXS_statusOk, i;
+#ifdef DXS_FEAT_HSM
+ DXS_status_t status;
+#endif
+ uint8_t ch;
+
+ if (access >= DXS_ACCESS_LAST)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ if (dev >= DXS_MAX_DEVICES)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ for (i=0; i<DXS_MAX_DEVICES; i++)
+ {
+ DXS_DEVICE_t *pdev = dxs_get_dev(i);
+
+ if (pdev->flags & DXS_DEV_INITIALIZED && pdev->dcdcType != dcdcType)
+ {
+ /* provided dcdcType does not match
+ with previously initialized devices */
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ }
+
+ ret = dxs_exit(pDev);
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(DXS_statusDevInitFailed);
+ }
+
+ pDev->nDevNum = dev;
+ pDev->chipSelect = chipSelect;
+ pDev->irqNumber = irqNumber;
+ pDev->dcdcType = dcdcType;
+ pDev->access = access;
+
+ pthread_mutex_init(&pDev->mtxMbxAcc, NULL);
+ pDev->nMbxCachedCbiLen = 0;
+
+#ifdef EVENT_LOGGER_DEBUG
+ dxs_el_register(pDev);
+#endif
+
+ /* open SPI interface */
+ pDev->spidev = dxs_spi_linux_init(chipSelect, access);
+ if (pDev->spidev > 0)
+ {
+ pDev->flags |= DXS_DEV_ACCESS_INITIALIZED;
+ }
+ else
+ {
+ DXS_RETURN(DXS_statusSpiOpenError);
+ }
+
+ /* TODO: light chip access test + error code if failed */
+
+ /* Reset the DXS controller to bring the chip into the default state.
+ The data structures of the driver will be initialized to the same
+ known default state.*/
+ dxs_controller_reset(pDev);
+
+ /* initialize message queues */
+ pDev->event_queue = fifo_init (20);
+ if (NULL == pDev->event_queue)
+ {
+ DXS_RETURN(DXS_statusMsgQueueCreatError);
+ }
+ pDev->cmd_obx_queue = fifo_init (64);
+ if (NULL == pDev->cmd_obx_queue)
+ {
+ DXS_RETURN(DXS_statusMsgQueueCreatError);
+ }
+
+ /* initialize event memory pool */
+ if (DXS_statusOk != dxs_event_pool_init(pDev))
+ {
+ DXS_RETURN(DXS_statusMpoolInitError);
+ }
+
+ /* start obx handling thread */
+ ret = dxs_outbox_handler_init(pDev);
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(DXS_statusObxHandlerStartError);
+ }
+ pDev->flags |= DXS_DEV_OBX_HND_INITIALIZED;
+
+ /* initialize device resources */
+ pDev->caps = dxs_caps_init(dev);
+ pDev->pcm = dxs_pcm_dev_init(dev);
+
+ if (pDev->access == DXS_ACCESS_CSI)
+ {
+ /* default configuration of CSI Master */
+ uint16_t nCSIMasterCFG =
+ (DXS_REG_CSI_M_CFG_PAUSE_DEFAULT | DXS_REG_CSI_M_CFG_PDEMUX);
+ ret = DXS_RegWrite(pDev, DXS_REG_CSI_M_CFG, nCSIMasterCFG);
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(ret);
+ }
+ }
+
+#ifdef DXS_FEAT_GPIO
+ pDev->gpio = DXS_GPIO_DevInit(dev);
+#endif
+
+ /* start device polling */
+ if (pDev->irqNumber != 255 &&
+ (pDev->irqNumber == -1 || dxs_interrupt_init(pDev) != DXS_statusOk))
+ {
+ dxs_polling_timer_start();
+ }
+
+ /* In IRQ as well as polling mode set the interrupt masks. */
+ ret = dxs_default_reg_init(pDev);
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(ret);
+ }
+
+ /* read capabilities and version from device -
+ must be after polling start or interrupt enable */
+ dxs_caps_vers_update(pDev);
+
+#ifdef DXS_FEAT_UTD
+ /* initialize UTD mutex */
+ dxs_sig_utd_mtx_init();
+#endif /* DXS_FEAT_UTD */
+
+ /* initialize channel resources -
+ must be after capabilities read */
+ for (ch = 0; ch < pDev->nChannels; ch++)
+ {
+ DXS_CHANNEL_t *pCh = &pDev->pChannel[ch];
+
+ pCh->pParent = pDev;
+ pCh->nCh = ch;
+ pCh->pcm = dxs_pcm_ch_init(pDev->nDevNum, ch);
+ pCh->sdd = DXS_SDD_ChInit(pDev->nDevNum, ch);
+ pCh->sig = dxs_sig_ch_init(pDev->nDevNum, ch);
+#ifdef DXS_FEAT_HSM
+ status = DXS_Dial_Initialise_Unprot(pCh);
+ if (status != DXS_statusOk)
+ {
+ DXS_RETURN(status);
+ }
+#endif
+#ifdef DXS_FEAT_CID
+ /* cleanup static data */
+ DXS_CID_Cleanup(pCh);
+#endif
+ pCh->ring = DXS_Ring_ResInit(pCh);
+ DXS_EventMaskSetDefault(pCh);
+ }
+
+ /* From now on process all events. */
+ dxs_outbox_handler_enable(pDev);
+
+ /* patch download sync sem */
+ sem_init(&pDev->mtxPatchDwld, 0, 0);
+ pDev->bWaitingInPatchDwld = 0;
+
+ /* DCDC HW specific init */
+ DXS_DCDC_HW_Init(pDev);
+
+ pDev->flags |= DXS_DEV_INITIALIZED;
+
+ return DXS_statusOk;
+}
+
+/**
+ Function dxs_controller_reset
+
+ \param pDev - pointer to DXS device structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_controller_reset(DXS_DEVICE_t *pDev)
+{
+ int32_t ret = DXS_statusOk;
+ uint16_t nDxsRegBootCfg = 0,
+ nDxsRegBootInfo = 0,
+ nDxsRegCfg = 0;
+
+ /* Set the controller startup configuration in the Boot Configuration
+ Register to boot from ROM. */
+ nDxsRegBootCfg = DXS_REG_BCFG_ASC_ROM;
+ ret = DXS_RegWrite(pDev, DXS_REG_BCFG, nDxsRegBootCfg);
+ if (ret != DXS_statusOk)
+ {
+ /* errmsg: Setting of boot configuration register failed. */
+ ret = DXS_statusSetBootCfgErr;
+ }
+
+ /* Reset controller to start the boot. */
+ if (ret == DXS_statusOk)
+ {
+ nDxsRegCfg = DXS_REG_CFG_RST_RSTCORE|DXS_REG_CFG_8BIT_EN;
+ ret = DXS_RegWrite(pDev, DXS_REG_CFG, nDxsRegCfg);
+ if (ret != DXS_statusOk)
+ {
+ /* errmsg: Controller reset failed. */
+ ret = DXS_statusCtrlResErr;
+ }
+ }
+
+ /* Check success of the reset by reading the boot info register. */
+ if (ret == DXS_statusOk)
+ {
+ uint8_t loop = 10;
+
+ while (loop > 0)
+ {
+ struct timespec ts = {0, 2000000}; /* 2 ms */
+
+ nanosleep(&ts, NULL);
+
+ /* read the boot state indication */
+ ret = DXS_RegRead(pDev, DXS_REG_BINF, &nDxsRegBootInfo);
+
+ if ((ret == DXS_statusOk) &&
+ ((nDxsRegBootInfo & DXS_REG_BINF_BOOTSTATE_MASK) >= 0x10))
+ {
+ break;
+ }
+
+ loop--;
+ }
+
+ if (loop == 0)
+ {
+ /* errmsg: Firmware download timeout. */
+ ret = DXS_statusFwDwldTimeout;
+ }
+ }
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function dxs_caps_read
+
+ \param pDev - pointer to DXS device structure
+ \param pCap - pointer to DXS_Caps_t structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_caps_read(DXS_DEVICE_t *pDev, DXS_Caps_t *pCap)
+{
+ DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
+
+ if (DXS_statusOk == dxs_caps_vers_update(pDev))
+ {
+ pCap->nChannels = pDev->nChannels;
+ pCap->nGR909 = p->fw_caps.GR909;
+ pCap->nACLM = p->fw_caps.ACLM;
+ pCap->nTTX = p->fw_caps.TTX;
+ pCap->nUTD = p->fw_caps.UTD;
+ pCap->nCID = p->fw_caps.CID;
+ pCap->nHowler = p->fw_caps.HOWLER;
+ }
+ else
+ {
+ DXS_RETURN(DXS_statusCapVersUpdateError);
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Function dxs_vers_read
+
+ \param pDev - pointer to DXS device structure
+ \param pVersion - pointer to DXS_Version_t structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_vers_read(DXS_DEVICE_t *pDev, DXS_Version_t *pVersion)
+{
+ DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
+
+ if (DXS_statusOk == dxs_caps_vers_update(pDev))
+ {
+ pVersion->device = p->dev;
+ pVersion->package = p->pack;
+
+ pVersion->fw_maj = p->fw_vers.MAJ;
+ pVersion->fw_min = p->fw_vers.MIN;
+ pVersion->fw_hfix = p->fw_vers.HF;
+ pVersion->fw_time = p->fw_vers.TIME;
+
+ pVersion->lib_ver = DXS_LIB_VERSION;
+ pVersion->api_ver = DXS_API_VERSION;
+ }
+ else
+ {
+ DXS_RETURN(DXS_statusCapVersUpdateError);
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Function dxs_sleep
+
+ \param pDev - pointer to DXS device structure
+ \param enable - enable
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_sleep(DXS_DEVICE_t *pDev, uint8_t enable)
+{
+ DXS_Dev_Caps_t *p;
+ int32_t ret = DXS_statusOk;
+
+ if (pDev == NULL || enable > 1)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_Dev_Caps_t *)pDev->caps;
+
+ if (!(p->flag & DXS_DEV_CAPS_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (!(p->flag & DXS_DEV_SYS_CTRL_UPDATED))
+ {
+ ret = CmdRead(pDev, (uint32_t *)&p->fw_sys_ctrl, (uint32_t *)&p->fw_sys_ctrl);
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(ret);
+ }
+ p->flag |= DXS_DEV_SYS_CTRL_UPDATED;
+ }
+
+ /* sleep mode is not allowed for shared DCDC */
+ if (pDev->dcdcType == DXS_DCDC_IFB12CH8 && enable)
+ {
+ DXS_RETURN(DXS_statusSleepModeNotAllowed);
+ }
+
+ /* update command */
+ if (enable != p->fw_sys_ctrl.SE)
+ {
+ p->fw_sys_ctrl.SE = enable;
+ ret = CmdWrite(pDev, (uint32_t *)&p->fw_sys_ctrl);
+ }
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Check if a particular feature is supported by the device
+
+ \param pDev - pointer to DXS device structure
+ \param cap - feature enumerator \ref e_DXS_DevCaps
+
+ \return
+ - 1 if a featire is supported, 0 if not
+*/
+int32_t DXS_IsFeatureSupported(DXS_DEVICE_t *pDev, enum e_DXS_DevCaps cap)
+{
+ DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
+ DXS_FW_SYS_CAPS_t *pCap = &p->fw_caps;
+ uint32_t sys_read_caps_I1 = *((uint32_t *)pCap + 1);
+
+ if (sys_read_caps_I1 & (1 << cap))
+ return 1;
+
+ return 0;
+}
+
+/**
+ Switch on the Charge Pump
+
+ \param pDev - pointer to DXS device structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_ChargePumpSwitchOn(DXS_DEVICE_t *pDev)
+{
+ DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
+ DXS_FW_SYS_Control_t *pSysCtrl = &p->fw_sys_ctrl;
+ int32_t ret = DXS_statusOk;
+
+ /* for IFB12CH8 apply the configuration only for the device
+ that owns a master channel */
+ if (pDev->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ DXS_CHANNEL_t *pCh, *pChMaster;
+ uint8_t i = 0, master_found = 0;
+
+ if ((pChMaster=DXS_DCDC_HW_SharedDcDcMasterChGetInt(pDev)) != NULL)
+ {
+ for (pCh=&pDev->pChannel[0],i=0; i < pDev->nChannels; i++, pCh++)
+ {
+ if (pCh == pChMaster)
+ {
+ master_found = 1;
+ break;
+ }
+ }
+
+ if (!master_found)
+ return DXS_statusOk;
+ }
+ }
+
+ if (pSysCtrl->CP_EN != 1)
+ {
+ pSysCtrl->CP_VOLT = DXS_FW_SYS_Control_CP_VOLT_5_0V;
+ pSysCtrl->CP_EN = 1;
+ ret = CmdWrite(pDev, (uint32_t *)pSysCtrl);
+ }
+
+ DXS_RETURN(ret);
+}
+
+#if 0
+/**
+ Switch off the Charge Pump
+
+ \param pDev - pointer to DXS device structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_ChargePumpSwitchOff(DXS_DEVICE_t *pDev)
+{
+ DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
+ DXS_FW_SYS_Control_t *pSysCtrl = &p->fw_sys_ctrl;
+ int32_t ret = DXS_statusOk;
+
+ /* for IFB12CH8 apply the configuration only for the device
+ that owns a master channel */
+ if (pDev->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ DXS_CHANNEL_t *pCh, *pChMaster;
+ uint8_t i = 0, master_found = 0;
+
+ if ((pChMaster=DXS_DCDC_HW_SharedDcDcMasterChGetInt(pDev)) != NULL)
+ {
+ for (pCh=&pDev->pChannel[0],i=0; i < pDev->nChannels; i++, pCh++)
+ {
+ if (pCh == pChMaster)
+ {
+ master_found = 1;
+ break;
+ }
+ }
+
+ if (!master_found)
+ return DXS_statusOk;
+ }
+ }
+
+ if (pSysCtrl->CP_EN != 0)
+ {
+ pSysCtrl->CP_EN = 0;
+ ret = CmdWrite(pDev, (uint32_t *)pSysCtrl);
+ }
+
+ DXS_RETURN(ret);
+}
+#endif /* 0 */
+
+/**
+ Switch on/off Clock Failure handling
+
+ \param pDev - pointer to DXS device structure
+ \param enable - 0 or 1
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CfEsdSwitch (DXS_DEVICE_t *pDev, uint8_t enable)
+{
+ DXS_Dev_Caps_t *p;
+ int32_t ret = DXS_statusOk;
+ uint8_t plim;
+
+ if (pDev == NULL || enable > 1)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ p = (DXS_Dev_Caps_t *)pDev->caps;
+
+ if (!(p->flag & DXS_DEV_CAPS_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (!(p->flag & DXS_DEV_SYS_CTRL_UPDATED))
+ {
+ ret = CmdRead(pDev, (uint32_t *)&p->fw_sys_ctrl, (uint32_t *)&p->fw_sys_ctrl);
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(ret);
+ }
+ p->flag |= DXS_DEV_SYS_CTRL_UPDATED;
+ }
+
+ plim = enable ? 0 : 1;
+
+ if (p->fw_sys_ctrl.PLIM != plim || p->fw_sys_ctrl.SYCLKE != enable)
+ {
+ p->fw_sys_ctrl.PLIM = plim;
+ p->fw_sys_ctrl.SYCLKE = enable;
+ ret = CmdWrite(pDev, (uint32_t *)&p->fw_sys_ctrl);
+ }
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Get device info
+
+ \param pDev - pointer to DXS device structure
+ \param pROM_id - ROM mask ID (output)
+ \param pChannels - number of channels (output)
+
+ \return
+ - DXS_status_t
+*/
+void DXS_DevInfoGet (DXS_DEVICE_t *pDev, uint8_t *pROM_id,
+ uint8_t *pChannels)
+{
+ DXS_Dev_Caps_t *p = (DXS_Dev_Caps_t *)pDev->caps;
+
+ *pROM_id = p->fw_vers.MAJ & 0x7f;
+ *pChannels = p->fw_vers.CH ? 1 : 2;
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_init.h b/marvell/services/dxslic/api_lib/src/dxs_init.h
new file mode 100644
index 0000000..c8448f5
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_init.h
@@ -0,0 +1,73 @@
+#ifndef __DXS_INIT_H__
+#define __DXS_INIT_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_init.h
+ Initialization functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs.h"
+#include "dxs_lib.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+enum e_DXS_DevCaps
+{
+ /** GR909 available */
+ dxs_cap_gr909 = 0,
+ /** AC Level Meter Support Available */
+ dxs_cap_aclm,
+ /** Reserved for future use */
+ dxs_cap_reserved,
+ /** Teletax Support Available */
+ dxs_cap_ttx,
+ /** Universal Tone Detector Available */
+ dxs_cap_utd,
+ /** Caller ID Available */
+ dxs_cap_cid,
+ /** Howler Support Available */
+ dxs_cap_howler,
+};
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern DXS_DEVICE_t *dxs_get_dev (uint8_t dxs);
+extern uint8_t dxs_CRC_8_CCITT(uint8_t *pData, uint32_t nLength);
+extern int32_t dxs_init(DXS_DEVICE_t *pDev, uint8_t chipSelect,
+ int32_t irqNumber, uint8_t dcdcType, uint8_t access,
+ uint8_t dev);
+extern int32_t dxs_exit(DXS_DEVICE_t *pDev);
+extern int32_t dxs_caps_vers_update(DXS_DEVICE_t *pDev);
+extern int32_t dxs_caps_vers_forget(DXS_DEVICE_t *pDev);
+extern int32_t dxs_caps_read(DXS_DEVICE_t *pDev, DXS_Caps_t *pCap);
+extern int32_t dxs_vers_read(DXS_DEVICE_t *pDev, DXS_Version_t *pVersion);
+extern int32_t DXS_IsFeatureSupported(DXS_DEVICE_t *pDev,
+ enum e_DXS_DevCaps cap);
+extern int32_t DXS_ChargePumpSwitchOn(DXS_DEVICE_t *pDev);
+#if 0
+extern int32_t DXS_ChargePumpSwitchOff(DXS_DEVICE_t *pDev);
+#endif
+extern int32_t DXS_CfEsdSwitch (DXS_DEVICE_t *pDev, uint8_t on);
+extern void DXS_DevInfoGet (DXS_DEVICE_t *pDev, uint8_t *pROM_id,
+ uint8_t *pChannels);
+extern int32_t dxs_sleep(DXS_DEVICE_t *pDev, uint8_t enable);
+#endif /* __DXS_INIT_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_lib.h b/marvell/services/dxslic/api_lib/src/dxs_lib.h
new file mode 100644
index 0000000..51226db
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_lib.h
@@ -0,0 +1,185 @@
+#ifndef __DXS_LIB_H__
+#define __DXS_LIB_H__
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_lib.h
+ This file contains the device and channel structure definitions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_config.h"
+#include <stdint.h>
+#include <semaphore.h>
+#include <string.h>
+#include <pthread.h>
+#include <endian.h>
+#include "dxs_fifo.h"
+#ifdef EVENT_LOGGER_DEBUG
+#include <linux/ioctl.h>
+#include "el_ioctl.h"
+#endif /* EVENT_LOGGER_DEBUG */
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define CH_PER_DEVICE 2
+
+#ifdef EVENT_LOGGER_DEBUG
+#define DXS_LIB_DEV_TYPE 17
+#endif
+
+#define POINTER_ASSERT(pPointer) \
+ do \
+ { \
+ if (pPointer == NULL) \
+ { \
+ DXS_RETURN(DXS_statusInvalidParam); \
+ } \
+ } while (0)
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+typedef struct dxs_device_t DXS_DEVICE_t;
+typedef struct dxs_channel_t DXS_CHANNEL_t;
+
+/* dxs_hsm.h uses DXS_CHANNEL_t, therefore it should be placed after the
+ * typedef of DXS_CHANNEL_t*/
+#include "dxs_hsm.h"
+
+/** Channel structure */
+struct dxs_channel_t
+{
+ /** channel number starting from 0 */
+ uint8_t nCh;
+ /** status flags */
+#define DXS_CH_BBD_DOWNLOADED 0x00000001
+#define DXS_CH_DIAL_DATA_INITIALIZED 0x00000008
+ volatile uint32_t flags;
+ /** pointer to parent device */
+ DXS_DEVICE_t *pParent;
+ /* mask for event reporting, 64 bits */
+ uint32_t event_mask[2];
+ /** PCM resource */
+ void *pcm;
+ /** SDD resource */
+ void *sdd;
+ /** SIG resource */
+ void *sig;
+#ifdef DXS_FEAT_HSM
+ DXS_DIAL_DATA_t DXS_DialData;
+#endif /* DXS_FEAT_HSM */
+ void *ring;
+};
+
+/** Device structure */
+struct dxs_device_t
+{
+ /** device number */
+ uint8_t nDevNum;
+ /** chip select number */
+ uint8_t chipSelect;
+ /** IRQ line number */
+ int32_t irqNumber;
+ /** DCDC variant */
+ uint8_t dcdcType;
+ /** Access mode */
+ DXS_ACCESS_MODE_t access;
+
+ /** device status flags */
+#define DXS_DEV_INITIALIZED 0x00000001
+#define DXS_DEV_PRAM_PATCH_DOWNLOADED 0x00000002
+#define DXS_DEV_OBX_HND_INITIALIZED 0x00000004
+#define DXS_DEV_ACCESS_INITIALIZED 0x00000008
+ volatile uint32_t flags;
+
+ /** SPI device fd */
+ int spidev;
+
+ /** Device ROM mask version */
+ uint32_t rom_mask_ver;
+ /** Patch download sync sem */
+ sem_t mtxPatchDwld;
+ /** Waiting status flag */
+ volatile uint32_t bWaitingInPatchDwld;
+
+ /** outbox data serving thread */
+ pthread_t obxThread;
+
+ /** outbox data thread semaphore */
+ sem_t obxSemaphore;
+ /** signaling semaphore used by
+ the outbox thread for command
+ read response */
+ sem_t obxCmdDataSem;
+ /** condition to stop the thread */
+ volatile uint8_t obxThreadStop;
+ /** Flag to discard events.
+ Used at startup until the startup finished event is received. */
+ uint8_t obxDiscardEvents;
+
+ /** mailbox access mutex */
+ pthread_mutex_t mtxMbxAcc;
+ /** cached command inbox length */
+ uint8_t nMbxCachedCbiLen;
+
+ /** event queue */
+ FIFO_t *event_queue;
+ /** command outbox data queue */
+ FIFO_t *cmd_obx_queue;
+
+ /** waiting list (the device is a member of) */
+ void *wait_list;
+
+ /* ======= fw capabilities: ====== */
+ /** actual analog channels count */
+ uint8_t nChannels;
+ /** capabilities handler */
+ void *caps;
+ /* === end of fw capabilities: === */
+
+ /* TODO: last error */
+
+ /** device event memory pool */
+ void *event_pool;
+
+ /** pcm resource handler */
+ void *pcm;
+
+ /** GPIO resource */
+ void *gpio;
+
+ /* 2022-3-17, expand array size from 32 to 512.
+ *
+ * DXS_ObxRead does not check array boundary;
+ * This will protect memory afterwards from overwritten.
+ */
+ /** copy of the mailbox */
+ uint16_t dmbx[512];
+
+ /** channel array */
+ DXS_CHANNEL_t pChannel[CH_PER_DEVICE];
+
+#ifdef EVENT_LOGGER_DEBUG
+ int32_t el_fd;
+#endif
+
+};
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+#endif /* __DXS_LIB_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_mbx.c b/marvell/services/dxslic/api_lib/src/dxs_mbx.c
new file mode 100644
index 0000000..d423594
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_mbx.c
@@ -0,0 +1,529 @@
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_mbx.c
+ Implementation of mailbox functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <time.h>
+#include <errno.h>
+
+#include "dxs_lib.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_access.h"
+#ifdef EVENT_LOGGER_DEBUG
+#include <sys/ioctl.h>
+#endif
+
+/*#define DXS_CMD_PRINT*/
+#undef DXS_CMD_PRINT
+
+#ifdef DXS_CMD_PRINT
+ #include <stdio.h>
+#endif
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_WAIT_POLLTIME 50000 /* ns */
+#define DXS_FIBXMS_POLL_LOOP 1000
+
+/** Size of the in message box (Host data message box in) in bytes */
+#define DXS_MBI_SIZE 32 /* 8 words @ 32-bit */
+/** Size of the out message box (Host data message box out) in bytes */
+#define DXS_MBO_SIZE 32 /* 8 words @ 32-bit */
+
+#define RW_WRITE 0
+#define RW_READ 1
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+/** Data structure for firmware command header */
+struct dxs_cmd_hdr
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Read/Write */
+ uint32_t RW : 1;
+ /* Reserved */
+ uint32_t Res00 : 2;
+ /* Command */
+ uint32_t CMD : 5;
+ /* Reserved */
+ uint32_t Res01 : 4;
+ /* Channel */
+ uint32_t CHAN : 4;
+ /* Module */
+ uint32_t MOD : 3;
+ /* Command Sub-Mode */
+ uint32_t ECMD : 5;
+ /* Length of Message */
+ uint32_t LENGTH : 8;
+#else
+ /* Length */
+ uint32_t LENGTH : 8;
+ /* Reserved */
+ uint32_t Res : 23;
+ /* Read write Access */
+ uint32_t RW : 1;
+#endif
+} __attribute__((packed));
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+static int32_t dxs_cmdWrite(
+ DXS_DEVICE_t *pDev,
+ uint32_t *pCmd,
+ uint8_t nCount);
+
+static int32_t dxs_Wait4MBIspace(
+ DXS_DEVICE_t *pDev,
+ uint8_t nCount);
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+#ifdef EVENT_LOGGER_DEBUG
+static void dxs_el_trace_cmd_wr(DXS_DEVICE_t *pDev, struct dxs_cmd_hdr *pMsgHead)
+{
+ EL_IoctlAddLog_t stLog;
+ stLog.nLogType = EL_LOG_TYPE_CMD_WR;
+ stLog.nOrygLogType = EL_MAX_LOG_TYPE;
+ stLog.nDevType = DXS_LIB_DEV_TYPE;
+ stLog.nDevNum = pDev->nDevNum;
+ stLog.nChNum = pMsgHead->CHAN;
+ stLog.uLogDetails.stCmd_Wr.nStatus = IFX_SUCCESS;
+ stLog.uLogDetails.stCmd_Wr.nCmdLength = 4;
+ stLog.uLogDetails.stCmd_Wr.nCount = pMsgHead->LENGTH + 4;
+ stLog.uLogDetails.stCmd_Wr.nDataLength = pMsgHead->LENGTH;
+ stLog.uLogDetails.stCmd_Wr.pCMD = (IFX_char_t *) pMsgHead;
+ stLog.uLogDetails.stCmd_Wr.pDATA = (IFX_char_t *) ((int16_t *) pMsgHead + 2);
+ ioctl(pDev->el_fd, EL_ADD_LOG, (int32_t)&stLog);
+}
+
+static void dxs_el_trace_cmd_rd(DXS_DEVICE_t *pDev, struct dxs_cmd_hdr *pMsgHead)
+{
+ EL_IoctlAddLog_t stLog;
+ stLog.nLogType = EL_LOG_TYPE_CMD_RD;
+ stLog.nOrygLogType = EL_MAX_LOG_TYPE;
+ stLog.nDevType = DXS_LIB_DEV_TYPE;
+ stLog.nDevNum = pDev->nDevNum;
+ stLog.uLogDetails.stCmd_Rd.nStatus = IFX_SUCCESS;
+ stLog.uLogDetails.stCmd_Rd.nCmdLength = 4;
+ stLog.uLogDetails.stCmd_Rd.nCount = pMsgHead->LENGTH + 4;
+ stLog.uLogDetails.stCmd_Rd.nDataLength = pMsgHead->LENGTH;
+ stLog.uLogDetails.stCmd_Rd.pCMD = (IFX_char_t *) pMsgHead;
+ stLog.uLogDetails.stCmd_Rd.pDATA = (IFX_char_t *) ((int16_t*) pMsgHead + 2);
+ ioctl(pDev->el_fd, EL_ADD_LOG, (int32_t)&stLog);
+}
+#endif
+
+/**
+ Function dxs_cmdWrite
+
+ \param pDev - pointer to DXS device structure
+ \param pCmd - pointer to command
+ \param nCount - command length
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_cmdWrite(DXS_DEVICE_t *pDev, uint32_t *pCmd, uint8_t nCount)
+{
+ int32_t ret;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ uint16_t pCmd_le[DXS_MBI_SIZE >> 1];
+ int32_t i;
+#else
+ uint16_t* pCmd_le = (uint16_t *)pCmd;
+#endif
+
+ nCount += sizeof(struct dxs_cmd_hdr);
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ if (nCount > DXS_MBI_SIZE || (nCount % 4))
+ {
+ DXS_RETURN(DXS_statusCmdLengthInvalid);
+ }
+ /* swap 2 byte words */
+ for(i = 0; i < nCount>>2; i++)
+ {
+ pCmd_le[i << 1] = *((uint16_t*)pCmd + (i << 1) + 1);
+ pCmd_le[(i << 1) + 1] = *((uint16_t*)pCmd + (i << 1));
+ }
+#endif
+ /* wait for free space in command inbox */
+ ret = dxs_Wait4MBIspace(pDev, nCount);
+
+ if (ret == DXS_statusOk)
+ {
+ ret = DXS_RegWriteMulti(pDev, DXS_REG_DATA, pCmd_le, nCount>>1);
+ }
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function dxs_Wait4MBIspace
+
+ \param pDev - pointer to DXS device structure
+ \param nCount - count
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_Wait4MBIspace(DXS_DEVICE_t *pDev, uint8_t nCount)
+{
+ int32_t nWaitCnt = 0;
+ uint16_t nReg = 0;
+
+ do
+ {
+ struct timespec ts = {0, DXS_WAIT_POLLTIME};
+
+
+ if (pDev->nMbxCachedCbiLen < nCount)
+ {
+ DXS_RegRead(pDev, DXS_REG_LEN, &nReg);
+ /* shift to get number of bytes from 16bit words */
+ pDev->nMbxCachedCbiLen = (nReg & 0xff) << 1;
+ }
+
+ if (nCount <= pDev->nMbxCachedCbiLen)
+ {
+ /* Sufficient free space in command-inbox to grant the request. */
+ /* Reduce the cache by the amount that was just granted. */
+ pDev->nMbxCachedCbiLen -= nCount;
+ return DXS_statusOk;
+ }
+ /* Not enough free space in the command-inbox, we have to wait until more
+ space becomes available and start the loop again after a short delay.
+ The iterations are limited and the resulting timeout is:
+ (WAIT_POLLTIME * DXT_FIBXMS_POLL_LOOP)us. */
+ nanosleep(&ts, NULL);
+ } while ((++nWaitCnt < DXS_FIBXMS_POLL_LOOP));
+
+#if 0
+ /* exceeded maximum wait time or device error,
+ reset the command-inbox by writing CMDMBX_RES bit */
+ nReg = 1;
+ REG_WRITE_UNPROT(pDev, DXS_REG_CMD, nReg);
+
+ /* poll the HOST_CMD.CMDMBX_RES bit until cleared */
+ do
+ {
+ REG_READ_UNPROT(pDev, DXS_REG_CMD, &nReg);
+ } while (nReg & 1);
+#endif
+
+ DXS_RETURN(DXS_statusCmdIbxNoSpace);
+}
+
+/**
+ Function DXS_CmdWrite
+
+ \param pDev - pointer to DXS device structure
+ \param pCmd - pointer to command
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CmdWrite(DXS_DEVICE_t *pDev, uint32_t *pCmd)
+{
+ struct dxs_cmd_hdr *pMsgHead = (struct dxs_cmd_hdr *)pCmd;
+ int32_t ret, err;
+
+ if (sizeof(struct dxs_cmd_hdr) + pMsgHead->LENGTH > DXS_MBI_SIZE)
+ {
+ DXS_RETURN(DXS_statusCmdLengthInvalid);
+ }
+
+ pMsgHead->RW = RW_WRITE;
+
+ err = pthread_mutex_lock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ ret = dxs_cmdWrite(pDev, pCmd, pMsgHead->LENGTH);
+
+ err = pthread_mutex_unlock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+#ifdef DXS_CMD_PRINT
+ {
+ int i, words = (pMsgHead->LENGTH + sizeof(*pMsgHead))/sizeof(*pMsgHead);
+
+ fprintf (stderr, "[cw] dev:%d err:0x%04X ", pDev->nDevNum, err);
+ for (i=0; i<words; i++)
+ fprintf (stderr, "%08X ", pCmd[i]);
+ fprintf (stderr, "\n");
+ }
+#endif
+#ifdef EVENT_LOGGER_DEBUG
+ dxs_el_trace_cmd_wr(pDev, pMsgHead);
+#endif
+
+ if (ret)
+ {
+ DXS_RETURN(DXS_statusCmdMbxWriteError);
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Function DXS_CmdRead
+
+ \param pDev - pointer to DXS device structure
+ \param pCmd - pointer to command
+ \param pData - pointer to data
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_CmdRead(DXS_DEVICE_t *pDev, uint32_t *pCmd, uint32_t *pData)
+{
+ struct dxs_cmd_hdr *pMsgHead = (struct dxs_cmd_hdr *)pCmd;
+ int32_t ret = DXS_statusOk, err;
+ uint8_t nReadBytes, nExpectedBytes, nCnt = 0;
+ struct timespec ts = {0};
+#ifdef DXS_CMD_PRINT
+ /* just for logging */
+ uint32_t *pw = pData;
+#endif
+ uint8_t runs;
+
+ if (pMsgHead->LENGTH > DXS_MBO_SIZE)
+ {
+ DXS_RETURN(DXS_statusCmdLengthInvalid);
+ }
+
+ err = pthread_mutex_lock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ /* Write the read request */
+ pMsgHead->RW = RW_READ;
+ if ((ret = dxs_cmdWrite(pDev, pCmd, 0)) != DXS_statusOk)
+ {
+ err = pthread_mutex_unlock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ DXS_RETURN(DXS_statusCmdMbxWriteError);
+ }
+
+ /* This is the number of bytes we are going to read. */
+ nExpectedBytes = sizeof(struct dxs_cmd_hdr) + pMsgHead->LENGTH;
+
+ /* make 3 read attempts with 1 sec interval */
+ runs = 0;
+ do
+ {
+ /* schedule obxThread for execution */
+ sem_post(&pDev->obxSemaphore);
+ /* wait 1s */
+ clock_gettime (CLOCK_REALTIME, &ts);
+ ts.tv_sec += 1;
+ ret = sem_timedwait(&pDev->obxCmdDataSem, &ts);
+ } while(++runs < 3 && ret);
+
+ if (runs == 3 && ret == -1 && errno == ETIMEDOUT)
+ {
+ err = pthread_mutex_unlock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ DXS_RETURN(DXS_statusCmdObDataRdTmout);
+ }
+ else if (ret != 0)
+ {
+ err = pthread_mutex_unlock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ DXS_RETURN(DXS_statusCmdObRdErr);
+ }
+
+ /* nCnt is a number of elements, 32-bit each */
+ nCnt = fifo_count (pDev->cmd_obx_queue);
+ nReadBytes = (nCnt * sizeof(uint32_t));
+
+ if (nReadBytes > nExpectedBytes)
+ {
+ /* more data than expected */
+#ifdef DXS_CMD_PRINT
+ fprintf (stderr,
+ "[cr] dev:%d ERROR excess data. Read:%d Expected:%d -",
+ pDev->nDevNum, nReadBytes, nExpectedBytes);
+ while (nCnt--)
+ {
+ void *pdummy;
+ uint32_t nData;
+
+ /* Clear the fifo by reading it and print the content. */
+ fifo_get (pDev->cmd_obx_queue, &pdummy, &nData);
+ fprintf (stderr, " %08X", nData);
+ }
+ fprintf (stderr, "\n");
+#else
+ /* Discard all data. The error code will report this event. */
+ fifo_flush (pDev->cmd_obx_queue);
+#endif
+ err = pthread_mutex_unlock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ DXS_RETURN(DXS_statusCmdObDataOvld);
+ }
+
+ while (nCnt--)
+ {
+ void *pdummy;
+
+ /* read the data from the fifo to pData */
+ fifo_get (pDev->cmd_obx_queue, &pdummy, pData++);
+ }
+
+ err = pthread_mutex_unlock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+#ifdef EVENT_LOGGER_DEBUG
+ dxs_el_trace_cmd_rd(pDev, pMsgHead);
+#endif
+
+#ifdef DXS_CMD_PRINT
+ {
+ int i, words = (pMsgHead->LENGTH + sizeof(*pMsgHead))/sizeof(*pMsgHead);
+
+ fprintf (stderr, "[cr] dev:%d return:0x%04X - ", pDev->nDevNum, ret);
+ for (i=0; i<words; i++)
+ fprintf (stderr, " %08X", pw[i]);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ return DXS_statusOk;
+}
+
+/**
+ Download binary into patch ram.
+
+ The given data is sent in to the mailbox. This code takes care of
+ fragmenting it into chunks of the size of the mailbox.
+ Note that the download does not need to read the mailbox length register
+ and wait for enough space to be available because the DXS reads the patch
+ faster out of the mailbox than it can be filled via the SPI interface.
+
+ \param pDev pointer to the device interface
+ \param pBuffer Pointer to Buffer for download
+ \param nSize size of the buffer in bytes
+ \return
+ Error code.
+*/
+int32_t DXS_DwldPatch ( DXS_DEVICE_t *pDev,
+ uint8_t *pBuffer,
+ uint32_t nSize)
+{
+ int32_t ret = DXS_statusOk, err;
+ uint32_t pos = 0,
+ remaining = nSize,
+ fragment,
+ fragment_limit;
+ uint16_t pBuf[DXS_MBI_SIZE>>1];
+
+ if ((pBuffer == NULL) || (nSize == 0))
+ {
+ /* errmsg: At least one parameter is wrong. */
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ /* Find the maximum size a fragment may have to pass through SPI without
+ incurring addtional fragmentation there. */
+ fragment_limit = DXS_spi_blocksize_get(pDev);
+
+ err = pthread_mutex_lock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ /* write all data */
+ while ((remaining > 0) && (ret == DXS_statusOk))
+ {
+ /* calculate length of fragment: note that count is in bytes */
+ fragment = (remaining > DXS_MBI_SIZE) ? DXS_MBI_SIZE : remaining;
+ fragment = (fragment > fragment_limit) ? fragment_limit : fragment;
+ /* ensure that the fragment has a multiple of 4 bytes */
+ fragment = fragment - (fragment % 4);
+
+ /* copy into the output buffer */
+ DXS_cpb2w(pBuf, &pBuffer[pos], fragment);
+
+ ret = DXS_RegWriteMulti(pDev, DXS_REG_DATA, pBuf, fragment>>1);
+ /* increment position */
+ pos += fragment;
+ /* decrement count */
+ remaining -= fragment;
+ } /* while */
+
+ err = pthread_mutex_unlock (&pDev->mtxMbxAcc);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ DXS_RETURN(ret);
+}
+
+/**
+ DXS_ObxRead - read DATA outbox content
+
+ \param pDev - pointer to DXS device structure
+ \param pData - buffer where to store data
+ \param len - returned data length in 16-bit words
+
+*/
+void DXS_ObxRead(DXS_DEVICE_t *pDev, uint16_t *pData, uint8_t *len)
+{
+ uint16_t nHostLen;
+ uint8_t words = 0; /* 16-bit words */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ int32_t i;
+ uint16_t tmp;
+#endif
+
+ /* read HOST_LEN */
+ DXS_RegRead(pDev, DXS_REG_LEN, &nHostLen);
+
+ words = nHostLen >> 8;
+
+ if (words > 0)
+ {
+ /* Read from HOST_DATA, the out mailbox. */
+ DXS_RegReadMulti(pDev, DXS_REG_DATA, pData, words);
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ /* swap 2 byte words */
+ for (i = 0; i < words >> 1; i++)
+ {
+ tmp = pData[i << 1];
+ pData[i << 1] = pData[(i << 1) + 1];
+ pData[(i << 1) + 1] = tmp;
+ }
+#endif
+ }
+
+ *len = words;
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_mbx.h b/marvell/services/dxslic/api_lib/src/dxs_mbx.h
new file mode 100644
index 0000000..9e3eb1d
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_mbx.h
@@ -0,0 +1,55 @@
+#ifndef __DXS_MBX_H__
+#define __DXS_MBX_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_mbx.h
+ Mailbox functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_lib.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define CmdWrite DXS_CmdWrite
+#define CmdRead DXS_CmdRead
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern int32_t DXS_CmdWrite(
+ DXS_DEVICE_t *pDev,
+ uint32_t *pCmd);
+
+extern int32_t DXS_CmdRead(
+ DXS_DEVICE_t *pDev,
+ uint32_t *pCmd,
+ uint32_t *pData);
+
+extern int32_t DXS_DwldPatch (
+ DXS_DEVICE_t *pDev,
+ uint8_t *pBuffer,
+ uint32_t nSize);
+extern void DXS_ObxRead(
+ DXS_DEVICE_t *pDev,
+ uint16_t *pData,
+ uint8_t *len);
+
+#endif /* __DXS_MBX_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_mempool.c b/marvell/services/dxslic/api_lib/src/dxs_mempool.c
new file mode 100644
index 0000000..df53b71
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_mempool.c
@@ -0,0 +1,354 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_mempool.c
+ XXXXXX
+
+ \remarks
+ XXXXXX
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdlib.h>
+#include <pthread.h>
+#include "dxs_mempool.h"
+#include "dxs_error.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_MAX_MEMPOOLS 16
+#define DXS_MAX_MEMPOOL_ELEMENTS 32
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+struct __mempool
+{
+ uint8_t in_use;
+ pthread_mutex_t mtx;
+ struct __buffer *free;
+ struct __buffer *allocated;
+};
+
+struct __buffer
+{
+ void *p;
+ struct __buffer *next;
+};
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+static struct __mempool mempool[DXS_MAX_MEMPOOLS] = {{0},};
+static struct __buffer buffers[DXS_MAX_MEMPOOLS * DXS_MAX_MEMPOOL_ELEMENTS];
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/**
+ Initialize a memory buffer pool.
+
+ \param mem Address of continuous memory block
+ on which to organize a pool.
+ \param size Size of continuous memory block in bytes.
+ \param elem_num Number of buffers to create.
+ \param elem_size Size of each individual buffer in bytes.
+ \param *pool_id pool instance to return.
+
+ \return
+ DXS_MPOOL_OK success
+ DXS_MPOOL_PARAMS invalid parameters
+ DXS_MPOOL_NOT_ENOUGH not enough memory for a pool
+ DXS_MPOOL_NO_FREE_POOLS cannot allocate a pool
+*/
+int32_t mempool_init(void *mem, uint32_t size, uint16_t elem_num,
+ uint16_t elem_size, void **pool_id)
+{
+ int i, err;
+ struct __mempool *pool;
+ struct __buffer *curr;
+
+ if (mem == NULL || size == 0)
+ return DXS_MPOOL_PARAMS;
+
+ if (elem_num > DXS_MAX_MEMPOOL_ELEMENTS)
+ elem_num = DXS_MAX_MEMPOOL_ELEMENTS;
+
+ if ((elem_num * elem_size) > size)
+ return DXS_MPOOL_NOT_ENOUGH;
+
+ /* get next available pool */
+ for (i=0; i<DXS_MAX_MEMPOOLS; i++)
+ {
+ pool = &mempool[i];
+ if (!pool->in_use)
+ break;
+ }
+
+ if (i == DXS_MAX_MEMPOOLS)
+ {
+ /* cannot allocate a free pool */
+ return DXS_MPOOL_NO_FREE_POOLS;
+ }
+
+ pool->in_use = 1;
+ pthread_mutex_init(&pool->mtx, NULL);
+
+ err = pthread_mutex_lock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ /* create a head node */
+ curr = pool->free = &buffers[i * DXS_MAX_MEMPOOL_ELEMENTS];
+ curr->p = mem;
+ curr->next = NULL;
+
+ /* initialize remaining nodes */
+ for (i=1; i<elem_num; i++)
+ {
+ /* get the new buffer */
+ struct __buffer *b = pool->free + i;
+
+ b->p = (void *)((uint8_t *)mem + i * elem_size);
+ b->next = NULL;
+
+ /* add the new buffer to the tail */
+ curr->next = b;
+ curr = b;
+ }
+
+ /* allocated list is initially empty */
+ pool->allocated = NULL;
+
+ /* return a pool instance */
+ *pool_id = (void *)pool;
+
+ err = pthread_mutex_unlock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ return DXS_MPOOL_OK;
+}
+
+/**
+ Get a buffer from the pool.
+
+ \param pool_id Memory pool selector.
+
+ \return
+ A memory buffer or NULL in case of an error.
+*/
+void *mempool_get(void *pool_id)
+{
+ int err;
+ struct __mempool *pool = (struct __mempool *)pool_id;
+ struct __buffer *buff;
+
+ /* TODO: trap on wild pool_id ? */
+
+ err = pthread_mutex_lock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ /* get the buffer from the free list head */
+ buff = pool->free;
+ if (buff == NULL)
+ {
+ /* empty list - no buffers available */
+ err = pthread_mutex_unlock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ return (void *)NULL;
+ }
+
+ /* advance the free list head */
+ pool->free = buff->next;
+
+ /* buff now goes to the tail of the allocated list */
+ buff->next = NULL;
+ if (pool->allocated == NULL)
+ {
+ pool->allocated = buff;
+ }
+ else
+ {
+ struct __buffer *b = pool->allocated;
+
+ while (b->next != NULL)
+ b = b->next;
+
+ b->next = buff;
+ }
+
+ err = pthread_mutex_unlock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ return (buff->p);
+}
+
+/**
+ Return a buffer to the pool.
+
+ \param pool_id Memory pool selector.
+ \param p Memory buffer to return to the pool.
+
+ \return
+ DXS_MPOOL_OK
+ DXS_MPOOL_BUF_NOT_FOUND
+*/
+int32_t mempool_put(void *pool_id, void *p)
+{
+ struct __mempool *pool = (struct __mempool *)pool_id;
+ struct __buffer *prev = NULL, *buff;
+ uint8_t found = 0;
+ int err;
+
+ /* TODO: trap on wild pool_id ? */
+
+ err = pthread_mutex_lock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ buff = pool->allocated;
+
+ /* search the allocated list for the buffer */
+ while (buff != NULL)
+ {
+ if (buff->p == p)
+ {
+ found = 1;
+ break;
+ }
+ else
+ {
+ prev = buff;
+ buff = buff->next;
+ }
+ }
+
+ if (!found)
+ {
+ /* buffer is not found in the allocated list */
+ err = pthread_mutex_unlock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ return DXS_MPOOL_BUF_NOT_FOUND;
+ }
+
+ /* remove buff from the allocated list */
+ if (prev != NULL)
+ prev->next = buff->next;
+ else
+ pool->allocated = buff->next;
+
+ /* add buff to the tail of the free list */
+ buff->next = NULL;
+ if (pool->free == NULL)
+ {
+ pool->free = buff;
+ }
+ else
+ {
+ struct __buffer *b = pool->free;
+
+ while (b->next != NULL)
+ b = b->next;
+
+ b->next = buff;
+ }
+
+ err = pthread_mutex_unlock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ return DXS_MPOOL_OK;
+}
+
+/**
+ Obtain the number of busy and free buffers in a pool.
+
+ \param pool_id Memory pool selector.
+ \param *busy Returned parameter reflecting number of busy buffers.
+ \param *free Returned parameter reflecting number of free buffers.
+
+ \return
+ None.
+*/
+void mempool_status(void *pool_id, uint16_t *busy, uint16_t *free)
+{
+ struct __mempool *pool = (struct __mempool *)pool_id;
+ struct __buffer *b;
+ int err;
+
+ /* TODO: trap on wild pool_id ? */
+
+ err = pthread_mutex_lock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ *free = 0;
+ b = pool->free;
+ if (b != NULL)
+ {
+ while (b != NULL)
+ {
+ (*free)++;
+ b = b->next;
+ }
+ }
+
+ *busy = 0;
+ b = pool->allocated;
+ if (b != NULL)
+ {
+ while (b != NULL)
+ {
+ (*busy)++;
+ b = b->next;
+ }
+ }
+
+ err = pthread_mutex_unlock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+}
+
+/**
+ Destroy a memory buffer pool.
+
+ \param pool_id Memory pool selector.
+
+ \return
+ None.
+*/
+void mempool_destroy(void *pool_id)
+{
+ struct __mempool *pool = (struct __mempool *)pool_id;
+ int err;
+
+ /* TODO: trap on wild pool_id ? */
+
+ err = pthread_mutex_lock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ pool->in_use = 0;
+ err = pthread_mutex_unlock (&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ err = pthread_mutex_destroy(&pool->mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_mempool.h b/marvell/services/dxslic/api_lib/src/dxs_mempool.h
new file mode 100644
index 0000000..49a0564
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_mempool.h
@@ -0,0 +1,49 @@
+#ifndef __DXS_MEMPOOL_H__
+#define __DXS_MEMPOOL_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_mempool.h
+ XXXXXX
+
+ \remarks
+ XXXXXX
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdint.h>
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* return codes */
+#define DXS_MPOOL_OK 0
+#define DXS_MPOOL_PARAMS (-1)
+#define DXS_MPOOL_NOT_ENOUGH (-2)
+#define DXS_MPOOL_NO_FREE_POOLS (-3)
+#define DXS_MPOOL_BUF_NOT_FOUND (-4)
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+extern int32_t mempool_init(void *mem, uint32_t size, uint16_t elem_num,
+ uint16_t elem_size, void **pool_id);
+extern void *mempool_get(void *pool_id);
+extern int32_t mempool_put(void *pool_id, void *p);
+extern void mempool_status(void *pool_id, uint16_t *busy, uint16_t *free);
+extern void mempool_destroy(void *pool_id);
+
+#endif /* __DXS_MEMPOOL_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_misc.c b/marvell/services/dxslic/api_lib/src/dxs_misc.c
new file mode 100644
index 0000000..8739339
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_misc.c
@@ -0,0 +1,436 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_misc.c
+ This file contains the implementation of the miscellaneous functions.
+*/
+
+/* ========================================================================= */
+/* Includes */
+/* ========================================================================= */
+#include "dxs_misc.h"
+
+/* ========================================================================= */
+/* Macro definitions */
+/* ========================================================================= */
+#define Q 15
+#define Q_PRECISION 1
+#define Q_ABS(a) ((a) < 0 ? -(a) : (a))
+
+/* ========================================================================= */
+/* Function implementation */
+/* ========================================================================= */
+
+/**
+ Rotate right (circular shift) an arbitrary data block for up to 8 bits
+ FIXME - data block length is a multiple of bytes, change to multiple of bits
+
+ \param data - pointer to the beginning of the data block
+ \param n - length of the data block in bytes
+ \param shift - number of bits to shift (min=0, max=8)
+
+ \return
+ - none
+*/
+static void dxs_misc_data_blk_ror8 (unsigned char *data, int n, int shift)
+{
+ int i;
+ unsigned char tmp = data[n-1];
+
+ for (i=n-1; i>0; i--)
+ data[i] = (data[i] >> shift)|((data[i-1] & (0xff >> (8 - shift))) << (8-shift));
+ data[0] = (data[0] >> shift)|((tmp & (0xff >> (8 - shift))) << (8-shift));
+}
+
+/**
+ Rotate right (circular shift) an arbitrary data block
+
+ \param data - pointer to the beginning of the data block
+ \param len - length of the data block in bytes
+ \param shift - number of bits to shift
+
+ \return
+ - none
+*/
+void DXS_Misc_DataBlkRor (unsigned char *data, int len, int shift)
+{
+ int i;
+
+ for (i=0; i<(shift >> 3); i++)
+ dxs_misc_data_blk_ror8(data, len, 8);
+ dxs_misc_data_blk_ror8(data, len, (shift % 8));
+}
+
+/**
+ Function DXS_Misc_MulQ15
+
+ \param a - Q15 number
+ \param b - Q15 number
+
+ \return
+ - uint16_t multiplication result of two Q15 numbers
+*/
+uint16_t DXS_Misc_MulQ15 (int16_t a, int16_t b)
+{
+ signed long int temp;
+
+ temp = (long int)a * (long int)b;
+ /* Rounding up */
+ temp += (1 << (Q-1));
+
+ /* Correct by dividing by base */
+ return (temp >> Q);
+}
+
+/**
+ Function DXS_Misc_LeveldB_to_Factor
+
+ \param dB_ten - integer value in units of 0.1 dB
+ \remark Parameter dB_ten must be zero or negative.
+
+ \return
+ - uint16_t factor in Q15 format
+*/
+uint16_t DXS_Misc_LeveldB_to_Factor (int16_t dB_ten)
+{
+ int16_t n, r, hundr, tens, units, mul1 = 32767, mul2 = 32767;
+
+ /* switch to 0.01 dB units */
+ dB_ten *= 10;
+
+ /* calculate factors of 0.5 */
+ n = dB_ten / -602;
+
+ /* calculate reminder */
+ r = -dB_ten - n * 602;
+
+ hundr = r / 100;
+ tens = (r % 100) / 10;
+ units = (r % 100) % 10;
+
+ while (n--)
+ {
+ /* multiply 0.5 n times */
+ mul1 = DXS_Misc_MulQ15(mul1, 16384);
+ }
+
+ while (hundr--)
+ {
+ /* multiply 0.891251 (1dB) hundr times */
+ mul2 = DXS_Misc_MulQ15(mul2, 29205);
+ }
+
+ while (tens--)
+ {
+ /* multiply 0.988553 (0.1dB) tens times */
+ mul2 = DXS_Misc_MulQ15(mul2, 32393);
+ }
+
+ while (units--)
+ {
+ /* multiply 0.998849 (0.01dB) units times */
+ mul2 = DXS_Misc_MulQ15(mul2, 32730);
+ }
+
+ return (DXS_Misc_MulQ15(mul1, mul2));
+}
+
+/*
+ * alt_method
+ *
+ * - parameter dB_t - integer, in 0.1 dB units, must be negative
+ *
+ */
+uint16_t DXS_Misc_PowerdB_to_Factor (int16_t dB_t)
+{
+ int16_t n, r, hundr, tens, units, mul1 = 32767, mul2 = 32767;
+
+ /* switch to 0.01 dB units */
+ dB_t *= 10;
+
+ /* calculate factors of 0.5 */
+ n = dB_t / -301;
+
+ /* calculate reminder */
+ r = -dB_t - n * 301;
+
+ hundr = r / 100;
+ tens = (r % 100) / 10;
+ units = (r % 100) % 10;
+
+ while (n--)
+ {
+ /* multiply 0.5 n times */
+ mul1 = DXS_Misc_MulQ15(mul1, 16384);
+ }
+
+ while (hundr--)
+ {
+ /* multiply 0.794328 (1dB) hundr times */
+ mul2 = DXS_Misc_MulQ15(mul2, 26029);
+ }
+
+ while (tens--)
+ {
+ /* multiply 0.977237 (0.1dB) tens times */
+ mul2 = DXS_Misc_MulQ15(mul2, 32022);
+ }
+
+ while (units--)
+ {
+ /* multiply 0.9977 (0.01dB) units times */
+ mul2 = DXS_Misc_MulQ15(mul2, 32693);
+ }
+
+ return (DXS_Misc_MulQ15 (mul1, mul2));
+}
+
+/**
+ Function DXS_Misc_RoundDiv
+
+ \param dividend
+ \param divisor
+
+ \return
+ - uint32_t division result
+*/
+uint32_t DXS_Misc_RoundDiv(uint32_t dividend, uint32_t divisor)
+{
+ return (dividend + (divisor >> 1)) / divisor;
+}
+
+/******************************************************************************/
+/* Fixed Point Calculations in Q4.27 format */
+/******************************************************************************/
+#if 0
+/**
+ Q4.27 Division
+
+ \param a - dividend in Q4.27
+ \param b - divisor in Q4.27
+ \return - a/b in Q4.27
+*/
+static int32_t q4_27_div (int32_t a, int32_t b)
+{
+ int64_t temp = ((int64_t)a) << 27;
+
+ /* round up */
+ temp += (b >> 1);
+
+ return (temp / b);
+}
+
+/**
+ Q4.27 Square Root
+
+ \param a - argument in Q4.27
+ \return
+ - sqrt(a) in Q4.27
+*/
+int32_t DXS_Misc_Q4_27_Sqrt(int32_t a)
+{
+ int32_t x0, x1;
+
+ if (a == 0) return a;
+
+ /* initial guess */
+ x0 = a;
+
+ /* Newton's formula */
+ while (1)
+ {
+ x1 = (x0 + q4_27_div(a, x0)) >> 1;
+
+ if (Q_ABS(x1-x0) <= Q_PRECISION)
+ break;
+
+ x0 = x1;
+ }
+
+ return x1;
+}
+#endif /* 0 */
+
+/**
+ Convert float to Q4.27
+
+ \param f - floating point number
+ \return
+ - Q4.27 representation of f
+*/
+int32_t DXS_Misc_Float_to_Q4_27 (float f)
+{
+ f *= 134217728.0f;
+ /* round up */
+ f += (f >= 0) ? 0.5 : -0.5;
+
+ return (int32_t)f;
+}
+
+/**
+ Convert Q4.27 to float
+
+ \param q - Q4.27 number
+ \return
+ - floating point representaion of Q4.27 q
+*/
+float DXS_Misc_Q4_27_to_Float (int32_t q)
+{
+ return ((float)q / 134217728.0f);
+}
+
+/**
+ Q4.27 Multiplication
+
+ \param a - Q4.27 number
+ \param b - Q4.27 number
+ \return
+ - (a*b) in Q4.27 format
+*/
+int32_t DXS_Misc_Q4_27_Mul (int32_t a, int32_t b)
+{
+ int64_t tmp = (int64_t)a * (int64_t)b;
+
+ /* round up */
+ tmp += (1 << 26);
+
+ return (int32_t)(tmp >> 27);
+}
+
+/******************************************************************************/
+/* Fixed Point Calculations in Q15.16 format */
+/******************************************************************************/
+#define Q15_16_LN_10 0x24D76
+
+/**
+ Q15.16 Division
+
+ \param a - dividend in Q15.16
+ \param b - divisor in Q15.16
+ \return - a/b in Q15.16
+*/
+static int32_t q15_16_div (int32_t a, int32_t b)
+{
+ int64_t temp = ((int64_t)a) << 16;
+
+ /* round up */
+ temp += (b >> 1);
+
+ return (temp / b);
+}
+
+/**
+ Q15.16 Multiplication
+
+ \param a - Q15.16 number
+ \param b - Q15.16 number
+ \return - (a*b) in Q15.16
+*/
+static int32_t q15_16_mul (int32_t a, int32_t b)
+{
+ int64_t tmp = (int64_t)a * (int64_t)b;
+
+ /* round up */
+ tmp += (1 << 15);
+
+ return (int32_t)(tmp >> 16);
+}
+
+/**
+ Q15.16 Power
+
+ \param a - Q15.16 number
+ \param pw - power, conventional integer, not Q
+ \return - (a^pw) in Q15.16
+*/
+static int32_t q15_16_pow (int32_t a, int32_t pw)
+{
+ int32_t result = Q15_16_ONE;
+ int32_t (*op)(int32_t a, int32_t b);
+
+ if (pw < 0)
+ {
+ op = q15_16_div;
+ pw = -pw;
+ }
+ else
+ op = q15_16_mul;
+
+ while (pw--)
+ result = op(result, a);
+
+ return result;
+}
+
+/**
+ Convert float to Q15.16
+
+ \param f - floating point number
+ \return - Q15.16 representation of f
+*/
+int32_t DXS_Misc_Float_to_Q15_16 (float f)
+{
+ f *= 65536.0f;
+ /* round up */
+ f += (f >= 0) ? 0.5 : -0.5;
+
+ return (int32_t)f;
+}
+
+/**
+ Convert Q15.16 to float
+
+ \param q - Q15.16 number
+ \return - floating point representation of q
+*/
+float DXS_Misc_Q15_16_to_Float (int32_t q)
+{
+ return ((float)q / 65536.0f);
+}
+
+/**
+ Common logarithm calculation
+
+ \param a - argument in Q15.16
+ \return - log10(a) in Q15.16
+*/
+int32_t DXS_Misc_Q15_16_Log10 (int32_t a)
+{
+ int32_t k=Q15_16_ONE, p=1, result=0, tmp=0;
+
+ while (1)
+ {
+ /* Taylor series */
+ result +=
+ (q15_16_mul(q15_16_pow(-Q15_16_ONE, (p+1)),
+ q15_16_div(q15_16_pow((a-Q15_16_ONE), p), k)));
+
+ if (Q_ABS(result-tmp) <= Q_PRECISION)
+ break;
+
+ tmp = result;
+ k += Q15_16_ONE;
+ p++;
+ }
+
+ return q15_16_div(result, Q15_16_LN_10);
+}
+
+int32_t DXS_Misc_Q15_16_Mul(int32_t a, int32_t b)
+{
+ return q15_16_mul (a, b);
+}
+
+int32_t DXS_Misc_Q15_16_Div(int32_t a, int32_t b)
+{
+ return q15_16_div (a, b);
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_misc.h b/marvell/services/dxslic/api_lib/src/dxs_misc.h
new file mode 100644
index 0000000..23ba071
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_misc.h
@@ -0,0 +1,66 @@
+#ifndef __DXS_MISC_H__
+#define __DXS_MISC_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_misc.h
+ Miscellaneous functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdint.h>
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern uint16_t DXS_Misc_MulQ15 (int16_t a, int16_t b);
+extern uint16_t DXS_Misc_LeveldB_to_Factor (int16_t dB_ten);
+extern uint16_t DXS_Misc_PowerdB_to_Factor (int16_t dB_t);
+extern uint32_t DXS_Misc_RoundDiv(uint32_t dividend, uint32_t divisor);
+/******************************************************************************/
+/* Fixed Point Calculations in Q4.27 format */
+/******************************************************************************/
+#define Q4_27_ONE (1 << 27)
+#define Q4_27_TEN (10 * Q4_27_ONE)
+/*extern int32_t DXS_Misc_Q4_27_Sqrt(int32_t a);*/
+extern int32_t DXS_Misc_Float_to_Q4_27 (float f);
+extern float DXS_Misc_Q4_27_to_Float (int32_t q);
+extern int32_t DXS_Misc_Q4_27_Mul (int32_t a, int32_t b);
+/******************************************************************************/
+/* Fixed Point Calculations in Q15.16 format */
+/******************************************************************************/
+#define Q15_16_ONE (1 << 16)
+#define Q15_16_HALF (Q15_16_ONE >> 1)
+#define Q15_16_TEN (10 * Q15_16_ONE)
+#define Q15_16_TWENTY (2 * Q15_16_TEN)
+#define Q15_16__3_14 0x323D7
+extern int32_t DXS_Misc_Float_to_Q15_16 (float f);
+extern float DXS_Misc_Q15_16_to_Float (int32_t q);
+extern int32_t DXS_Misc_Q15_16_Log10 (int32_t a);
+extern int32_t DXS_Misc_Q15_16_Mul(int32_t a, int32_t b);
+extern int32_t DXS_Misc_Q15_16_Div(int32_t a, int32_t b);
+/******************************************************************************/
+/* Other functions */
+/******************************************************************************/
+extern void DXS_Misc_DataBlkRor (unsigned char* , int , int );
+
+#endif /* __DXS_MISC_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_outbox.c b/marvell/services/dxslic/api_lib/src/dxs_outbox.c
new file mode 100644
index 0000000..5a347f9
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_outbox.c
@@ -0,0 +1,918 @@
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_outbox.c
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdio.h>
+#include <errno.h>
+
+#include "dxs_config.h"
+#include "dxs.h"
+#include "dxs_lib.h"
+#include "dxs_mbx.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_event.h"
+#include "dxs_sdd.h"
+#include "dxs_sig.h"
+#include "dxs_cid_fsk.h"
+#include "dxs_cid.h"
+#include "dxs_init.h"
+#include "dxs_dcdc_hw.h"
+#ifdef EVENT_LOGGER_DEBUG
+#include <sys/ioctl.h>
+#endif
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+/*#define DXS_CMD_PRINT*/
+#undef DXS_CMD_PRINT
+//#define DXS_CMD_PRINT
+
+/* SDD events */
+/** Over temperature detected */
+#define EVT_SDD_OTEMP 0
+/** Line testing finished */
+#define EVT_SDD_LT_FIN 1
+/** Ground fault detected */
+#define EVT_SDD_GF 3
+/** Ground key detected */
+#define EVT_SDD_GK 4
+/** Opmode changed */
+#define EVT_SDD_OPC 5
+/** Error in command SDD_CoeffReadConfig */
+#define EVT_SDD_CORCE 6
+/** Error in command SDD_Coeff */
+#define EVT_SDD_COEFE 7
+/** On-hook */
+#define EVT_SDD_ONH 9
+/** Off-hook */
+#define EVT_SDD_OFFH 10
+/** Ground Fault Finished */
+#define EVT_SDD_GF_FIN 12
+/** Ground Key Finished */
+#define EVT_SDD_GK_FIN 13
+/** Overtemp finished which means that
+ SLIC temperature is back in normal range */
+#define EVT_SDD_OTEMP_FIN 14
+/** Operating Mode Ignored */
+#define EVT_SDD_OMI 17
+/** Operating Mode discarded */
+#define EVT_SDD_OPM_DIS 18
+/** Line testing aborted */
+#define EVT_SDD_LT_ABORT 19
+
+/* SIG events */
+/** DTMF detector */
+#define EVT_SIG_DTMF_DET 1
+/** Caller ID sender request */
+#define EVT_SIG_CIS_REQ 2
+/** Caller ID sender buffer underflow */
+#define EVT_SIG_CIS_BUF 3
+/** Caller ID sender has finished sending data */
+#define EVT_SIG_CIS_FIN 4
+/** Start of tone detected */
+#define EVT_SIG_UTD_START 5
+/** End of tone detected */
+#define EVT_SIG_UTD_END 6
+/** Metering pulse sent */
+#define EVT_SIG_TTX_FIN 9
+/** AC level metering finished */
+#define EVT_SIG_AC_LM_FIN 10
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+struct __fw_evt_header
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Reserved */
+ uint32_t Res00 : 3;
+ /* Command Type */
+ uint32_t CMD : 5;
+ /* Channel */
+ uint32_t CHAN : 8;
+ /* Command Mode */
+ uint32_t MOD : 3;
+ /* Command Sub-Mode */
+ uint32_t ECMD : 5;
+ /* Length of Command Payload */
+ uint32_t LENGTH : 8;
+#else
+ /* Length of Command Payload */
+ uint32_t LENGTH : 8;
+ /* Command Sub-Mode */
+ uint32_t ECMD : 5;
+ /* Command Mode */
+ uint32_t MOD : 3;
+ /* Channel */
+ uint32_t CHAN : 8;
+ /* Command Type */
+ uint32_t CMD : 5;
+ /* Reserved */
+ uint32_t Res00 : 3;
+#endif
+} __attribute__ ((packed));
+
+struct __fw_evt_int_err
+{
+ struct __fw_evt_header hdr;
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Reserved */
+ uint32_t Res01 : 27;
+ /* Event Code */
+ uint32_t ERREVT : 5;
+#else
+ /* Event Code */
+ uint32_t ERREVT : 5;
+ /* Reserved */
+ uint32_t Res01 : 27;
+#endif
+} __attribute__ ((packed));
+
+struct __fw_evt_cmd_err
+{
+ struct __fw_evt_header hdr;
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Reserved */
+ uint32_t Res01 : 18;
+ /* Error Cause */
+ uint32_t CMDERR : 14;
+ /* Command Header of Command */
+ uint32_t CMDHDR;
+#else
+ /* Error Cause */
+ uint32_t CMDERR : 14;
+ /* Reserved */
+ uint32_t Res01 : 18;
+ /* Command Header of Command */
+ uint32_t CMDHDR;
+#endif
+} __attribute__ ((packed));
+
+struct __fw_evt_sdd
+{
+ struct __fw_evt_header hdr;
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Time Stamp */
+ uint32_t TIME_STAMP : 16;
+ /* Analog line operating mode */
+ uint32_t OPMODE : 8;
+ /* Reserved */
+ uint32_t Res01 : 3;
+ /* Event code */
+ uint32_t EVT : 5;
+#else
+ /* Event code */
+ uint32_t EVT : 5;
+ /* Reserved */
+ uint32_t Res01 : 3;
+ /* Analog line operating mode */
+ uint32_t OPMODE : 8;
+ /* Time Stamp */
+ uint32_t TIME_STAMP : 16;
+#endif
+} __attribute__ ((packed));
+
+struct __fw_evt_sig
+{
+ struct __fw_evt_header hdr;
+#if __BYTE_ORDER == __BIG_ENDIAN
+ /* Time Stamp */
+ uint32_t TIME_STAMP : 16;
+ /* Reserved */
+ uint32_t Res01 : 4;
+ /* DTMF Key */
+ uint32_t DTMF_KEY : 4;
+ /* Reserved */
+ uint32_t Res02 : 3;
+ /* Event code */
+ uint32_t SIGEVT : 5;
+#else
+ /* Event code */
+ uint32_t SIGEVT : 5;
+ /* Reserved */
+ uint32_t Res02 : 3;
+ /* DTMF Key */
+ uint32_t DTMF_KEY : 4;
+ /* Reserved */
+ uint32_t Res01 : 4;
+ /* Time Stamp */
+ uint32_t TIME_STAMP : 16;
+#endif
+} __attribute__ ((packed));
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+#ifdef EVENT_LOGGER_DEBUG
+static void dxs_el_trace_event_read(DXS_DEVICE_t *pDev,
+ struct __fw_evt_header *pHdr)
+{
+ EL_IoctlAddLog_t stLog;
+ stLog.nLogType = EL_LOG_TYPE_EVT_MBX_RD;
+ stLog.nOrygLogType = EL_MAX_LOG_TYPE;
+ stLog.nDevType = DXS_LIB_DEV_TYPE;
+ stLog.nDevNum = pDev->nDevNum;
+ stLog.nChNum = pHdr->CHAN;
+ stLog.uLogDetails.stEvt_Mbx_Rd.nCmdLength = 4;
+ stLog.uLogDetails.stEvt_Mbx_Rd.nCount = pHdr->LENGTH + 4;
+ stLog.uLogDetails.stEvt_Mbx_Rd.nDataLength = pHdr->LENGTH;
+ stLog.uLogDetails.stEvt_Mbx_Rd.pCmd = (char*)pHdr;
+ if(pHdr->LENGTH == 0)
+ {
+ stLog.uLogDetails.stEvt_Mbx_Rd.pDATA = NULL;
+ }
+ else
+ {
+ stLog.uLogDetails.stEvt_Mbx_Rd.pDATA = (IFX_char_t*)((int16_t*) pHdr + 2);
+ }
+ ioctl(pDev->el_fd, EL_ADD_LOG, (int32_t)&stLog);
+}
+#endif
+
+/**
+ Dispatch raw off-hook event
+
+ \param pCh - pointer to DXS channel structure
+ \return none
+*/
+static void dxs_evt_offhook_raw (DXS_CHANNEL_t *pCh)
+{
+ DXS_Event_t evt = {0};
+
+ evt.dev = pCh->pParent->nDevNum;
+ evt.ch = pCh->nCh;
+ evt.id = DXS_EVENT_FXS_RAW_OFFHOOK;
+ DXS_EventDispatch(pCh->pParent, &evt);
+}
+
+/**
+ Dispatch raw on-hook event
+
+ \param pCh - pointer to DXS channel structure
+ \return none
+*/
+static void dxs_evt_onhook_raw (DXS_CHANNEL_t *pCh)
+{
+ DXS_Event_t evt = {0};
+
+ evt.dev = pCh->pParent->nDevNum;
+ evt.ch = pCh->nCh;
+ evt.id = DXS_EVENT_FXS_RAW_ONHOOK;
+ DXS_EventDispatch(pCh->pParent, &evt);
+}
+
+/**
+ Function dxs_cerr_ack
+
+ \param pDev - pointer to DXS device structure
+
+ \return
+ - DXS_status_t
+*/
+static int32_t dxs_cerr_ack(DXS_DEVICE_t *pDev)
+{
+ uint32_t cerr_ack_cmd = 0x0600e000;
+
+ return DXS_CmdWrite(pDev, &cerr_ack_cmd);
+}
+
+/**
+ Function dxs_event_sdd
+
+ \param pDev - pointer to DXS device structure
+ \param pSddEvt - pointer to SDD event structure
+
+*/
+static void dxs_event_sdd(DXS_DEVICE_t *pDev, struct __fw_evt_sdd *pSddEvt)
+{
+ DXS_Event_t dxs_event = {0};
+ int32_t ret;
+ uint8_t nTmp;
+ DXS_CHANNEL_t *pCh = &pDev->pChannel[pSddEvt->hdr.CHAN];
+
+ dxs_event.dev = pDev->nDevNum;
+ dxs_event.ch = pSddEvt->hdr.CHAN;
+
+ switch (pSddEvt->EVT)
+ {
+ case EVT_SDD_OTEMP:
+ dxs_event.id = DXS_EVENT_OVERTEMP;
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+
+ case EVT_SDD_OTEMP_FIN:
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
+ dxs_event.id = DXS_EVENT_OVERTEMP_END;
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+
+ case EVT_SDD_LT_FIN:
+#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
+ obx_DXS_SDD_OLCalibrationFinished(pCh, 0);
+#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
+ dxs_event.id = DXS_EVENT_NLT_END;
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+
+ case EVT_SDD_LT_ABORT:
+#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
+ obx_DXS_SDD_OLCalibrationFinished(pCh, 1);
+#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
+ dxs_event.id = DXS_EVENT_NLT_ABORT;
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+
+ case EVT_SDD_GF:
+ dxs_event.id = DXS_EVENT_GROUND_FAULT;
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+
+ case EVT_SDD_GF_FIN:
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
+ dxs_event.id = DXS_EVENT_GROUND_FAULT_END;
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+
+ case EVT_SDD_GK:
+ dxs_event.id = DXS_EVENT_GROUND_KEY;
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+
+ case EVT_SDD_GK_FIN:
+ dxs_event.id = DXS_EVENT_GROUND_KEY_END;
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+
+ case EVT_SDD_OPC:
+ case EVT_SDD_OMI:
+ {
+ uint8_t opmode_changed = (pSddEvt->EVT == EVT_SDD_OPC) ? 1 : 0;
+
+ /*DXS_DCDC_HW_Lock(pCh);*/
+ obx_DXS_SDD_OpmodeUpdate(pCh, pSddEvt->OPMODE, opmode_changed);
+ /*DXS_DCDC_HW_UnLock(pCh);*/
+
+ /* For some OPC events more actions are needed */
+ if (opmode_changed)
+ {
+#ifdef DXS_FEAT_HSM
+ /* Set hook-state to ONHOOK if opmode was changed to disabled */
+ if (pSddEvt->OPMODE == DXS_LINE_FEED_DISABLED)
+ {
+#ifdef DXS_FEAT_CID
+ if (DXS_CID_EventOpcDisabled(pCh))
+#endif
+ {
+ DXS_Dial_HookStateSetOnhook(pCh);
+ }
+ }
+#endif
+ /* Calibration ends with an opmode change */
+ if (pSddEvt->OPMODE != DXS_LINE_FEED_CALIBRATE)
+ {
+ ret = DXS_SDD_CalibrationRunningGet(pCh, &nTmp);
+ /* if calibration was running, signal that it has finished */
+ if (ret == DXS_statusOk && nTmp == 1)
+ DXS_SDD_Calibration_Finish(pCh, &dxs_event);
+ }
+ }
+ }
+ break;
+
+ case EVT_SDD_CORCE:
+ break;
+ case EVT_SDD_COEFE:
+ break;
+ case EVT_SDD_ONH:
+ /* Report RAW on-hook */
+ dxs_evt_onhook_raw(pCh);
+#ifdef DXS_FEAT_CID
+ /* Report on-hook */
+ if (DXS_CID_EventOnhook(pCh, pSddEvt->TIME_STAMP))
+#endif
+ {
+#ifdef DXS_FEAT_HSM
+ DXS_Dial_HookEvent(pCh, 0, pSddEvt->TIME_STAMP);
+#else
+ dxs_event.id = DXS_EVENT_FXS_ONHOOK;
+ DXS_EventDispatch(pDev, &dxs_event);
+#endif
+ }
+ break;
+
+ case EVT_SDD_OFFH:
+ /* Report RAW off-hook */
+ dxs_evt_offhook_raw(pCh);
+#ifdef DXS_FEAT_FSK
+ /* Attempt to disable FSK generator */
+ DXS_FSK_Disable(pCh, 0);
+#endif
+#ifdef DXS_FEAT_CID
+ /* Report off-hook */
+ if (DXS_CID_EventOffhook(pCh, pSddEvt->TIME_STAMP))
+#endif
+ {
+#ifdef DXS_FEAT_HSM
+ DXS_Dial_HookEvent(pCh, 1, pSddEvt->TIME_STAMP);
+#else
+ dxs_event.id = DXS_EVENT_FXS_OFFHOOK;
+ DXS_EventDispatch(pDev, &dxs_event);
+#endif
+ }
+ break;
+
+ case EVT_SDD_OPM_DIS:
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Function dxs_event_sig
+
+ \param pDev - pointer to DXS device structure
+ \param pSigEvt - pointer to SIG event structure
+
+*/
+static void dxs_event_sig(DXS_DEVICE_t *pDev, struct __fw_evt_sig *pSigEvt)
+{
+ DXS_Event_t dxs_event = {0};
+#if defined (DXS_FEAT_CID) || defined (DXS_FEAT_UTD) || defined (DXS_FEAT_METERING) || defined (DXS_FEAT_ACMETER)
+ DXS_CHANNEL_t *pCh = &pDev->pChannel[pSigEvt->hdr.CHAN];
+#endif
+ dxs_event.dev = pDev->nDevNum;
+ dxs_event.ch = pSigEvt->hdr.CHAN;
+
+ switch (pSigEvt->SIGEVT)
+ {
+ case EVT_SIG_DTMF_DET:
+ {
+ dxs_event.id = DXS_EVENT_DTMF_DIGIT;
+ switch (pSigEvt->DTMF_KEY)
+ {
+ case 0x0:
+ dxs_event.data.dtmf.digit = 11;
+ dxs_event.data.dtmf.ascii = '0';
+ break;
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ case 0x8:
+ case 0x9:
+ dxs_event.data.dtmf.digit = pSigEvt->DTMF_KEY;
+ dxs_event.data.dtmf.ascii = '0' + pSigEvt->DTMF_KEY;
+ break;
+ case 0xA:
+ dxs_event.data.dtmf.digit = 10;
+ dxs_event.data.dtmf.ascii = '*';
+ break;
+ case 0xB:
+ dxs_event.data.dtmf.digit = 12;
+ dxs_event.data.dtmf.ascii = '#';
+ break;
+ case 0xC:
+ dxs_event.data.dtmf.digit = 28;
+ dxs_event.data.dtmf.ascii = 'A';
+ break;
+ case 0xD:
+ dxs_event.data.dtmf.digit = 29;
+ dxs_event.data.dtmf.ascii = 'B';
+ break;
+ case 0xE:
+ dxs_event.data.dtmf.digit = 30;
+ dxs_event.data.dtmf.ascii = 'C';
+ break;
+ case 0xF:
+ dxs_event.data.dtmf.digit = 31;
+ dxs_event.data.dtmf.ascii = 'D';
+ break;
+ default:
+ break;
+ }
+#ifdef DXS_FEAT_CID
+ /* Report dtmf tone */
+ if (DXS_CID_EventDtmf(pCh, &dxs_event))
+#endif
+ {
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+ }
+ }
+ break;
+
+#if defined(DXS_FEAT_FSK) || defined(DXS_FEAT_CID)
+ case EVT_SIG_CIS_REQ:
+ dxs_event.id = DXS_EVENT_CID_REQ_DATA;
+ DXS_EventDispatch(pDev, &dxs_event);
+#ifdef DXS_FEAT_CID
+ /* inform FSK state machine */
+ DXS_CID_FSK_EventInfo (pCh, DXS_CID_FSK_DATA_REQUEST);
+#endif /* DXS_FEAT_CID */
+ break;
+ case EVT_SIG_CIS_BUF:
+ dxs_event.id = DXS_EVENT_CID_BUF_UNDERFLOW;
+ DXS_EventDispatch(pDev, &dxs_event);
+#ifdef DXS_FEAT_CID
+ /* inform FSK state machine */
+ DXS_CID_FSK_EventInfo (pCh, DXS_CID_FSK_DATA_BUF);
+#endif /* DXS_FEAT_CID */
+ break;
+ case EVT_SIG_CIS_FIN:
+ dxs_event.id = DXS_EVENT_CID_END;
+ DXS_EventDispatch(pDev, &dxs_event);
+#ifdef DXS_FEAT_CID
+ /* inform FSK state machine */
+ DXS_CID_FSK_EventInfo (pCh, DXS_CID_FSK_DATA_FINISH);
+#endif /* DXS_FEAT_CID */
+ break;
+#endif /* DXS_FEAT_FSK || DXS_FEAT_CID */
+
+#ifdef DXS_FEAT_UTD
+ case EVT_SIG_UTD_START:
+ dxs_event.id = DXS_EVENT_TONE_DET_CPT;
+ dxs_event.data.tone_det.index = DXS_UTD_ToneIdxGet(pCh);
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+ case EVT_SIG_UTD_END:
+ dxs_event.id = DXS_EVENT_TONE_DET_CPT_END;
+ dxs_event.data.tone_det.index = DXS_UTD_ToneIdxGet(pCh);
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+#endif /* DXS_FEAT_UTD */
+
+#ifdef DXS_FEAT_METERING
+ case EVT_SIG_TTX_FIN:
+ obx_DXS_SIG_MeterPulseStatusClear(pCh);
+ dxs_event.id = DXS_EVENT_METERING_END;
+ DXS_EventDispatch(pDev, &dxs_event);
+ break;
+#endif /* DXS_FEAT_METERING */
+
+#ifdef DXS_FEAT_ACMETER
+ case EVT_SIG_AC_LM_FIN:
+ obx_DXS_SDD_ACLM_Finish(pCh);
+ break;
+#endif /* DXS_FEAT_ACMETER */
+
+ default:
+ break;
+ }
+}
+
+/**
+ Function dxs_handle_event
+
+ \param pDev Pointer to DXS device structure.
+ \param pHdr Pointer to __fw_evt_header structure.
+*/
+static void dxs_handle_event(DXS_DEVICE_t *pDev, struct __fw_evt_header *pHdr)
+{
+ /* Discard all events here while event handling is globally disabled. */
+ if (pDev->obxDiscardEvents != 0)
+ {
+#ifdef DXS_CMD_PRINT
+ /* The boot finished event has only one word all other two words. */
+ if (pHdr->MOD == 7 && pHdr->ECMD == 0)
+ fprintf (stderr, "[evt] dev:%d %08X DISCARDED\n",
+ pDev->nDevNum, *((uint32_t *)pHdr));
+ else
+ fprintf (stderr, "[evt] dev:%d %08X %08X DISCARDED\n", pDev->nDevNum,
+ *((uint32_t *)pHdr), *((uint32_t *)pHdr + 1));
+#endif /* DXS_CMD_PRINT */
+ return;
+ }
+
+ if (pHdr->MOD == 7 && pHdr->ECMD == 0)
+ {
+ /* Boot Finished Event */
+
+ uint8_t i;
+
+#ifdef DXS_CMD_PRINT
+ fprintf (stderr, "[evt] dev:%d %08X\n", pDev->nDevNum,
+ *((uint32_t *)pHdr));
+#endif /* DXS_CMD_PRINT */
+
+ /* clear flags and capabilities */
+ dxs_caps_vers_forget(pDev);
+ pDev->flags &= ~DXS_DEV_PRAM_PATCH_DOWNLOADED;
+ for (i=0; i<CH_PER_DEVICE; i++)
+ {
+ DXS_CHANNEL_t *pCh = &pDev->pChannel[i];
+
+ pCh->flags &= ~DXS_CH_BBD_DOWNLOADED;
+ }
+
+ if (pDev->bWaitingInPatchDwld)
+ {
+ sem_post(&pDev->mtxPatchDwld);
+ pDev->bWaitingInPatchDwld = 0;
+ }
+ else
+ {
+ /* FW crash */
+
+ DXS_Event_t dxs_event = {0};
+
+ dxs_event.dev = pDev->nDevNum;
+ dxs_event.ch = 0;
+ dxs_event.id = DXS_EVENT_FAULT_FW_WATCHDOG;
+ DXS_EventDispatch(pDev, &dxs_event);
+ }
+ }
+
+ if (pHdr->MOD == 7 && pHdr->ECMD == 11)
+ {
+ /* Internal Error Event */
+
+#ifdef DXS_CMD_PRINT
+ fprintf (stderr, "[evt] dev:%d %08X %08X\n", pDev->nDevNum,
+ *((uint32_t *)pHdr), *((uint32_t *)pHdr + 1));
+#endif /* DXS_CMD_PRINT */
+ }
+ else if (pHdr->MOD == 7 && pHdr->ECMD == 2)
+ {
+ /* Command Error Event */
+
+ struct __fw_evt_cmd_err *pCerr = (struct __fw_evt_cmd_err *)pHdr;
+ DXS_Event_t dxs_event = {0};
+
+#ifdef DXS_CMD_PRINT
+ fprintf (stderr, "[evt] dev:%d %08X %08X %08X\n", pDev->nDevNum,
+ *((uint32_t *)pHdr), *((uint32_t *)pHdr + 1),
+ *((uint32_t *)pHdr + 2));
+#endif /* DXS_CMD_PRINT */
+
+ /* acknowledge command error */
+ dxs_cerr_ack(pDev);
+
+ dxs_event.dev = pDev->nDevNum;
+ dxs_event.id = DXS_EVENT_DEBUG_CERR;
+ dxs_event.data.cerr.reason = pCerr->CMDERR;
+ dxs_event.data.cerr.command = pCerr->CMDHDR;
+ DXS_EventDispatch(pDev, &dxs_event);
+ }
+ else if (pHdr->MOD == 1 && pHdr->ECMD == 4)
+ {
+ /* SDD Event */
+
+#ifdef DXS_CMD_PRINT
+ fprintf (stderr, "[evt] dev:%d %08X %08X\n", pDev->nDevNum,
+ *((uint32_t *)pHdr), *((uint32_t *)pHdr + 1));
+#endif /* DXS_CMD_PRINT */
+
+ dxs_event_sdd(pDev, (struct __fw_evt_sdd *)pHdr);
+ }
+ else if (pHdr->MOD == 1 && pHdr->ECMD == 5)
+ {
+ /* Signaling Event */
+
+#ifdef DXS_CMD_PRINT
+ fprintf (stderr, "[evt] dev:%d %08X %08X\n", pDev->nDevNum,
+ *((uint32_t *)pHdr), *((uint32_t *)pHdr + 1));
+#endif /* DXS_CMD_PRINT */
+
+ dxs_event_sig(pDev, (struct __fw_evt_sig *)pHdr);
+ }
+}
+
+/**
+ Function dxs_outbox_handler
+
+ \param arg - pointer to device
+
+*/
+static void *dxs_outbox_handler (void *arg)
+{
+ DXS_DEVICE_t *pDev = (DXS_DEVICE_t *)arg;
+
+ while (pDev->obxThreadStop == 0)
+ {
+ uint8_t words16, words32, msg_len/*in 32-bit words*/, tmp,
+ words32_remaining;
+ /* 16 bit index points to the header of message that has been read out */
+ uint8_t pos1;
+ int32_t ret;
+
+ ret = sem_wait (&pDev->obxSemaphore);
+ if (ret == EINTR)
+ pthread_exit((void *)DXS_statusOk);
+
+ /* TODO:- take additional mutex (trylock ???) - concurrency with CmdRead() */
+ /* TODO: check if SPI works */
+
+ /* read the outbox */
+ DXS_ObxRead(pDev, pDev->dmbx, &words16);
+
+ if (words16 == 0)
+ {
+ continue;
+ }
+ if (words16 & 1)
+ {
+ /* TODO: is this an error ? */
+ fprintf (stderr, "OutMbx: Odd word count: %d\n", words16);
+ continue;
+ }
+
+ words32_remaining = words32 = words16 >> 1;
+ pos1 = 0;
+
+ while ((pos1/2) < words32)
+ {
+ struct __fw_evt_header *pHdr = (struct __fw_evt_header *)(pDev->dmbx+pos1);
+ uint8_t attempts = 0, out_of_sync = 0;
+
+ /* get the length of the message in 32-bit words */
+ msg_len = (pHdr->LENGTH + sizeof(struct __fw_evt_header)) >> 2;
+
+ while (msg_len > words32_remaining)
+ {
+ /* read 2nd segment */
+
+ /* read the outbox again */
+ DXS_ObxRead(pDev, pDev->dmbx + words16, &tmp);
+
+ /* here we don't expect that nothing is read */
+
+ words16 += tmp;
+ words32 = words16 >> 1;
+ words32_remaining += (tmp >> 1);
+
+ if (++attempts == 3)
+ {
+ out_of_sync = 1;
+ break;
+ }
+ }
+
+ if (out_of_sync)
+ {
+ int32_t i;
+ fprintf (stderr, "Mailbox out of sync.\n");
+ /* print the read buffer */
+ fprintf (stderr, "READ BUFFER:\n");
+ for (i=0; i<(sizeof(pDev->dmbx)>>1); i+=2)
+ fprintf (stderr, "%02d: %04X %04X\n", i, pDev->dmbx[i], pDev->dmbx[i+1]);
+ fprintf (stderr, "pos=%02d\n", pos1);
+ break;
+ }
+
+ /* decode message, buffer it, advance to the next */
+ if (pHdr->Res00 == 0 &&
+ pHdr->CMD == 9 &&
+ (pHdr->MOD == 1 || pHdr->MOD == 7) &&
+ (pHdr->LENGTH == 0 || pHdr->LENGTH == 4 || pHdr->LENGTH == 8))
+ {
+#ifdef EVENT_LOGGER_DEBUG
+ dxs_el_trace_event_read(pDev, pHdr);
+#endif
+
+ /* this is an event header */
+ dxs_handle_event(pDev, pHdr);
+ }
+ else
+ {
+ /* this is a command header */
+ int i;
+ uint32_t *pw32;
+
+ for (i=0, pw32 = (uint32_t *)pHdr; i<msg_len; i++, pw32++)
+ {
+ fifo_put(pDev->cmd_obx_queue, NULL, *pw32);
+ }
+ sem_post(&pDev->obxCmdDataSem);
+ }
+
+ pos1 += (msg_len * 2);
+ words32_remaining -= msg_len;
+
+ /* This implementation works in IRQ edge mode. */
+#if 0
+ /* If the IRQ is edge triggered we have to make sure that the
+ mailbox is empty when we exit the loop. There won't be another IRQ
+ generated if there is still data left in outbox. */
+ if (pos1 >= words16)
+ {
+ DXS_ObxRead(pDev, pDev->dmbx, &words16);
+ if (words16 == 0)
+ break;
+ if (words16 & 1)
+ {
+ /* TODO: is this an error ? */
+ fprintf (stderr, "OutMbx: Odd word count: %d\n", words16);
+ break;
+ }
+ words32 = words16 >> 1;
+ pos1 = 0;
+ }
+#endif
+ }
+ }
+ pthread_exit((void *)DXS_statusOk);
+}
+
+/**
+ Function dxs_outbox_handler_init
+
+ \param pDev - pointer to DXS device structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_outbox_handler_init(DXS_DEVICE_t *pDev)
+{
+ int32_t ret;
+
+ sem_init(&pDev->obxSemaphore, 0, 0);
+ sem_init(&pDev->obxCmdDataSem, 0, 0);
+
+ pDev->obxThreadStop = 0;
+ pDev->obxDiscardEvents = 1;
+
+ ret = pthread_create(&pDev->obxThread, NULL, dxs_outbox_handler, (void *)pDev);
+ if (ret)
+ {
+ /* error code */
+ DXS_RETURN(DXS_statusThreadCreatError);
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Function dxs_outbox_handler_exit
+
+ \param pDev - pointer to DXS device structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_outbox_handler_exit(DXS_DEVICE_t *pDev)
+{
+ int32_t ret;
+ void *status;
+
+ /* condition to stop */
+ pDev->obxThreadStop = 1;
+
+ /* let the thread run */
+ sem_post (&pDev->obxSemaphore);
+
+ /* wait for the thread to exit */
+ ret = pthread_join(pDev->obxThread, &status);
+ if (ret || status != DXS_statusOk)
+ {
+ /* error code */
+ DXS_RETURN(DXS_statusThreadStopError);
+ }
+
+ sem_destroy(&pDev->obxSemaphore);
+ sem_destroy(&pDev->obxCmdDataSem);
+
+ return ret;
+}
+
+/**
+ Function dxs_outbox_handler_enable
+
+ This enables the event handling. After init the outbox is processed but
+ events are discarded until this function is called.
+
+ \param pDev - pointer to DXS device structure
+*/
+void dxs_outbox_handler_enable(DXS_DEVICE_t *pDev)
+{
+ /* From now on process all events. */
+ pDev->obxDiscardEvents = 0;
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_outbox.h b/marvell/services/dxslic/api_lib/src/dxs_outbox.h
new file mode 100644
index 0000000..a8f2022
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_outbox.h
@@ -0,0 +1,37 @@
+#ifndef __DXS_OUTBOX_H__
+#define __DXS_OUTBOX_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_outbox.h
+ Miscellaneous functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern int32_t dxs_outbox_handler_exit(DXS_DEVICE_t *pDev);
+extern void dxs_outbox_handler_enable(DXS_DEVICE_t *pDev);
+extern int32_t dxs_outbox_handler_init(DXS_DEVICE_t *pDev);
+#endif /* __DXS_OUTBOX_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_pcm.c b/marvell/services/dxslic/api_lib/src/dxs_pcm.c
new file mode 100644
index 0000000..703d5af
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_pcm.c
@@ -0,0 +1,516 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_pcm.c
+ Implementation of PCM functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_config.h"
+#include "dxs_lib.h"
+#include "dxs_fw_cmd.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_FW_PCM_IF_BIT_OFF_MAX 7
+#define DXS_FW_PCM_CH_CODEC_LINEAR 0
+#define DXS_FW_PCM_CH_CODEC_G711A 2
+#define DXS_FW_PCM_CH_CODEC_G711U 3
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+/** Data structure for PCM interface configuration firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Enable */
+ uint32_t EN : 1;
+ /** Data Streaming Enable */
+ uint32_t DS : 1;
+ /** Reserved */
+ uint32_t Res02 : 3;
+ /** Transmit Bit Offset */
+ uint32_t XOFF : 3;
+ /** Double Bit Clock */
+ uint32_t DBL : 1;
+ /** Transmit Slope */
+ uint32_t XS : 1;
+ /** Receive Slope */
+ uint32_t RS : 1;
+ /** Bit 0 Drive Length */
+ uint32_t DRV0 : 1;
+ /** Shift Control */
+ uint32_t SH : 1;
+ /** Receive Bit Offset */
+ uint32_t ROFF : 3;
+ /** Reserved */
+ uint32_t Res03 : 16;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res03 : 16;
+ /** Receive Bit Offset */
+ uint32_t ROFF : 3;
+ /** Shift Control */
+ uint32_t SH : 1;
+ /** Bit 0 Drive Length */
+ uint32_t DRV0 : 1;
+ /** Receive Slope */
+ uint32_t RS : 1;
+ /** Transmit Slope */
+ uint32_t XS : 1;
+ /** Double Bit Clock */
+ uint32_t DBL : 1;
+ /** Transmit Bit Offset */
+ uint32_t XOFF : 3;
+ /** Reserved */
+ uint32_t Res02 : 3;
+ /** Data Streaming Enable */
+ uint32_t DS : 1;
+ /** Enable */
+ uint32_t EN : 1;
+#endif
+} __attribute__ ((packed)) DXS_FW_PCM_IF_t;
+#define DXS_FW_PCM_IF_ECMD 0
+#define DXS_FW_PCM_IF_LENGTH 4
+
+/** Data structure for PCM channel activation firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Enable */
+ uint32_t EN : 1;
+ /** Coder */
+ uint32_t COD : 3;
+ /** Wideband 16 kHz */
+ uint32_t WIDE : 1;
+ /** Wide Band PCM Time Slot Configuration Bit */
+ uint32_t WBTSC : 1;
+ /** Reserved */
+ uint32_t Res02 : 11;
+ /** Transmit Highway Time Slot */
+ uint32_t XTS : 7;
+ /** Reserved */
+ uint32_t Res03 : 1;
+ /** Receive Highway Time Slot */
+ uint32_t RTS : 7;
+#else
+ CMD_HEAD_LE;
+ /** Receive Highway Time Slot */
+ uint32_t RTS : 7;
+ /** Reserved */
+ uint32_t Res03 : 1;
+ /** Transmit Highway Time Slot */
+ uint32_t XTS : 7;
+ /** Reserved */
+ uint32_t Res02 : 11;
+ /** Wide Band PCM Time Slot Configuration Bit */
+ uint32_t WBTSC : 1;
+ /** Wideband 16 kHz */
+ uint32_t WIDE : 1;
+ /** Coder */
+ uint32_t COD : 3;
+ /** Enable */
+ uint32_t EN : 1;
+#endif
+} __attribute__ ((packed)) DXS_FW_PCM_CH_t;
+#define DXS_FW_PCM_CH_ECMD 1
+#define DXS_FW_PCM_CH_LENGTH 4
+
+/** Data structure for PCM channel mute firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Reserved */
+ uint32_t Res02 : 31;
+ /** Mute of RX Direction */
+ uint32_t RX_MUTE : 1;
+#else
+ CMD_HEAD_LE;
+ /** Mute of RX Direction */
+ uint32_t RX_MUTE : 1;
+ /** Reserved */
+ uint32_t Res02 : 31;
+#endif
+} __attribute__ ((packed)) DXS_FW_PCM_CH_MUTE_t;
+#define DXS_FW_PCM_CH_MUTE_ECMD 4
+#define DXS_FW_PCM_CH_MUTE_LENGTH 4
+
+/** Data structure for PCM device resource */
+typedef struct
+{
+ /** status flag */
+ uint32_t flag;
+#define PCM_DEV_INITIALIZED 1
+ /** PCM Interface Control firmware message */
+ DXS_FW_PCM_IF_t pcm_if;
+} DXS_PCM_Dev_Resource_t;
+
+/** Data structure for PCM channel resource */
+typedef struct
+{
+ /** status flag */
+ uint32_t flag;
+#define PCM_CH_INITIALIZED 1
+ /** PCM Channel Control firmware message */
+ DXS_FW_PCM_CH_t pcm_ch;
+ /** PCM Channel Mute firmware message */
+ DXS_FW_PCM_CH_MUTE_t pcm_ch_mute;
+} DXS_PCM_Ch_Resource_t;
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+static DXS_PCM_Dev_Resource_t pcm_devs[DXS_MAX_DEVICES] = {0};
+static DXS_PCM_Ch_Resource_t pcm_chan[DXS_MAX_DEVICES * CH_PER_DEVICE] = {0};
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+/**
+ Function dxs_pcm_dev_init
+
+ \param devnum - device number
+
+*/
+void *dxs_pcm_dev_init(uint8_t devnum)
+{
+ DXS_PCM_Dev_Resource_t *p;
+
+ if (devnum >= DXS_MAX_DEVICES)
+ return (void *)NULL;
+
+ p = &pcm_devs[devnum];
+
+ p->flag = 0;
+
+ p->pcm_if.CMD = CMD_EOP;
+ p->pcm_if.MOD = MOD_SDD_PCM;
+ p->pcm_if.ECMD = DXS_FW_PCM_IF_ECMD;
+ p->pcm_if.LENGTH = DXS_FW_PCM_IF_LENGTH;
+ /* DS bit should always be set to one (= double buffer) */
+ p->pcm_if.DS = 1;
+
+ p->flag |= PCM_DEV_INITIALIZED;
+
+ return (void *)p;
+}
+
+/**
+ Function dxs_pcm_ch_init
+
+ \param dev - device number
+ \param ch - channel number
+
+*/
+void *dxs_pcm_ch_init(uint8_t dev, uint8_t ch)
+{
+ DXS_PCM_Ch_Resource_t *p;
+
+ if (dev >= DXS_MAX_DEVICES || ch >= CH_PER_DEVICE)
+ return (void *)NULL;
+
+ p = &pcm_chan[dev * CH_PER_DEVICE + ch];
+
+ p->flag = 0;
+
+ p->pcm_ch.CMD = CMD_EOP;
+ p->pcm_ch.MOD = MOD_SDD_PCM;
+ p->pcm_ch.ECMD = DXS_FW_PCM_CH_ECMD;
+ p->pcm_ch.LENGTH = DXS_FW_PCM_CH_LENGTH;
+ p->pcm_ch.CHAN = ch;
+
+ p->pcm_ch_mute.CMD = CMD_EOP;
+ p->pcm_ch_mute.MOD = MOD_SDD_PCM;
+ p->pcm_ch_mute.ECMD = DXS_FW_PCM_CH_MUTE_ECMD;
+ p->pcm_ch_mute.LENGTH = DXS_FW_PCM_CH_MUTE_LENGTH;
+ p->pcm_ch_mute.CHAN = ch;
+
+ p->flag |= PCM_CH_INITIALIZED;
+
+ return (void *)p;
+}
+
+/**
+ Function dxs_pcm_if_config
+
+ \param pDev - pointer to DXS device structure
+ \param xoff - transmit bit offset
+ \param dbl - double bit clock
+ \param xs - transmit slope
+ \param rs - receive slope
+ \param drv0 - bit 0 drive length
+ \param sh - shift control
+ \param roff - receive bit offset
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_pcm_if_config(DXS_DEVICE_t *pDev, uint8_t xoff, uint8_t dbl,
+ uint8_t xs, uint8_t rs, uint8_t drv0, uint8_t sh,
+ uint8_t roff)
+{
+ DXS_PCM_Dev_Resource_t *p;
+ int32_t err;
+
+ if (pDev == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_PCM_Dev_Resource_t *)pDev->pcm;
+
+ if (!(p->flag & PCM_DEV_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* parameter sanity check */
+ if (xoff > DXS_FW_PCM_IF_BIT_OFF_MAX || roff > DXS_FW_PCM_IF_BIT_OFF_MAX ||
+ dbl > 1 || xs > 1 || rs > 1 || drv0 > 1 || sh > 1)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ if (p->pcm_if.EN == 1)
+ {
+ uint8_t ch;
+
+ /* check if there are active channels */
+ for (ch = 0; ch < pDev->nChannels; ch++)
+ {
+ DXS_PCM_Ch_Resource_t *pPcmChRes =
+ (DXS_PCM_Ch_Resource_t *)pDev->pChannel[ch].pcm;
+
+ if ((pPcmChRes->flag & PCM_CH_INITIALIZED) && pPcmChRes->pcm_ch.EN == 1)
+ {
+ /* error code - there are active PCM timeslots on this highway */
+ DXS_RETURN(DXS_statusPcmChNotDisabled);
+ }
+ }
+
+ p->pcm_if.EN = 0;
+ err = CmdWrite(pDev, (uint32_t *)&p->pcm_if);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusPcmIfActError);
+ }
+ }
+
+ p->pcm_if.XOFF = xoff;
+ p->pcm_if.DBL = dbl;
+ p->pcm_if.XS = xs;
+ p->pcm_if.RS = rs;
+ p->pcm_if.DRV0 = drv0;
+ p->pcm_if.SH = sh;
+ p->pcm_if.ROFF = roff;
+ p->pcm_if.EN = 1;
+
+ err = CmdWrite(pDev, (uint32_t *)&p->pcm_if);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusPcmIfActError);
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Function dxs_pcm_ch_act
+
+ \param pCh - pointer to DXS channel structure
+ \param line - line number
+ \param wb - wideband
+ \param wbtsc - wideband PCM time slot configuration
+ \param codec - codec
+ \param xts - transmit highway time slot
+ \param rts - receive highway time slot
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_pcm_ch_act(DXS_CHANNEL_t *pCh, uint8_t wb, uint8_t wbtsc,
+ uint8_t codec, uint8_t xts, uint8_t rts)
+{
+ DXS_PCM_Ch_Resource_t *p;
+ DXS_PCM_Dev_Resource_t *pPcmDevRes;
+ int32_t err;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_PCM_Ch_Resource_t *)pCh->pcm;
+
+ if (!(p->flag & PCM_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ pPcmDevRes = (DXS_PCM_Dev_Resource_t *)pCh->pParent->pcm;
+ if (pPcmDevRes->pcm_if.EN != 1)
+ {
+ /* error code - PCM interface is not enabled */
+ DXS_RETURN(DXS_statusPcmIfNotEnabled);
+ }
+
+ /* parameter sanity check */
+ if (wb > 1 || wbtsc > 1 ||
+ (codec != DXS_FW_PCM_CH_CODEC_LINEAR &&
+ codec != DXS_FW_PCM_CH_CODEC_G711A &&
+ codec != DXS_FW_PCM_CH_CODEC_G711U))
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ if (p->pcm_ch.EN == 1)
+ {
+ if (p->pcm_ch.COD != codec || p->pcm_ch.WIDE != wb ||
+ p->pcm_ch.WBTSC != wbtsc || p->pcm_ch.XTS != xts || p->pcm_ch.RTS != rts)
+ {
+ p->pcm_ch.EN = 0;
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->pcm_ch);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusPcmChActError);
+ }
+ }
+ else
+ {
+ /* parameters aren't changed */
+ return DXS_statusOk;
+ }
+ }
+
+ p->pcm_ch.COD = codec;
+ p->pcm_ch.WIDE = wb;
+ p->pcm_ch.WBTSC = wbtsc;
+ p->pcm_ch.XTS = xts;
+ p->pcm_ch.RTS = rts;
+ /* always set EN bit */
+ p->pcm_ch.EN = 1;
+
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->pcm_ch);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusPcmChActError);
+ }
+
+ /* unmute Rx direction implicitly */
+ if (p->pcm_ch_mute.RX_MUTE)
+ {
+ p->pcm_ch_mute.RX_MUTE = 0;
+
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->pcm_ch_mute);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusPcmChActError);
+ }
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Function dxs_pcm_ch_deact
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_pcm_ch_deact(DXS_CHANNEL_t *pCh)
+{
+ DXS_PCM_Ch_Resource_t *p;
+ int32_t err;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_PCM_Ch_Resource_t *)pCh->pcm;
+
+ if (!(p->flag & PCM_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (p->pcm_ch.EN == 0)
+ {
+ /* already deactivated */
+ return DXS_statusOk;
+ }
+
+ p->pcm_ch.EN = 0;
+
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->pcm_ch);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusPcmChActError);
+ }
+
+ return DXS_statusOk;
+}
+
+/**
+ Function dxs_pcm_ch_mute
+
+ \param pCh - pointer to DXS channel structure
+ \param action - action mute/unmute
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_pcm_ch_mute(DXS_CHANNEL_t *pCh, uint8_t action)
+{
+ DXS_PCM_Ch_Resource_t *p;
+ int32_t err;
+
+ if (pCh == NULL || action > 1)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_PCM_Ch_Resource_t *)pCh->pcm;
+
+ if (!(p->flag & PCM_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (p->pcm_ch_mute.RX_MUTE == action)
+ {
+ /* parameters aren't changed */
+ return DXS_statusOk;
+ }
+
+ p->pcm_ch_mute.RX_MUTE = action;
+
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->pcm_ch_mute);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusPcmChMuteError);
+ }
+
+ return DXS_statusOk;
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_pcm.h b/marvell/services/dxslic/api_lib/src/dxs_pcm.h
new file mode 100644
index 0000000..b3a0353
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_pcm.h
@@ -0,0 +1,45 @@
+#ifndef __DXS_PCM_H__
+#define __DXS_PCM_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_pcm.h
+ PCM functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_lib.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern void *dxs_pcm_dev_init(uint8_t devnum);
+extern void *dxs_pcm_ch_init(uint8_t dev, uint8_t ch);
+extern int32_t dxs_pcm_if_config(DXS_DEVICE_t *pDev, uint8_t xoff, uint8_t dbl,
+ uint8_t xs, uint8_t rs, uint8_t drv0,
+ uint8_t sh, uint8_t roff);
+extern int32_t dxs_pcm_ch_act(DXS_CHANNEL_t *pCh, uint8_t wb, uint8_t wbtsc,
+ uint8_t codec, uint8_t xts, uint8_t rts);
+extern int32_t dxs_pcm_ch_deact(DXS_CHANNEL_t *pCh);
+extern int32_t dxs_pcm_ch_mute(DXS_CHANNEL_t *pCh, uint8_t action);
+
+#endif /* __DXS_PCM_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_pollint.c b/marvell/services/dxslic/api_lib/src/dxs_pollint.c
new file mode 100644
index 0000000..9697868
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_pollint.c
@@ -0,0 +1,272 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_pollint.c
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdint.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "dxs_init.h"
+#include "dxs_config.h"
+#include "dxs_error.h"
+#include "dxs_pollint.h"
+#include "irq_handler/dxs_irq.h"
+#include "dxs_access.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_SHARED_INTERRUPT
+/*#undef DXS_SHARED_INTERRUPT*/
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+static timer_t gPollTimerId;
+static uint8_t timer_use = 0;
+static pthread_t gInterruptThread;
+static volatile int gInterruptThreadStop = 0;
+static int gInterruptFD = -1;
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/**
+ Function dxs_poll_devices
+*/
+static void dxs_poll_devices()
+{
+ uint8_t dev;
+ DXS_DEVICE_t *pDev;
+
+ for (dev=0; dev<DXS_MAX_DEVICES; dev++)
+ {
+ pDev = dxs_get_dev (dev);
+ DXS_StatusGet(pDev);
+ }
+}
+
+/**
+ Function dxs_polling_timer_start
+*/
+void dxs_polling_timer_start()
+{
+ if (!timer_use)
+ {
+ struct itimerspec value;
+
+ (void) signal(SIGALRM, dxs_poll_devices);
+
+ value.it_value.tv_sec = 0;
+ value.it_value.tv_nsec = DXS_POLLING_INTERVAL_MS * 1000000;
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_nsec = DXS_POLLING_INTERVAL_MS * 1000000;
+ timer_create (CLOCK_REALTIME, NULL, &gPollTimerId);
+ timer_settime (gPollTimerId, 0, &value, NULL);
+ }
+
+ timer_use++;
+}
+
+/**
+ Function dxs_polling_timer_stop
+*/
+void dxs_polling_timer_stop()
+{
+ timer_use--;
+
+ if (!timer_use)
+ {
+ struct itimerspec value;
+
+ value.it_value.tv_sec = 0;
+ value.it_value.tv_nsec = 0;
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_nsec = 0;
+ timer_settime (gPollTimerId, 0, &value, NULL);
+ timer_delete (gPollTimerId);
+ }
+}
+
+/* definition of dxs_int_client() */
+/* - open /dev/dxs
+ * - prepare select
+ * - while (1) {
+ * - sleep on select()
+ * - when woken up, call dxs_poll_devices()
+ * - }
+ */
+
+
+/**
+ Function dxs_interrupt_handler
+
+ \param arg - unused
+
+*/
+static void *dxs_interrupt_handler (void *arg)
+{
+ fd_set readfds;
+ int ret, dev;
+
+ FD_ZERO(&readfds);
+ while (gInterruptThreadStop == 0)
+ {
+ FD_SET(gInterruptFD, &readfds);
+ ret = select (gInterruptFD + 1, &readfds, NULL, NULL, NULL);
+ if (ret > 0)
+ {
+#if defined(DXS_SHARED_INTERRUPT)
+ ret = ioctl(gInterruptFD, DXS_INT_DEV_GET, &dev);
+ if (ret == 0)
+ {
+ dxs_poll_devices();
+
+ /* Outbox handling is finished. Release IRQ line. */
+ ioctl(gInterruptFD, DXS_INT_DEV_REL, &dev);
+ }
+#else
+ do
+ {
+ ret = ioctl(gInterruptFD, DXS_INT_DEV_GET, &dev);
+ if (ret == 0)
+ {
+ DXS_DEVICE_t *pDev = dxs_get_dev(dev);
+ if (pDev && (pDev->flags & DXS_DEV_OBX_HND_INITIALIZED))
+ {
+ DXS_StatusGet(pDev);
+
+ /* Outbox handling is finished. Release IRQ line. */
+ ioctl(gInterruptFD, DXS_INT_DEV_REL, &dev);
+ }
+ }
+ } while (ret == 0 && dev != -1);
+#endif /* DXS_SHARED_INTERRUPT */
+ }
+ }
+ return NULL;
+}
+
+/**
+ Initialize interrupt handling code. Start interrupt handling thread,
+ configure interrupt number.
+
+ \param pDev pointer to the device interface
+ \return
+ Error code.
+*/
+int32_t dxs_interrupt_init (DXS_DEVICE_t *pDev)
+{
+ int32_t ret;
+ DXS_INT_CONF_t int_conf;
+ pthread_attr_t irq_thread_attr;
+
+ if (pDev->irqNumber == -1)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ if (gInterruptFD == -1)
+ {
+ gInterruptFD = open("/dev/" DXS_IRQ_NAME, O_RDWR);
+ if (gInterruptFD == -1)
+ {
+ DXS_RETURN(DXS_statusFdOpenError);
+ }
+
+ /* Set highest priority for IRQ thread handling */
+ pthread_attr_init(&irq_thread_attr);
+ pthread_attr_setschedpolicy(&irq_thread_attr, SCHED_RR);
+
+ ret = pthread_create(&gInterruptThread, &irq_thread_attr,
+ dxs_interrupt_handler, NULL);
+ if (ret != 0)
+ {
+ close(gInterruptFD);
+ pthread_attr_destroy(&irq_thread_attr);
+ gInterruptFD = -1;
+ /* error code */
+ DXS_RETURN(DXS_statusThreadCreatError);
+ }
+ pthread_attr_destroy(&irq_thread_attr);
+#if defined(DXS_SHARED_INTERRUPT)
+ int_conf.dev = pDev->nDevNum;
+ int_conf.irq = pDev->irqNumber;
+ ret = ioctl(gInterruptFD, DXS_INT_CONF, &int_conf);
+ if (ret < 0)
+ {
+ DXS_RETURN(DXS_statusIntConfError);
+ }
+#endif
+ }
+#if !defined(DXS_SHARED_INTERRUPT)
+ int_conf.dev = pDev->nDevNum;
+ int_conf.irq = pDev->irqNumber;
+ ret = ioctl(gInterruptFD, DXS_INT_CONF, &int_conf);
+ if (ret < 0)
+ {
+ DXS_RETURN(DXS_statusIntConfError);
+ }
+#endif
+ return DXS_statusOk;
+}
+
+/**
+ Release interrupt handling code. Stop interrupt handling thread,
+ close interrupt handler driver file descriptor.
+
+ \param none
+ \return
+ Error code.
+*/
+int32_t dxs_interrupt_exit (void)
+{
+ int32_t ret = DXS_statusOk;
+ void *status;
+
+ if (gInterruptFD != -1)
+ {
+ gInterruptThreadStop = 1;
+ /* wait for the thread to exit */
+ ret = pthread_join(gInterruptThread, &status);
+ if (ret || status != DXS_statusOk)
+ {
+ /* error code */
+ DXS_RETURN(DXS_statusThreadStopError);
+ }
+ close(gInterruptFD);
+ gInterruptFD = -1;
+ }
+ return ret;
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_pollint.h b/marvell/services/dxslic/api_lib/src/dxs_pollint.h
new file mode 100644
index 0000000..c5885fa
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_pollint.h
@@ -0,0 +1,38 @@
+#ifndef __DXS_POLLINT_H__
+#define __DXS_POLLINT_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_pollint.h
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+extern int32_t dxs_interrupt_init (DXS_DEVICE_t *pDev);
+extern int32_t dxs_interrupt_exit (void);
+extern void dxs_polling_timer_stop(void);
+extern void dxs_polling_timer_start(void);
+#endif /* __DXS_POLLINT_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_ring.c b/marvell/services/dxslic/api_lib/src/dxs_ring.c
new file mode 100644
index 0000000..8ad1c68
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_ring.c
@@ -0,0 +1,754 @@
+/*******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, 2017, 2018 Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+*******************************************************************************/
+
+/**
+ \file dxs_ring.c
+ Function implementation for cadenced ringing.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <time.h>
+#include <errno.h>
+#include "dxs_config.h"
+#include "dxs_lib.h"
+#include "dxs_sdd.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_misc.h"
+#include "dxs_ring.h"
+#include "dxs_dcdc_hw.h"
+#include "dxs_cid.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* total channel count */
+#define DXS_RING_CHANNELS (DXS_MAX_DEVICES * CH_PER_DEVICE)
+#define RING_TIMER_INTERVAL_MS 50
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+typedef struct
+{
+#define RING_TIMER_STOPPED 0
+#define RING_TIMER_RUNNING 1
+ int32_t state;
+ sem_t sem;
+ pthread_t thr;
+ int32_t ret_val;
+ int32_t current_bit;
+ int32_t reset_bits;
+} dxs_ring_timer_t;
+
+typedef struct
+{
+#define RING_CADENCE_NOT_INIT 0
+#define RING_CADENCE_INIT 1
+#define RING_CADENCE_CID_ACT 2
+ int32_t flag;
+ DXS_CHANNEL_t *pCh;
+#define RING_POLARITY_NORMAL 0
+#define RING_POLARITY_REVERSE 1
+ int32_t polarity;
+#define RING_CAD_STATE_IDLE 0
+#define RING_CAD_STATE_RINGING 1
+#define RING_CAD_STATE_CID_DURING_RINGING 2
+#define RING_CAD_STATE_CID_PRIOR_TO_RINGING 3
+ volatile int32_t ring_cadence_state;
+#define RINGER_STATE_PAUSE 0
+#define RINGER_STATE_RINGING 1
+ int32_t ringer_state;
+ DXS_RingCadence_t cadence;
+ /* used only for
+ prior to ringing CID standards */
+ int32_t wait_counter;
+ int32_t current_bit;
+} dxs_ring_res_t;
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+static dxs_ring_timer_t reft = {0};
+static dxs_ring_res_t ring_cadence[DXS_RING_CHANNELS] = {0};
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/**
+ Return the bit position of the ringing pulse number in a cadence
+
+ \param pRes - pointer to ringing cadence resource
+ \param ring - ringing pulse number starting from 0
+
+ \return
+ - bit position of the ringing pulse
+*/
+static int32_t dxs_ring_next_pos_get (dxs_ring_res_t *pRes, int32_t ring)
+{
+ int32_t bit=0, i=0, rpulse=0, ring_phase=0;
+
+ /* TODO: protection against infinite loop */
+
+ while (1)
+ {
+ if ((pRes->cadence.data[i >> 3] >> (7-(i%8))) & 1)
+ {
+ ring_phase = 1;
+ if (rpulse == ring)
+ break;
+ }
+ else
+ {
+ if (ring_phase)
+ {
+ ring_phase = 0;
+ ++rpulse;
+ }
+ }
+ ++bit;
+ if (++i == pRes->cadence.valid_bits)
+ i = 0;
+ }
+ return bit;
+}
+
+/**
+ Return the ringing cadence initial state; decision point
+ whether the CID sequence shall be used in the ringing cadence.
+
+ \param pCh - pointer to \ref DXS_CHANNEL_t
+
+ \return
+ - RING_CAD_STATE_CID_DURING_RINGING
+ - RING_CAD_STATE_CID_PRIOR_TO_RINGING
+ - RING_CAD_STATE_RINGING
+*/
+static int32_t dxs_ring_cad_initial_state (DXS_CHANNEL_t *pCh)
+{
+ int32_t err, ret = RING_CAD_STATE_RINGING;
+ DXS_CID_Std_t cid_std;
+ DXS_CID_AS_t cid_as;
+
+ err = DXS_CID_StandardGet(pCh, &cid_std);
+ if (err == DXS_statusOk)
+ {
+ err = DXS_CID_AlertSigGet(pCh, &cid_as);
+ }
+
+ if (err == DXS_statusOk)
+ {
+ if (cid_as == DXS_CID_AS_NONE &&
+ (cid_std == DXS_CID_STD_TELCORDIA || cid_std == DXS_CID_STD_ETSI))
+ {
+ ret = RING_CAD_STATE_CID_DURING_RINGING;
+ }
+ else if (cid_as != DXS_CID_AS_NONE && cid_std != DXS_CID_STD_UNDEF)
+ {
+ ret = RING_CAD_STATE_CID_PRIOR_TO_RINGING;
+ }
+ }
+ return ret;
+}
+
+/**
+ Attempt to shift the ringing cadence so that the new cadence
+ fits into the limitation of IFB12CH8 HW - only two ring bursts
+ are possible at a time per DCDC.
+ 1) The first available bit position for a cadence is searched -
+ where less than two rings are programmed for parallel channels.
+ 2) The new cadence is bit shifted to the found position.
+ 3) The new shifted cadence is checked from shift position to the
+ end if there is no conflict of two parallel rings.
+ If step 1) or 3) fails, than the new cadence does not fit into
+ the ring matrix of a DCDC and an error will be returned.
+
+ \param pointer to ringing resource context
+ \param ringing cadence length in bytes
+ \return
+ the code from \ref DXS_status_t list
+*/
+static int32_t dxs_ifb12ch8_shift_cadence (dxs_ring_res_t *pRes, int32_t len)
+{
+ int i, pos=0, conflict=0, dcdc;
+ unsigned int max_bits;
+ uint8_t channels_per_dcdc;
+
+ dcdc = DXS_DCDC_HW_SharedDcDcNumberGet(pRes->pCh);
+ channels_per_dcdc = DXS_DCDC_HW_SharedDcDcChannelNumGet(pRes->pCh);
+
+ /* get maximum cadence length for a DCDC */
+ for (i=0, max_bits=0; i<channels_per_dcdc; i++)
+ {
+ DXS_CHANNEL_t *pCh = DXS_DCDC_HW_SharedDcDcChannelGet(dcdc, i);
+
+ if (pCh != NULL)
+ {
+ dxs_ring_res_t *p = (dxs_ring_res_t *)pCh->ring;
+
+ if (p->cadence.valid_bits > max_bits)
+ max_bits = p->cadence.valid_bits;
+ }
+ }
+
+ /* find the first available bit position for the cadence */
+ for (i=0; i<max_bits; i++)
+ {
+ int c = 0;
+ uint8_t bits=0,
+ my_bit = (pRes->cadence.data[i >> 3] >> (7-(i % 8))) & 1;
+
+ while (c < channels_per_dcdc)
+ {
+ DXS_CHANNEL_t *pCh = DXS_DCDC_HW_SharedDcDcChannelGet(dcdc, c);
+
+ if (pCh != NULL && pCh != pRes->pCh)
+ {
+ dxs_ring_res_t *p = (dxs_ring_res_t *)pCh->ring;
+
+ uint8_t bit = (p->cadence.data[i >> 3] >> (7-(i % 8))) & 1;
+ if (bit) ++bits;
+ }
+ ++c;
+ }
+ if (bits >= 2 && my_bit && !conflict)
+ {
+ conflict = 1;
+ }
+ else if (conflict && bits < 2)
+ {
+ pos = i;
+ conflict = 0;
+ break;
+ }
+ }
+
+ if (conflict)
+ {
+ DXS_RETURN(DXS_statusRingCadConfInvalid);
+ }
+
+ DXS_Misc_DataBlkRor(pRes->cadence.data, len, pos);
+
+ /* position for a cadence start is found, now check the rest
+ of the cadence for possible conflicts */
+ i = pos;
+ do
+ {
+ int c = 0;
+ uint8_t bits=0,
+ my_bit = (pRes->cadence.data[i >> 3] >> (7-(i % 8))) & 1;
+
+ while (c < channels_per_dcdc)
+ {
+ DXS_CHANNEL_t *pCh = DXS_DCDC_HW_SharedDcDcChannelGet(dcdc, c);
+
+ if (pCh != NULL && pCh != pRes->pCh)
+ {
+ dxs_ring_res_t *p = (dxs_ring_res_t *)pCh->ring;
+
+ uint8_t bit = (p->cadence.data[i >> 3] >> (7-(i % 8))) & 1;
+ if (bit) ++bits;
+ }
+ ++c;
+ }
+
+ if (bits >= 2 && my_bit)
+ {
+ DXS_RETURN(DXS_statusRingCadConfInvalid);
+ }
+
+ if (++i == pRes->cadence.valid_bits)
+ i = 0;
+ } while (i != pos);
+ return DXS_statusOk;
+}
+
+/**
+ Start the ringing pulse
+
+ \param pointer to ringing resource context
+ \return
+ the code from \ref DXS_status_t list
+*/
+static int32_t dxs_ring_pulse_start (dxs_ring_res_t *pRes)
+{
+ int32_t ret = DXS_statusOk;
+
+ if (pRes->ring_cadence_state == RING_CAD_STATE_RINGING ||
+ pRes->ring_cadence_state == RING_CAD_STATE_CID_DURING_RINGING)
+ {
+ DXS_CHANNEL_t *pCh = pRes->pCh;
+
+ ret = DXS_SDD_LineModeSet(pCh, pRes->polarity ?
+ DXS_LINE_FEED_RINGING_REVPOL :
+ DXS_LINE_FEED_RING_BURST
+ );
+ pRes->ringer_state = (DXS_statusOk == ret) ?
+ RINGER_STATE_RINGING : RINGER_STATE_PAUSE;
+ }
+ return ret;
+}
+
+/**
+ Stop the ringing pulse
+
+ \param pointer to ringing resource context
+ \return
+ the code from \ref DXS_status_t list
+*/
+static int32_t dxs_ring_pulse_stop (dxs_ring_res_t *pRes)
+{
+ int32_t ret = DXS_statusOk;
+
+ if (pRes->ring_cadence_state == RING_CAD_STATE_RINGING ||
+ pRes->ring_cadence_state == RING_CAD_STATE_CID_DURING_RINGING)
+ {
+ DXS_CHANNEL_t *pCh = pRes->pCh;
+
+ ret = DXS_SDD_LineModeSet(pCh, pRes->polarity ?
+ DXS_LINE_FEED_ACTIVE_REVPOL :
+ DXS_LINE_FEED_ACTIVE
+ );
+ pRes->ringer_state = (DXS_statusOk == ret) ?
+ RINGER_STATE_PAUSE : RINGER_STATE_RINGING;
+ }
+ return ret;
+}
+
+/**
+ Get current bit position for the ringing cadence
+
+ \param pointer to ringing cadence resource context
+ \return bit position
+*/
+static int32_t dxs_ring_cad_bit_position_get (dxs_ring_res_t *pRes)
+{
+ int32_t bit_pos;
+
+ if (pRes->pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ /* cadence bit position is global for all channels
+ in case of IFB12CH8 */
+ bit_pos = reft.current_bit;
+ }
+ else
+ {
+ /* cadence bit position is individual for each
+ channel in case of HW without ringing limitations */
+ bit_pos = pRes->current_bit;
+ }
+ return bit_pos;
+}
+
+/**
+ Ringing timer thread function
+
+ \param pointer to ringing timer context
+ \return none
+*/
+static void *ring_timer_thread (void *arg)
+{
+ int err;
+ dxs_ring_timer_t *p = (dxs_ring_timer_t *)arg;
+ struct timespec ts = {0};
+ unsigned long ns;
+
+ while (p->state == RING_TIMER_RUNNING)
+ {
+ int32_t i, bit_position = -1;
+
+ /* run through all channels, get ring cadence bit value for
+ each channel and execute appropriate action */
+ for (i=0; i<DXS_RING_CHANNELS; i++)
+ {
+ dxs_ring_res_t *pRes = &ring_cadence[i];
+ uint8_t *cad, ring;
+
+ if (!(pRes->flag & RING_CADENCE_INIT))
+ continue;
+
+ cad = pRes->cadence.data;
+ bit_position = dxs_ring_cad_bit_position_get(pRes);
+ /* get ring cadence bit value */
+ ring = (cad[bit_position >> 3] >> (7-(bit_position % 8))) & 1;
+
+ /* handle CID prior to ringing */
+ if (pRes->ring_cadence_state == RING_CAD_STATE_CID_PRIOR_TO_RINGING)
+ {
+ if (!pRes->wait_counter && !(pRes->flag & RING_CADENCE_CID_ACT))
+ {
+ pRes->flag |= RING_CADENCE_CID_ACT;
+ err = DXS_CID_TypeI_Play(pRes->pCh, DXS_CID_MSG_TYPE_CS,
+ DXS_CID_CALL_FROM_RING_SM);
+ if (err)
+ {
+ DXS_ERROR_PUSH(err);
+ }
+ }
+ else
+ pRes->wait_counter--;
+ }
+
+ if (!ring && pRes->ringer_state == RINGER_STATE_RINGING)
+ {
+ /* RING OFF */
+ err = dxs_ring_pulse_stop(pRes);
+ if (err)
+ {
+ DXS_ERROR_PUSH(err);
+ }
+
+ /* handle CID during ringing */
+ if (pRes->ring_cadence_state == RING_CAD_STATE_CID_DURING_RINGING)
+ {
+ pRes->flag |= RING_CADENCE_CID_ACT;
+ err = DXS_CID_TypeI_Play(pRes->pCh, DXS_CID_MSG_TYPE_CS,
+ DXS_CID_CALL_FROM_RING_SM);
+ if (err)
+ {
+ DXS_ERROR_PUSH(err);
+ }
+ }
+ }
+ }
+
+ if (bit_position == -1)
+ {
+ DXS_ERROR_PUSH(-1);
+ continue;
+ }
+
+ for (i=0; i<DXS_RING_CHANNELS; i++)
+ {
+ dxs_ring_res_t *pRes = &ring_cadence[i];
+ uint8_t *cad, ring;
+
+ if (!(pRes->flag & RING_CADENCE_INIT))
+ continue;
+
+ cad = pRes->cadence.data;
+ bit_position = dxs_ring_cad_bit_position_get(pRes);
+ /* get ring cadence bit value */
+ ring = (cad[bit_position >> 3] >> (7-(bit_position % 8))) & 1;
+
+ if (ring && pRes->ringer_state == RINGER_STATE_PAUSE)
+ {
+ int32_t reset_bits = (pRes->pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8) ?
+ p->reset_bits : pRes->cadence.valid_bits;
+ int32_t pos = ((bit_position + 1) >= reset_bits) ?
+ 0 : (bit_position + 1);
+ int32_t ring_bits = 0;
+ uint8_t bit_val = ring;
+
+ /* skip execution of "short ring pulses",
+ ensure that ring pulse is at least 500ms long */
+ while (bit_val)
+ {
+ bit_val = (cad[pos >> 3] >> (7-(pos % 8))) & 1;
+ if (bit_val)
+ ++ring_bits;
+
+ if (++pos == reset_bits)
+ pos = 0;
+ }
+
+ if (ring_bits >= 10)
+ {
+ /* RING ON */
+ err = dxs_ring_pulse_start(pRes);
+ if (err)
+ {
+ DXS_ERROR_PUSH(err);
+ }
+ }
+ }
+ }
+
+ /* wait 50ms */
+ clock_gettime (CLOCK_REALTIME, &ts);
+ ns = ts.tv_nsec + RING_TIMER_INTERVAL_MS * 1000 * 1000;
+ ts.tv_nsec = ns % (1000 * 1000 * 1000);
+ ts.tv_sec += ns / (1000 * 1000 * 1000);
+ while ((err = sem_timedwait(&p->sem, &ts)) == -1 && errno == EINTR)
+ continue;
+ if (err == -1 && errno != ETIMEDOUT)
+ {
+ p->ret_val = errno;
+ break;
+ }
+
+ /* update global bit position */
+ if (++p->current_bit == p->reset_bits)
+ p->current_bit = 0;
+
+ /* update individual bit positions per channel */
+ for (i=0; i<DXS_RING_CHANNELS; i++)
+ {
+ dxs_ring_res_t *pRes = &ring_cadence[i];
+
+ if (!(pRes->flag & RING_CADENCE_INIT))
+ continue;
+
+ if (pRes->ring_cadence_state != RING_CAD_STATE_CID_PRIOR_TO_RINGING)
+ {
+ if (++pRes->current_bit == pRes->cadence.valid_bits)
+ pRes->current_bit = 0;
+ }
+ }
+ }
+ pthread_exit((void *)(&p->ret_val));
+}
+
+/**
+ Start the ringing timer
+
+ \param none
+ \return
+ the code from \ref DXS_status_t list
+*/
+static int32_t ring_timer_start (void)
+{
+ int32_t ret = DXS_statusOk;
+
+ if (reft.state == RING_TIMER_STOPPED)
+ {
+ int32_t i;
+
+ reft.state = RING_TIMER_RUNNING;
+ sem_init(&reft.sem, 0, 0);
+ reft.current_bit = 0;
+ reft.reset_bits = 0;
+
+ for (i=0; i<DXS_RING_CHANNELS; i++)
+ {
+ dxs_ring_res_t *pRes = &ring_cadence[i];
+ /* reset_bits is the maximum cadence length */
+ if ((pRes->flag & RING_CADENCE_INIT) &&
+ reft.reset_bits < pRes->cadence.valid_bits)
+ {
+ reft.reset_bits = pRes->cadence.valid_bits;
+ }
+ }
+
+ if (0 != pthread_create(&reft.thr, NULL, ring_timer_thread, (void *)&reft))
+ ret = DXS_statusThreadCreatError;
+ }
+ return ret;
+}
+
+/**
+ Stop the ringing timer
+
+ \param none
+ \return none
+*/
+static void ring_timer_stop (void)
+{
+ int i;
+
+ for (i=0; i<DXS_RING_CHANNELS; i++)
+ {
+ dxs_ring_res_t *pRes = &ring_cadence[i];
+
+ if (pRes->ring_cadence_state != RING_CAD_STATE_IDLE)
+ return;
+ }
+
+ if (reft.state != RING_TIMER_STOPPED)
+ {
+ reft.state = RING_TIMER_STOPPED;
+ sem_post(&reft.sem);
+ pthread_join(reft.thr, NULL);
+ sem_destroy(&reft.sem);
+ }
+}
+
+/**
+ Inform ringing SM about finished CID sequence
+
+ \param pCh - pointer to DXS channel structure
+ \return
+ - none
+*/
+void DXS_Ring_CidFinished (DXS_CHANNEL_t *pCh)
+{
+ dxs_ring_res_t *pRes =
+ &ring_cadence[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ if (pRes->ring_cadence_state == RING_CAD_STATE_CID_DURING_RINGING ||
+ pRes->ring_cadence_state == RING_CAD_STATE_CID_PRIOR_TO_RINGING)
+ {
+ pRes->ring_cadence_state = RING_CAD_STATE_RINGING;
+ }
+ pRes->flag &= ~RING_CADENCE_CID_ACT;
+}
+
+/**
+ Initialize ringing resource and link it
+ with the \ref DXS_CHANNEL_t structure
+
+ \param pCh - pointer to DXS channel structure
+ \return
+ pointer to ringing resource
+*/
+void *DXS_Ring_ResInit(DXS_CHANNEL_t *pCh)
+{
+ dxs_ring_res_t *pRes =
+ &ring_cadence[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
+
+ pRes->pCh = pCh;
+ pRes->flag = RING_CADENCE_NOT_INIT;
+
+ return (void *)pRes;
+}
+
+/**
+ Initialize ringing cadence
+
+ \param pCh - pointer to DXS channel structure
+ \param pConf - pointer to \ref DXS_RingCadence_t structure
+ \return
+ the code from \ref DXS_status_t list
+*/
+int32_t DXS_RING_CadenceInit (DXS_CHANNEL_t *pCh, DXS_RingCadence_t *pConf)
+{
+ int32_t ret = DXS_statusOk;
+ dxs_ring_res_t *pRes = (dxs_ring_res_t *)pCh->ring;
+ int32_t bytes, bytes_to_copy, extra_bits;
+
+ POINTER_ASSERT(pConf);
+
+ if (pRes->ring_cadence_state != RING_CAD_STATE_IDLE)
+ {
+ DXS_RETURN(DXS_statusRingCadConfNotPossible);
+ }
+
+ bytes = pConf->valid_bits >> 3;
+ extra_bits = pConf->valid_bits % 8;
+ bytes_to_copy = bytes + (extra_bits ? 1 : 0);
+
+ if (bytes_to_copy > DXS_RING_CADENCE_MAX_LEN_BYTES)
+ {
+ DXS_RETURN(DXS_statusRingCadConfInvalid);
+ }
+
+ pRes->flag &= ~RING_CADENCE_INIT;
+
+ /* copy cadence data and valid bits */
+ pRes->cadence = *pConf;
+ if (extra_bits)
+ pRes->cadence.data[bytes] &= (0xff & (0xff << (8 - extra_bits)));
+
+ /* special arrangements for IFB12CH8 HW */
+ if (pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ ret = dxs_ifb12ch8_shift_cadence(pRes, bytes_to_copy);
+ }
+
+ if (ret == DXS_statusOk)
+ {
+ pRes->ring_cadence_state = RING_CAD_STATE_IDLE;
+ pRes->ringer_state = RINGER_STATE_PAUSE;
+ pRes->flag |= RING_CADENCE_INIT;
+ }
+ DXS_RETURN(ret);
+}
+
+/**
+ Start ringing cadence
+
+ \param pCh - pointer to DXS channel structure
+ \return
+ the code from \ref DXS_status_t list
+*/
+int32_t DXS_RING_CadenceStart (DXS_CHANNEL_t *pCh)
+{
+ dxs_ring_res_t *pRes = (dxs_ring_res_t *)pCh->ring;
+ int32_t ret;
+ int opmode;
+
+ if (!(pRes->flag & RING_CADENCE_INIT))
+ {
+ DXS_RETURN(DXS_statusRingCadStartNotConf);
+ }
+
+ ret = DXS_SDD_LineModeGet(pCh, &opmode);
+ if (ret == DXS_statusOk && opmode == DXS_LINE_FEED_ACTIVE_REVPOL)
+ pRes->polarity = RING_POLARITY_REVERSE;
+
+ if (ret == DXS_statusOk)
+ {
+ pRes->current_bit = 0;
+ pRes->ring_cadence_state = dxs_ring_cad_initial_state(pCh);
+ pRes->ringer_state = RINGER_STATE_PAUSE;
+ pRes->wait_counter = 0;
+ if (pRes->pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8 &&
+ pRes->ring_cadence_state == RING_CAD_STATE_CID_PRIOR_TO_RINGING)
+ {
+ int32_t next_ring_bit_pos, cid_len_bits, ring_pulse=0;
+
+ DXS_CID_LengthBitsGet(pCh, &cid_len_bits);
+ if (cid_len_bits > 0)
+ {
+ /* set the wait_counter */
+ do
+ {
+ next_ring_bit_pos = dxs_ring_next_pos_get(pRes, ring_pulse++);
+ pRes->wait_counter = next_ring_bit_pos - cid_len_bits;
+ } while (pRes->wait_counter < 0);
+ }
+ else
+ {
+ /* zero or negative CID length means no CID */
+ pRes->ring_cadence_state = RING_CAD_STATE_RINGING;
+ }
+ }
+ ret = ring_timer_start();
+ }
+ DXS_RETURN(ret);
+}
+
+/**
+ Stop ringing cadence
+
+ \param pCh - pointer to DXS channel structure
+ \return
+ DXS_statusOk
+*/
+int32_t DXS_RING_CadenceStop (DXS_CHANNEL_t *pCh)
+{
+ int32_t ret = DXS_statusOk;
+ dxs_ring_res_t *pRes = (dxs_ring_res_t *)pCh->ring;
+
+ if (pRes->ringer_state == RINGER_STATE_RINGING)
+ {
+ ret = dxs_ring_pulse_stop(pRes);
+ }
+
+ if (pRes->ring_cadence_state == RING_CAD_STATE_CID_DURING_RINGING ||
+ pRes->ring_cadence_state == RING_CAD_STATE_CID_PRIOR_TO_RINGING)
+ {
+ DXS_CID_Stop(pCh);
+ }
+
+ if (ret == DXS_statusOk)
+ {
+ pRes->ring_cadence_state = RING_CAD_STATE_IDLE;
+ ring_timer_stop();
+ }
+ DXS_RETURN(ret);
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_ring.h b/marvell/services/dxslic/api_lib/src/dxs_ring.h
new file mode 100644
index 0000000..5376d76
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_ring.h
@@ -0,0 +1,28 @@
+#ifndef __DXS_RING_H__
+#define __DXS_RING_H__
+/*******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, 2017, 2018 Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+*******************************************************************************/
+
+/**
+ \file dxs_ring.h
+ API functions for cadenced ringing operation.
+*/
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern void *DXS_Ring_ResInit(DXS_CHANNEL_t *);
+extern void DXS_Ring_CidFinished(DXS_CHANNEL_t *);
+extern int32_t DXS_RING_CadenceInit (DXS_CHANNEL_t* , DXS_RingCadence_t* );
+extern int32_t DXS_RING_CadenceStart (DXS_CHANNEL_t* );
+extern int32_t DXS_RING_CadenceStop (DXS_CHANNEL_t* );
+
+#endif /* __DXS_RING_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_sdd.c b/marvell/services/dxslic/api_lib/src/dxs_sdd.c
new file mode 100644
index 0000000..de2beb3
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_sdd.c
@@ -0,0 +1,3692 @@
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_sdd.c
+ This file contains the implementation of the functions for SDD operations.
+*/
+
+/* ========================================================================= */
+/* Includes */
+/* ========================================================================= */
+#include <errno.h>
+#include <time.h>
+
+#include "dxs.h"
+#include "dxs_config.h"
+#include "dxs_lib.h"
+#include "dxs_fw_cmd.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_misc.h"
+#include "dxs_init.h"
+#include "dxs_sdd.h"
+#include "dxs_pcm.h"
+#include "dxs_sig.h"
+#include "dxs_event.h"
+#include "dxs_access.h"
+#include "dxs_dcdc_hw.h"
+
+/* ========================================================================= */
+/* Macro definitions */
+/* ========================================================================= */
+
+#define SDD_MWL_VOLTAGE_MAX 144 /* V */
+#define SDD_MWL_THRESH_MAX 100 /* mA */
+#define SDD_MWL_SLOPE_MIN 100 /* V/s */
+#define SDD_MWL_SLOPE_MAX 1000 /* V/s */
+#define SDD_MWL_ONOFFTIME_MAX 6375 /* ms */
+
+#define SDD_RING_FREQ_MIN 15 /* Hz */
+#define SDD_RING_FREQ_MAX 50 /* Hz */
+#define SDD_RING_CF_MAX 7
+#define SDD_RING_AMP_MAX 144 /* V */
+
+#define SDD_GR909_DC_LIMIT_MAX 655350 /* mV */
+#define SDD_GR909_AC_LIMIT_MAX 463472 /* mVrms */
+#define SDD_GR909_RFT_RIT_MAX 1048560 /* Ohm */
+#define SDD_GR909_SETTLE_TIME_MAX 3968 /* ms */
+#define SDD_GR909_ROH_LIN_MAX 65535 /* % */
+
+#define SDD_EVT_TIMEOUT_MS 100 /* ms */
+
+/* Add line mode valid transition to table */
+#define SDD_LINEMODE_TRANSITION_ADD(nModeSrc, nModeDst) \
+ line_mode_table[nModeSrc] |= 0x80000000 >> nModeDst;
+
+#define SDD_TX_GAIN_MIN (-900)
+#define SDD_TX_GAIN_MAX 40
+#define SDD_RX_GAIN_MIN (-900)
+#define SDD_RX_GAIN_MAX 0
+#define SDD_TX_GAIN_DEFAULT (-30)
+#define SDD_RX_GAIN_DEFAULT (-100)
+
+/* ACLM constants */
+#define DXS_ACLM_FR_MEASUREMENTS 35
+#define DXS_ACLM_TH_MEASUREMENTS 37
+#define DXS_ACLM_GT_MEASUREMENTS 30
+#define DXS_ACLM_SNR_MEASUREMENTS 28
+#define DXS_ACLM_INT_TIME_MS_DEFAULT 50
+#define DXS_ACLM_AC_DELAY_MS_DEFAULT 20
+#define DXS_ACLM_FR_TH_FREQ_MIN_HZ 100
+#define DXS_ACLM_FR_FREQ_CENTER_HZ 1020
+#define DXS_ACLM_FR_TH_FREQ_STEP_HZ 100
+#define DXS_ACLM_GT_LEVEL_MIN_DBM0 (-55)
+#define DXS_ACLM_SNR_LEVEL_MIN_DBM0 (-51)
+#define DXS_ACLM_GT_SNR_LEVEL_STEP_DBM0 2
+#define DXS_ACLM_MAX_RESULTS DXS_ACLM_TH_MEASUREMENTS
+
+#ifndef DXS_SHARED_DCDC_STANDBY_MODE_WKR
+#define DXS_SHARED_DCDC_STANDBY_MODE_WKR 1
+#endif
+
+/* ========================================================================= */
+/* Type definitions */
+/* ========================================================================= */
+/** Data structure for SDD basic config firmware command */
+typedef struct
+{
+ struct DXS_FW_Cmd_Header hdr;
+ struct DXS_basicConfigData bc_data;
+ /*uint32_t data[sizeof(struct DXS_FW_SDD_BasicConfig)/sizeof(uint32_t)];*/
+} __attribute__ ((packed)) DXS_FW_SDD_BasicConfig_t;
+#define DXS_FW_SDD_BasicConfig_ECMD 4
+#define DXS_FW_SDD_BasicConfig_LENGTH 20
+
+/** Data structure for SDD ring config firmware command */
+typedef struct
+{
+ struct DXS_FW_Cmd_Header hdr;
+ struct DXS_FW_SDD_RingConfig content;
+} __attribute__ ((packed)) DXS_FW_SDD_RingConfig_t;
+#define DXS_FW_SDD_RingConfig_ECMD 5
+#define DXS_FW_SDD_RingConfig_LENGTH 20
+
+/** Data structure for SDD DC/DC config firmware command */
+typedef struct
+{
+ struct DXS_FW_Cmd_Header hdr;
+ struct DXS_DcDcConfigData dcdc_data;
+} __attribute__ ((packed)) DXS_FW_SDD_DcDcConfig_t;
+#define DXS_FW_SDD_DcDcConfig_ECMD 12
+#define DXS_FW_SDD_DcDcConfig_LENGTH 8
+
+/** Data structure for SDD gain config firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Tx Relative Level Setting */
+ uint32_t TxGain : 16;
+ /** Rx Relative Level setting */
+ uint32_t RxGain : 16;
+#else
+ CMD_HEAD_LE;
+ /** Rx Relative Level setting */
+ uint32_t RxGain : 16;
+ /** Tx Relative Level Setting */
+ uint32_t TxGain : 16;
+#endif
+} __attribute__ ((packed)) DXS_FW_SDD_TxRxGain_t;
+#define DXS_FW_SDD_TxRxGain_ECMD 14
+#define DXS_FW_SDD_TxRxGain_LENGTH 4
+
+/** Data structure for SDD basic config firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Reserved */
+ uint32_t Res02 : 8;
+ /** Select Operating Mode */
+ uint32_t OpMode : 8;
+ /** Reserved */
+ uint32_t Res03 : 16;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res03 : 16;
+ /** Select Operating Mode */
+ uint32_t OpMode : 8;
+ /** Reserved */
+ uint32_t Res02 : 8;
+#endif
+} __attribute__ ((packed)) DXS_FW_SDD_Opmode_t;
+#define DXS_FW_SDD_Opmode_ECMD 7
+#define DXS_FW_SDD_Opmode_LENGTH 4
+
+/** Data structure for SDD MWL config firmware command */
+typedef struct
+{
+ struct DXS_FW_Cmd_Header hdr;
+ struct DXS_FW_SDD_MwlConfig content;
+} __attribute__ ((packed)) DXS_FW_SDD_MwlConfig_t;
+#define DXS_FW_SDD_MwlConfig_ECMD 6
+#define DXS_FW_SDD_MwlConfig_LENGTH 8
+
+/** Data structure for SDD coefficients firmware command */
+typedef struct
+{
+ struct DXS_FW_Cmd_Header hdr;
+ struct DXS_FW_SDD_Coeff content;
+} __attribute__ ((packed)) DXS_FW_SDD_Coeff_t;
+
+
+
+#define DXS_CALIBRATION_VERSION 1
+
+/** Data structure for calibration data */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+#else
+ CMD_HEAD_LE;
+#endif
+ union
+ {
+ uint32_t data1_32;
+ uint8_t data1_8[sizeof(uint32_t)];
+ };
+ union
+ {
+ uint32_t data2_32;
+ uint8_t data2_8[sizeof(uint32_t)];
+ };
+} __attribute__ ((packed)) DXS_FW_SDD_Calibrate_t;
+#define DXS_FW_SDD_Calibrate_ECMD 3
+#define DXS_FW_SDD_Calibrate_LENGTH 8
+
+
+/** Data structure for capacitance measurement result firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Capacitance Ring to Ground */
+ uint32_t CapR2G : 16;
+ /** Capacitance Tip to Ground */
+ uint32_t CapT2G : 16;
+ /** Capacitance Tip to Ring */
+ uint32_t CapT2R : 16;
+ /** Reserved */
+ uint32_t Res02 : 16;
+#else
+ CMD_HEAD_LE;
+ /** Capacitance Tip to Ground */
+ uint32_t CapT2G : 16;
+ /** Capacitance Ring to Ground */
+ uint32_t CapR2G : 16;
+ /** Reserved */
+ uint32_t Res02 : 16;
+ /** Capacitance Tip to Ring */
+ uint32_t CapT2R : 16;
+#endif
+} __attribute__ ((packed)) DXS_FW_SDD_CapMeasurRes_t;
+#define DXS_FW_SDD_CapMeasurRes_ECMD 16
+#define DXS_FW_SDD_CapMeasurRes_LENGTH 8
+
+/** Data structure for continuous measurement result firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Line Voltage */
+ int32_t Vline : 16;
+ /** Line Current */
+ int32_t Itrans : 16;
+ /** RING Current */
+ uint32_t Iring : 16;
+ /** RING Voltage */
+ uint32_t Vring : 16;
+ /** Reserved */
+ uint32_t Res02 : 32;
+#else
+ CMD_HEAD_LE;
+ /** Line Current */
+ int32_t Itrans : 16;
+ /** Line Voltage */
+ int32_t Vline : 16;
+ /** RING Voltage */
+ uint32_t Vring : 16;
+ /** RING Current */
+ uint32_t Iring : 16;
+ /** Reserved */
+ uint32_t Res02 : 32;
+#endif
+} __attribute__ ((packed)) DXS_FW_SDD_ContMeasurRes_t;
+#define DXS_FW_SDD_ContMeasurRes_ECMD 2
+#define DXS_FW_SDD_ContMeasurRes_LENGTH 12
+
+/** Data structure for GR-909 limits configuration firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Reserved */
+ uint32_t Res02 : 11;
+ /** Settle Time */
+ uint32_t SettleTime : 5;
+ /** HPT Wire to GND AC Limit */
+ uint32_t HptW2gAcLim : 16;
+ /** HPT Wire to Wire AC Limit */
+ uint32_t HptW2wAcLim : 16;
+ /** HPT Wire to GND DC Limit */
+ uint32_t HptW2gDcLim : 16;
+ /** HPT Wire to Wire DC Limit */
+ uint32_t HptW2wDcLim : 16;
+ /** FEMF Wire to GND AC Limit */
+ uint32_t FemfW2gAcLim : 16;
+ /** FEMF Wire to Wire AC Limit */
+ uint32_t FemfW2wAcLim : 16;
+ /** FEMF Wire to GND DC Limit */
+ uint32_t FemfW2gDcLim : 16;
+ /** FEMF Wire to Wire DC Limit */
+ uint32_t FemfW2wDcLim : 16;
+ /** RFT Resistance Limit */
+ uint32_t RftResLim : 16;
+ /** ROH Linearity Limit */
+ uint32_t RohLinLim : 16;
+ /** RIT Lower Limit */
+ uint32_t RitLowLim : 16;
+ /** RIT Higher Limit */
+ uint32_t RitHighLim : 16;
+ /** Reserved */
+ uint32_t Res03 : 16;
+#else
+ CMD_HEAD_LE;
+ /** HPT Wire to GND AC Limit */
+ uint32_t HptW2gAcLim : 16;
+ /** Settle Time */
+ uint32_t SettleTime : 5;
+ /** Reserved */
+ uint32_t Res02 : 11;
+ /** HPT Wire to GND DC Limit */
+ uint32_t HptW2gDcLim : 16;
+ /** HPT Wire to Wire AC Limit */
+ uint32_t HptW2wAcLim : 16;
+ /** FEMF Wire to GND AC Limit */
+ uint32_t FemfW2gAcLim : 16;
+ /** HPT Wire to Wire DC Limit */
+ uint32_t HptW2wDcLim : 16;
+ /** FEMF Wire to GND DC Limit */
+ uint32_t FemfW2gDcLim : 16;
+ /** FEMF Wire to Wire AC Limit */
+ uint32_t FemfW2wAcLim : 16;
+ /** RFT Resistance Limit */
+ uint32_t RftResLim : 16;
+ /** FEMF Wire to Wire DC Limit */
+ uint32_t FemfW2wDcLim : 16;
+ /** RIT Lower Limit */
+ uint32_t RitLowLim : 16;
+ /** ROH Linearity Limit */
+ uint32_t RohLinLim : 16;
+ /** Reserved */
+ uint32_t Res03 : 16;
+ /** RIT Higher Limit */
+ uint32_t RitHighLim : 16;
+#endif
+} __attribute__ ((packed)) DXS_FW_SDD_GR909Config_t;
+#define DXS_FW_SDD_GR909Config_ECMD 8
+#define DXS_FW_SDD_GR909Config_LENGTH 28
+
+/** Data structure for GR-909 result firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** HPT Test Valid */
+ uint32_t HptValid : 1;
+ /** FEMF Test Valid */
+ uint32_t FemfValid : 1;
+ /** RFT Test Valid */
+ uint32_t RftValid : 1;
+ /** ROH Test Valid */
+ uint32_t RohValid : 1;
+ /** RIT Test Valid */
+ uint32_t RitValid : 1;
+ /** Reserved */
+ uint32_t Res02 : 11;
+ /** HPT Test Passed */
+ uint32_t HptPass : 1;
+ /** FEMF Test Passed */
+ uint32_t FemfPass : 1;
+ /** RFT Test Passed */
+ uint32_t RftPass : 1;
+ /** ROH Test Passed */
+ uint32_t RohPass : 1;
+ /** RIT Test Passed */
+ uint32_t RitPass : 1;
+ /** Reserved */
+ uint32_t Res03 : 11;
+ /** Test Result HPT or FEMF AC Ring to GND */
+ uint32_t HptAcR2g : 16;
+ /** Test Result HPT or FEMF AC Tip to GND */
+ uint32_t HptAcT2g : 16;
+ /** Test Result HPT or FEMF AC Tip to Ring */
+ uint32_t HptAcT2r : 16;
+ /** Test Result HPT or FEMF DC Ring to GND */
+ int32_t HptDcR2g : 16;
+ /** Test Result HPT or FEMF DC Tip to GND */
+ int32_t HptDcT2g : 16;
+ /** Test Result HPT or FEMF DC Tip to Ring */
+ int32_t HptDcT2r : 16;
+ /** Resistive Fault Ring to Ground Result */
+ uint32_t RftR2g : 16;
+ /** Resistive Fault Tip to Ground Result */
+ uint32_t RftT2g : 16;
+ /** Resistive Fault Tip to Ring Result */
+ uint32_t RftT2r : 16;
+ /** Test Result ROH Low */
+ uint32_t RohLow : 16;
+ /** Test Result ROH High */
+ uint32_t RohHigh : 16;
+ /** Test Result RIT */
+ uint32_t RitRes : 16;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res03: 11;
+ /** RIT Test Passed */
+ uint32_t RitPass : 1;
+ /** ROH Test Passed */
+ uint32_t RohPass : 1;
+ /** RFT Test Passed */
+ uint32_t RftPass : 1;
+ /** FEMF Test Passed */
+ uint32_t FemfPass : 1;
+ /** HPT Test Passed */
+ uint32_t HptPass : 1;
+ /** Reserved */
+ uint32_t Res02 : 11;
+ /** RIT Test Valid */
+ uint32_t RitValid : 1;
+ /** ROH Test Valid */
+ uint32_t RohValid : 1;
+ /** RFT Test Valid */
+ uint32_t RftValid : 1;
+ /** FEMF Test Valid */
+ uint32_t FemfValid : 1;
+ /** HPT Test Valid */
+ uint32_t HptValid : 1;
+ /** Test Result HPT or FEMF AC Tip to GND */
+ uint32_t HptAcT2g : 16;
+ /** Test Result HPT or FEMF AC Ring to GND */
+ uint32_t HptAcR2g : 16;
+ /** Test Result HPT or FEMF DC Ring to GND */
+ int32_t HptDcR2g : 16;
+ /** Test Result HPT or FEMF AC Tip to Ring */
+ uint32_t HptAcT2r : 16;
+ /** Test Result HPT or FEMF DC Tip to Ring */
+ int32_t HptDcT2r : 16;
+ /** Test Result HPT or FEMF DC Tip to GND */
+ int32_t HptDcT2g : 16;
+ /** Resistive Fault Tip to Ground Result */
+ uint32_t RftT2g : 16;
+ /** Resistive Fault Ring to Ground Result */
+ uint32_t RftR2g : 16;
+ /** Test Result ROH Low */
+ uint32_t RohLow : 16;
+ /** Resistive Fault Tip to Ring Result */
+ uint32_t RftT2r : 16;
+ /** Test Result RIT */
+ uint32_t RitRes : 16;
+ /** Test Result ROH High */
+ uint32_t RohHigh : 16;
+#endif
+} __attribute__ ((packed)) DXS_FW_SDD_GR909Result_t;
+#define DXS_FW_SDD_GR909Result_ECMD 9
+#define DXS_FW_SDD_GR909Result_LENGTH 28
+
+/** Data structure for open loop calibration firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Open Loop Conductance Ring To Ground */
+ uint32_t GRG : 8;
+ /** Open Loop Conductance Tip To Ground */
+ uint32_t GTG : 8;
+ /** Open Loop Conductance Tip To Ring */
+ uint32_t GTR : 8;
+ /** Reserved */
+ uint32_t Res02 : 8;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res02 : 8;
+ /** Open Loop Conductance Tip To Ring */
+ uint32_t GTR : 8;
+ /** Open Loop Conductance Tip To Ground */
+ uint32_t GTG : 8;
+ /** Open Loop Conductance Ring To Ground */
+ uint32_t GRG : 8;
+#endif
+} __attribute__ ((packed)) DXS_FW_SDD_OpenLoopCalibration_t;
+#define DXS_FW_SDD_OpenLoopCalibration_ECMD 11
+#define DXS_FW_SDD_OpenLoopCalibration_LENGTH 4
+
+/** The SDD_AcLevelMeterControl message starts and stops
+ the AC level meter measurement. */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Enable: 0=stop, 1=start */
+ uint32_t EN : 1;
+ /** Reserved */
+ uint32_t Res02 : 31;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res02 : 31;
+ /** Enable: 0-stop, 1-start */
+ uint32_t EN : 1;
+#endif
+} __attribute__ ((packed)) DXS_FW_SDD_AcLevelMeterControl_t;
+#define DXS_FW_SDD_AcLevelMeterControl_ECMD 17
+#define DXS_FW_SDD_AcLevelMeterControl_LENGTH 4
+
+/** The SDD_AcLevelMeterConfig message configures the AC level meter. */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Bandwidth Coefficient */
+ uint32_t BW : 16;
+ /** Center Frequency Coefficient */
+ uint32_t CF : 16;
+ /** Reserved */
+ uint32_t Res02 : 14;
+ /** Bandpass enable: 0=disable, 1=enable */
+ uint32_t BP : 1;
+ /** Transhybrid enable: 0=disable, 1=enable */
+ uint32_t TH : 1;
+ /** AC Delay [ms] */
+ uint32_t Del : 7;
+ /** AC Integration Time [ms] */
+ uint32_t Int : 9;
+#else
+ CMD_HEAD_LE;
+ /** Center Frequency Coefficient */
+ uint32_t CF : 16;
+ /** Bandwidth Coefficient */
+ uint32_t BW : 16;
+ /** AC Integration Time [ms] */
+ uint32_t Int : 9;
+ /** AC Delay [ms] */
+ uint32_t Del : 7;
+ /** Transhybrid enable: 0=disable, 1=enable */
+ uint32_t TH : 1;
+ /** Bandpass enable: 0=disable, 1=enable */
+ uint32_t BP : 1;
+ /** Reserved */
+ uint32_t Res02 : 14;
+#endif
+} __attribute__ ((packed)) DXS_FW_SDD_AcLevelMeterConfig_t;
+#define DXS_FW_SDD_AcLevelMeterConfig_ECMD 18
+#define DXS_FW_SDD_AcLevelMeterConfig_LENGTH 8
+
+/** The SDD_AcLevelMeterResult message carries the AC level meter
+ measurement result. */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** AC Levelmeter Inband Result */
+ uint32_t AcInb : 24;
+ /** AC Levelmeter Inband Result Shift (signed) */
+ int32_t AcInbSh : 8;
+ /** AC Levelmeter Outband Result */
+ uint32_t AcOutb : 24;
+ /** AC Levelmeter Outband Result Shift (signed) */
+ int32_t AcOutbSh : 8;
+#else
+ CMD_HEAD_LE;
+ /** AC Levelmeter Inband Result Shift */
+ int32_t AcInbSh : 8;
+ /** AC Levelmeter Inband Result */
+ uint32_t AcInb : 24;
+ /** AC Levelmeter Outband Result Shift */
+ int32_t AcOutbSh : 8;
+ /** AC Levelmeter Outband Result */
+ uint32_t AcOutb : 24;
+#endif
+} __attribute__ ((packed)) DXS_FW_SDD_AcLevelMeterResult_t;
+#define DXS_FW_SDD_AcLevelMeterResult_ECMD 19
+#define DXS_FW_SDD_AcLevelMeterResult_LENGTH 8
+
+enum ACLM_meas_status
+{
+ /** Initial */
+ dxs_aclm_init,
+ /** Measurement in progress */
+ dxs_aclm_in_progress,
+ /** Measurement finished */
+ dxs_aclm_finished,
+ /** Measurement aborted */
+ dxs_aclm_aborted
+};
+
+typedef struct
+{
+ /** Argument */
+ int32_t arg;
+ /** Value */
+ int32_t value;
+} DXS_ACLM_Result_t;
+
+/** Data structure for SDD channel resource */
+typedef struct
+{
+ /** status flag */
+#define SDD_CH_INITIALIZED 0x00000001
+#define SDD_RING_CONFIGURED 0x80000000
+#define SDD_MWL_CONFIGURED 0x40000000
+#define SDD_DCDC_CONFIGURED 0x20000000
+ volatile uint32_t flag;
+ /** SDD Event mutex */
+ pthread_mutex_t sdd_event_mtx;
+ /* semaphore to defer until calibration has completed. */
+ sem_t calibration_wait_sem;
+ /** SDD Opmode Change condition variable */
+ pthread_cond_t sdd_opc_cv;
+ /** pending opmode change: 0=no, 1=yes */
+ volatile uint8_t bOpmodeChangePending;
+ /* Indicates that calibration was called by library (internal). */
+ volatile uint8_t bCalibrationInternal;
+ /* Indicates that calibration is needed after BBD download. */
+ volatile uint8_t bCalibrationNeeded;
+ /* Indicates that calibration is running */
+ volatile uint8_t bCalibrationRunning;
+ /** current opmode: written by outbox thread from OPC event,
+ read by DxsLineModeGet() */
+ DXS_LINE_MODE_t curr_opmode;
+ /** SDD_Coeff command */
+ DXS_FW_SDD_Coeff_t sdd_coeff;
+ /** SDD_BasicConfig command */
+ DXS_FW_SDD_BasicConfig_t basic_config;
+ /** SDD_DcDcConfig command */
+ DXS_FW_SDD_DcDcConfig_t dcdc_config;
+ /** SDD_Opmode command */
+ DXS_FW_SDD_Opmode_t opmode;
+ /** SDD_TxRxGain command */
+ DXS_FW_SDD_TxRxGain_t gain;
+ /** SDD_RingConfig command */
+ DXS_FW_SDD_RingConfig_t ring_config;
+ /** SDD_MwlConfig command */
+ DXS_FW_SDD_MwlConfig_t mwl;
+ /** SDD_Calibrate command */
+ DXS_FW_SDD_Calibrate_t calibrate;
+ /** SDD_ContMeasurRes command */
+ DXS_FW_SDD_ContMeasurRes_t contmeasur_res;
+#ifdef DXS_FEAT_CAPMEAS
+ /** SDD_CapMeasurRes command */
+ DXS_FW_SDD_CapMeasurRes_t capmeasur_res;
+#endif /* DXS_FEAT_CAPMEAS */
+#ifdef DXS_FEAT_GR909
+ /** SDD_GR909Config command */
+ DXS_FW_SDD_GR909Config_t gr909cfg;
+ /** SDD_GR909Result command */
+ DXS_FW_SDD_GR909Result_t gr909res;
+#endif /* DXS_FEAT_GR909 */
+#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
+ /** semaphore to defer untill C-Measurement or GR-909 for
+ OL calibration has completed. */
+ sem_t ol_calibration_wait_sem;
+ /** Indicates that OL calibration is running */
+ volatile uint8_t bOLCalibrationRunning;
+ /** Indicates that C-Measurements or GR-909 results for
+ OL calibration received. */
+ volatile uint8_t bOLCalibrationNltResultRdy;
+ /** OL calibration results for capacitance */
+ DXS_Capacitance_t ol_cap_meas_res;
+ /** SDD_OpenLoopCalibration command */
+ DXS_FW_SDD_OpenLoopCalibration_t ol_calibration;
+#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
+#ifdef DXS_FEAT_ACMETER
+ /** AC Level Meter event signaling semaphore */
+ sem_t aclm_sig_sem;
+ /** SDD_AcLevelMeterConfig command */
+ DXS_FW_SDD_AcLevelMeterConfig_t aclm_config;
+ /** SDD_AcLevelMeterControl command */
+ DXS_FW_SDD_AcLevelMeterControl_t aclm_ctrl;
+ /** SDD_AcLevelMeterResult command */
+ DXS_FW_SDD_AcLevelMeterResult_t aclm_result;
+ /** Current measurement selector */
+ DXS_ACLM_Measurement_t aclm_current_meas;
+ /** Measurement status */
+ enum ACLM_meas_status aclm_meas_status;
+ /** Flag to restore DISABLED opmode after measurement finish */
+ uint8_t bAclmRestoreDisabled;
+ /** Result index in a table */
+ uint8_t aclm_result_tbl_idx;
+ /** Results table */
+ DXS_ACLM_Result_t aclm_results[DXS_ACLM_MAX_RESULTS];
+#endif /* DXS_FEAT_ACMETER */
+} DXS_SDD_Ch_Resource_t;
+
+
+
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+static DXS_SDD_Ch_Resource_t sdd_chan[DXS_MAX_DEVICES * CH_PER_DEVICE] = {0};
+
+/* Line mode transition table based on DXS_LINE_MODE_t */
+static uint8_t bLineModeTblSet = 0;
+static uint32_t line_mode_table[31] = {0};
+
+static uint16_t dxs_sdd_tx_gain_precalc[] = {
+/* 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 dB */
+ 0x4f00, 0x4fea, 0x50d7, 0x51c7, 0x52b9, 0x53ae, 0x54a6, 0x55a1,
+/* 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 dB */
+ 0x569f, 0x57a0, 0x58a4, 0x59aa, 0x5ab4, 0x5bc1, 0x5cd1, 0x5de4,
+/* 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 dB */
+ 0x5efb, 0x6014, 0x6131, 0x6251, 0x6375, 0x649b, 0x65c6, 0x66f3,
+/* 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 dB */
+ 0x6824, 0x6959, 0x6a91, 0x6bcd, 0x6d0d, 0x6e50, 0x6f97, 0x70e2,
+/* 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 dB */
+ 0x7231, 0x7383, 0x74d9, 0x7634, 0x7792, 0x78f5, 0x7a5b, 0x7bc6,
+/* 4.0 dB */
+ 0x7d35
+};
+
+/* ========================================================================= */
+/* Function prototypes */
+/* ========================================================================= */
+
+/* ========================================================================= */
+/* Function implementation */
+/* ========================================================================= */
+
+/**
+ Gain calculator used by DXS_SDD_GainGet function.
+
+ \param factor - factor in Q15.16 format
+ \return
+ - int16_t calculated gain in 0.1[dB] units
+*/
+static int16_t dxs_gain_get_calc (int32_t factor)
+{
+ int32_t qCorrection_dB = 0, qTmp, qGain;
+
+ while ((qTmp = DXS_Misc_Q15_16_Mul(factor, Q15_16_TEN)) < Q15_16_ONE)
+ {
+ qCorrection_dB += Q15_16_ONE;
+ factor = qTmp;
+ }
+ qGain = DXS_Misc_Q15_16_Log10(factor);
+ /* apply gain correction, dB */
+ qGain -= qCorrection_dB;
+ qGain = DXS_Misc_Q15_16_Mul(Q15_16_TWENTY, qGain);
+ /* switch to 0.1 dB units */
+ qGain = DXS_Misc_Q15_16_Mul(qGain, Q15_16_TEN);
+ /* round up */
+ qGain += (qGain >= 0 ? Q15_16_HALF : -(Q15_16_HALF));
+
+ return (int16_t)DXS_Misc_Q15_16_to_Float(qGain);
+}
+
+/**
+ Function dxs_sdd_opmode_get
+
+ \param pRes - pointer to DXS SDD channel structure
+
+ \return
+ - int32_t
+*/
+static int32_t dxs_sdd_opmode_get(DXS_SDD_Ch_Resource_t *pRes)
+{
+ int ret = 0, err;
+ unsigned long ns;
+ struct timespec ts = {0};
+
+ err = pthread_mutex_lock(&pRes->sdd_event_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ns = ts.tv_nsec + SDD_EVT_TIMEOUT_MS * 1000 * 1000;
+ ts.tv_nsec = ns % (1000 * 1000 * 1000);
+ ts.tv_sec += ns / (1000 * 1000 * 1000);
+
+ while(pRes->bOpmodeChangePending == 1)
+ {
+ ret = pthread_cond_timedwait(&pRes->sdd_opc_cv,
+ &pRes->sdd_event_mtx, &ts);
+ if (ret != 0)
+ break;
+ }
+
+ if (ret == EINVAL || ret == EPERM)
+ ret = DXS_statusSddEvtWaitError;
+ else if (ret == ETIMEDOUT)
+ ret = DXS_statusSddEvtWaitTmout;
+
+ err = pthread_mutex_unlock(&pRes->sdd_event_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ return ret;
+}
+
+/**
+ Function to add all possible valid line mode transitions
+
+*/
+static void dxs_sdd_linemode_valid_transitions_set()
+{
+ /* Valid transitions for DISABLED line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_DISABLED, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_DISABLED, DXS_LINE_FEED_RING_BURST);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_DISABLED, DXS_LINE_FEED_STANDBY);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_DISABLED, DXS_LINE_FEED_ACTIVE);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_DISABLED, DXS_LINE_FEED_GROUND_START);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_DISABLED, DXS_LINE_FEED_CALIBRATE);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_DISABLED, DXS_LINE_FEED_GR909);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_DISABLED, DXS_LINE_FEED_RINGING_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_DISABLED, DXS_LINE_FEED_ACTIVE_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_DISABLED, DXS_LINE_FEED_CAP_MEAS);
+ /* Valid transitions for RING_BURST line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_RING_BURST, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_RING_BURST, DXS_LINE_FEED_RING_BURST);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_RING_BURST, DXS_LINE_FEED_STANDBY);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_RING_BURST, DXS_LINE_FEED_ACTIVE);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_RING_BURST, DXS_LINE_FEED_GROUND_START);
+ /* Valid transitions for STANDBY line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_STANDBY, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_STANDBY, DXS_LINE_FEED_RING_BURST);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_STANDBY, DXS_LINE_FEED_STANDBY);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_STANDBY, DXS_LINE_FEED_ACTIVE);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_STANDBY, DXS_LINE_FEED_RINGING_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_STANDBY, DXS_LINE_FEED_ACTIVE_REVPOL);
+ /* Valid transitions for ACTIVE line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE, DXS_LINE_FEED_RING_BURST);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE, DXS_LINE_FEED_STANDBY);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE, DXS_LINE_FEED_ACTIVE);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE, DXS_LINE_FEED_GROUND_START);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE, DXS_LINE_FEED_ACTIVE_MWI);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE, DXS_LINE_FEED_ACTIVE_HOWL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE, DXS_LINE_FEED_ACTIVE_REVPOL);
+ /* Valid transitions for GROUND_START line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START, DXS_LINE_FEED_RING_BURST);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START, DXS_LINE_FEED_ACTIVE);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START, DXS_LINE_FEED_GROUND_START);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START, DXS_LINE_FEED_RINGING_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START, DXS_LINE_FEED_ACTIVE_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START, DXS_LINE_FEED_GROUND_START_T2G);
+ /* Valid transitions for CALIBRATE line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_CALIBRATE, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_CALIBRATE, DXS_LINE_FEED_CALIBRATE);
+ /* Valid transitions for GR909 line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GR909, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GR909, DXS_LINE_FEED_GR909);
+ /* Valid transitions for ACTIVE_MWI line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_MWI, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_MWI, DXS_LINE_FEED_ACTIVE);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_MWI, DXS_LINE_FEED_ACTIVE_MWI);
+ /* Valid transitions for ACTIVE_HOWL line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_HOWL, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_HOWL, DXS_LINE_FEED_ACTIVE);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_HOWL, DXS_LINE_FEED_ACTIVE_HOWL);
+ /* Valid transitions for RINGING_REVPOL line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_RINGING_REVPOL, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_RINGING_REVPOL, DXS_LINE_FEED_STANDBY);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_RINGING_REVPOL, DXS_LINE_FEED_GROUND_START);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_RINGING_REVPOL, DXS_LINE_FEED_RINGING_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_RINGING_REVPOL, DXS_LINE_FEED_ACTIVE_REVPOL);
+ /* Valid transitions for ACTIVE_REVPOL line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_REVPOL, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_REVPOL, DXS_LINE_FEED_STANDBY);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_REVPOL, DXS_LINE_FEED_ACTIVE);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_REVPOL, DXS_LINE_FEED_GROUND_START);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_REVPOL, DXS_LINE_FEED_RINGING_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_REVPOL, DXS_LINE_FEED_ACTIVE_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_REVPOL, DXS_LINE_FEED_ACTIVE_HOWL_REVPOL);
+ /* Valid transitions for GROUND_START_T2G line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START_T2G, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START_T2G, DXS_LINE_FEED_RING_BURST);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START_T2G, DXS_LINE_FEED_ACTIVE);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START_T2G, DXS_LINE_FEED_GROUND_START);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START_T2G, DXS_LINE_FEED_RINGING_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START_T2G, DXS_LINE_FEED_ACTIVE_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_GROUND_START_T2G, DXS_LINE_FEED_GROUND_START_T2G);
+ /* Valid transitions for CAP_MEAS line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_CAP_MEAS, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_CAP_MEAS, DXS_LINE_FEED_CAP_MEAS);
+ /* Valid transitions for ACTIVE_HOWL_REVPOL line mode */
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_HOWL_REVPOL, DXS_LINE_FEED_DISABLED);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_HOWL_REVPOL, DXS_LINE_FEED_ACTIVE_REVPOL);
+ SDD_LINEMODE_TRANSITION_ADD(DXS_LINE_FEED_ACTIVE_HOWL_REVPOL, DXS_LINE_FEED_ACTIVE_HOWL_REVPOL);
+ /* Internal fw emergency shutdown state */
+ SDD_LINEMODE_TRANSITION_ADD(11, DXS_LINE_FEED_DISABLED);
+
+ bLineModeTblSet = 1;
+}
+
+/**
+ Function to verify if the line mode state transition is valid
+
+ \param nLineModeSrc - current line mode
+ \param nLineModeDst - requested line mode
+
+ \return
+ - DXS_statusOk or DXS_statusLineModeInvalidTransition
+*/
+static int32_t dxs_sdd_linemode_transition_check(DXS_LINE_MODE_t nLineModeSrc,
+ DXS_LINE_MODE_t nLineModeDst)
+{
+ int32_t err = DXS_statusLineModeInvalidTransition;
+
+ if ((line_mode_table[nLineModeSrc] << nLineModeDst) & 0x80000000)
+ err = DXS_statusOk;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function DXS_SDD_ChExit
+
+ \param pCh - pointer to DXS channel structure
+
+*/
+int32_t DXS_SDD_ChExit(DXS_CHANNEL_t *pCh)
+{
+ DXS_SDD_Ch_Resource_t *pRes;
+ int32_t ret = DXS_statusOk;
+
+ if (pCh == NULL)
+ return ret;
+
+ pRes = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ /* delete SDD Opmode Change condition variable */
+ ret = pthread_cond_destroy(&pRes->sdd_opc_cv);
+ if (ret != 0)
+ DXS_ERROR_PUSH(ret);
+ /* delete SDD Event mutex */
+ ret = pthread_mutex_unlock(&pRes->sdd_event_mtx);
+ if (ret != 0)
+ DXS_ERROR_PUSH(ret);
+ ret = pthread_mutex_destroy(&pRes->sdd_event_mtx);
+ if (ret != 0)
+ DXS_ERROR_PUSH(ret);
+
+ /* Delete the sem to wait for calibration to finish. */
+ sem_destroy(&pRes->calibration_wait_sem);
+
+#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
+ /* Delete the sem required by OL Calibration. */
+ sem_destroy(&pRes->ol_calibration_wait_sem);
+#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
+
+#ifdef DXS_FEAT_ACMETER
+ sem_destroy(&pRes->aclm_sig_sem);
+#endif /* DXS_FEAT_ACMETER */
+ DXS_RETURN(ret);
+}
+
+/**
+ Function obx_DXS_SDD_OpmodeUpdate
+
+ \param pCh - pointer to DXS channel structure
+ \param mode - line mode
+ \param bOPC - bOPC
+
+*/
+void obx_DXS_SDD_OpmodeUpdate(DXS_CHANNEL_t *pCh, DXS_LINE_MODE_t mode, uint8_t bOPC)
+{
+ DXS_SDD_Ch_Resource_t *pRes = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ int32_t err;
+
+ /* Avoiding race condition with DXS_SDD_ChInit().
+ Consequence - loosing of the first two OPC events, which is not a problem
+ as the device always starts from DISABLED mode after booting up. */
+ if (pRes == NULL || !(pRes->flag & SDD_CH_INITIALIZED))
+ return;
+
+ err = pthread_mutex_lock(&pRes->sdd_event_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ pRes->bOpmodeChangePending = 0;
+
+ if (bOPC == 1)
+ {
+ pRes->curr_opmode = mode;
+ }
+
+ pthread_cond_signal(&pRes->sdd_opc_cv);
+
+ err = pthread_mutex_unlock(&pRes->sdd_event_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+}
+
+/**
+ Function to initialize SDD channel resource
+
+ \param dev - device number
+ \param ch - channel number
+
+*/
+void *DXS_SDD_ChInit(uint8_t dev, uint8_t ch)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int err;
+
+ if (dev >= DXS_MAX_DEVICES || ch >= CH_PER_DEVICE)
+ return (void *)NULL;
+
+ p = &sdd_chan[dev * CH_PER_DEVICE + ch];
+
+ p->flag = 0;
+
+ p->sdd_coeff.hdr.CMD = CMD_SDD;
+ p->sdd_coeff.hdr.MOD = MOD_SDD_PCM;
+ p->sdd_coeff.hdr.ECMD = DXS_FW_SDD_Coeff_ECMD;
+ p->sdd_coeff.hdr.LENGTH = DXS_FW_SDD_Coeff_MAXLENGTH;
+ p->sdd_coeff.hdr.CHAN = ch;
+
+ p->basic_config.hdr.CMD = CMD_SDD;
+ p->basic_config.hdr.MOD = MOD_SDD_PCM;
+ p->basic_config.hdr.ECMD = DXS_FW_SDD_BasicConfig_ECMD;
+ p->basic_config.hdr.LENGTH = DXS_FW_SDD_BasicConfig_LENGTH;
+ p->basic_config.hdr.CHAN = ch;
+
+ p->dcdc_config.hdr.CMD = CMD_SDD;
+ p->dcdc_config.hdr.MOD = MOD_SDD_PCM;
+ p->dcdc_config.hdr.ECMD = DXS_FW_SDD_DcDcConfig_ECMD;
+ p->dcdc_config.hdr.LENGTH = DXS_FW_SDD_DcDcConfig_LENGTH;
+ p->dcdc_config.hdr.CHAN = ch;
+
+ p->opmode.CMD = CMD_SDD;
+ p->opmode.MOD = MOD_SDD_PCM;
+ p->opmode.ECMD = DXS_FW_SDD_Opmode_ECMD;
+ p->opmode.LENGTH = DXS_FW_SDD_Opmode_LENGTH;
+ p->opmode.CHAN = ch;
+
+ p->gain.CMD = CMD_SDD;
+ p->gain.MOD = MOD_SDD_PCM;
+ p->gain.ECMD = DXS_FW_SDD_TxRxGain_ECMD;
+ p->gain.LENGTH = DXS_FW_SDD_TxRxGain_LENGTH;
+ p->gain.CHAN = ch;
+
+ p->ring_config.hdr.CMD = CMD_SDD;
+ p->ring_config.hdr.MOD = MOD_SDD_PCM;
+ p->ring_config.hdr.ECMD = DXS_FW_SDD_RingConfig_ECMD;
+ p->ring_config.hdr.LENGTH = DXS_FW_SDD_RingConfig_LENGTH;
+ p->ring_config.hdr.CHAN = ch;
+
+ p->mwl.hdr.CMD = CMD_SDD;
+ p->mwl.hdr.MOD = MOD_SDD_PCM;
+ p->mwl.hdr.ECMD = DXS_FW_SDD_MwlConfig_ECMD;
+ p->mwl.hdr.LENGTH = DXS_FW_SDD_MwlConfig_LENGTH;
+ p->mwl.hdr.CHAN = ch;
+
+ p->calibrate.CMD = CMD_SDD;
+ p->calibrate.MOD = MOD_SDD_PCM;
+ p->calibrate.ECMD = DXS_FW_SDD_Calibrate_ECMD;
+ p->calibrate.LENGTH = DXS_FW_SDD_Calibrate_LENGTH;
+ p->calibrate.CHAN = ch;
+
+ p->contmeasur_res.CMD = CMD_SDD;
+ p->contmeasur_res.MOD = MOD_SDD_PCM;
+ p->contmeasur_res.ECMD = DXS_FW_SDD_ContMeasurRes_ECMD;
+ p->contmeasur_res.LENGTH = DXS_FW_SDD_ContMeasurRes_LENGTH;
+ p->contmeasur_res.CHAN = ch;
+
+#ifdef DXS_FEAT_CAPMEAS
+ p->capmeasur_res.CMD = CMD_SDD;
+ p->capmeasur_res.MOD = MOD_SDD_PCM;
+ p->capmeasur_res.ECMD = DXS_FW_SDD_CapMeasurRes_ECMD;
+ p->capmeasur_res.LENGTH = DXS_FW_SDD_CapMeasurRes_LENGTH;
+ p->capmeasur_res.CHAN = ch;
+#endif /* DXS_FEAT_CAPMEAS */
+
+#ifdef DXS_FEAT_GR909
+ p->gr909cfg.CMD = CMD_SDD;
+ p->gr909cfg.MOD = MOD_SDD_PCM;
+ p->gr909cfg.ECMD = DXS_FW_SDD_GR909Config_ECMD;
+ p->gr909cfg.LENGTH = DXS_FW_SDD_GR909Config_LENGTH;
+ p->gr909cfg.CHAN = ch;
+
+ p->gr909res.CMD = CMD_SDD;
+ p->gr909res.MOD = MOD_SDD_PCM;
+ p->gr909res.ECMD = DXS_FW_SDD_GR909Result_ECMD;
+ p->gr909res.LENGTH = DXS_FW_SDD_GR909Result_LENGTH;
+ p->gr909res.CHAN = ch;
+#endif /* DXS_FEAT_GR909 */
+
+#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
+ p->ol_calibration.CMD = CMD_SDD;
+ p->ol_calibration.MOD = MOD_SDD_PCM;
+ p->ol_calibration.ECMD = DXS_FW_SDD_OpenLoopCalibration_ECMD;
+ p->ol_calibration.LENGTH = DXS_FW_SDD_OpenLoopCalibration_LENGTH;
+ p->ol_calibration.CHAN = ch;
+
+ /* Open Loop Calibration flags and parameters */
+ sem_init(&p->ol_calibration_wait_sem, 0, 0);
+ p->ol_cap_meas_res.Cap_R2G = 0;
+ p->ol_cap_meas_res.Cap_T2G = 0;
+ p->ol_cap_meas_res.Cap_T2R = 0;
+ p->bOLCalibrationRunning = 0;
+ p->bOLCalibrationNltResultRdy = 0;
+#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
+
+#ifdef DXS_FEAT_ACMETER
+ p->aclm_config.CMD = CMD_SDD;
+ p->aclm_config.MOD = MOD_SDD_PCM;
+ p->aclm_config.ECMD = DXS_FW_SDD_AcLevelMeterConfig_ECMD;
+ p->aclm_config.LENGTH = DXS_FW_SDD_AcLevelMeterConfig_LENGTH;
+ p->aclm_config.CHAN = ch;
+
+ p->aclm_ctrl.CMD = CMD_SDD;
+ p->aclm_ctrl.MOD = MOD_SDD_PCM;
+ p->aclm_ctrl.ECMD = DXS_FW_SDD_AcLevelMeterControl_ECMD;
+ p->aclm_ctrl.LENGTH = DXS_FW_SDD_AcLevelMeterControl_LENGTH;
+ p->aclm_ctrl.CHAN = ch;
+
+ p->aclm_result.CMD = CMD_SDD;
+ p->aclm_result.MOD = MOD_SDD_PCM;
+ p->aclm_result.ECMD = DXS_FW_SDD_AcLevelMeterResult_ECMD;
+ p->aclm_result.LENGTH = DXS_FW_SDD_AcLevelMeterResult_LENGTH;
+ p->aclm_result.CHAN = ch;
+
+ p->aclm_current_meas = 0;
+ p->aclm_meas_status = dxs_aclm_init;
+
+ sem_init(&p->aclm_sig_sem, 0, 0);
+#endif /* DXS_FEAT_ACMETER */
+
+ pthread_mutex_init(&p->sdd_event_mtx, NULL);
+
+ err = pthread_cond_init (&p->sdd_opc_cv, NULL);
+ if (err != 0)
+ {
+ DXS_ERROR_PUSH(err);
+ err = pthread_mutex_destroy(&p->sdd_event_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ return NULL;
+ }
+
+ /* Initialize the semaphore to wait for calibration to finish. */
+ sem_init(&p->calibration_wait_sem, 0, 0);
+
+ p->bOpmodeChangePending = 0;
+ /* No calibration is needed - flag will be set during BBD download. */
+ p->bCalibrationNeeded = 0;
+ /* currently calibration is not running */
+ p->bCalibrationRunning = 0;
+ p->curr_opmode = DXS_LINE_FEED_DISABLED;
+
+ /* Set up line mode valid transitions table */
+ if (!bLineModeTblSet)
+ dxs_sdd_linemode_valid_transitions_set();
+
+ p->flag |= SDD_CH_INITIALIZED;
+
+ return (void *)p;
+}
+
+/**
+ Function DXS_SDD_CoeffBBD
+
+ \param pCh - pointer to DXS channel structure
+ \param dest - destination
+ \param blk_offset - BBD block offset
+ \param blk_len - BBD block length
+ \param pData - pointer to BBD data
+ \param padding - padding (in bytes)
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_CoeffBBD(DXS_CHANNEL_t *pCh,
+ uint8_t dest,
+ uint16_t blk_offset,
+ uint8_t blk_len, /* in words */
+ uint8_t *pData,
+ uint16_t padding) /* in bytes */
+{
+ DXS_FW_SDD_Coeff_t *pCoeff;
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk;
+ uint8_t cmd_LENGTH;
+ uint16_t coeff0;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ pCoeff = &p->sdd_coeff;
+
+ cmd_LENGTH = (blk_len + 1) << 1;
+
+ pCoeff->hdr.LENGTH = cmd_LENGTH;
+ pCoeff->content.BlockOffset = blk_offset;
+ pCoeff->content.BlockLength = blk_len;
+ pCoeff->content.Dest = dest;
+ DXS_cpb2w(&coeff0, pData, sizeof(coeff0));
+ pCoeff->content.Coefficient0 = coeff0;
+
+ DXS_cpb2dw(&pCoeff->content.Coefficients_32[0],
+ pData + sizeof(coeff0),
+ cmd_LENGTH - sizeof(coeff0) - 2);
+
+ if (padding)
+ pCoeff->hdr.LENGTH += padding;
+
+#if 1
+ err = CmdWrite(pCh->pParent, (uint32_t *)pCoeff);
+#else
+ {
+ int i;
+ uint32_t *p = (uint32_t *)pCoeff;
+
+ fprintf (stderr, "BBD CRAM: ");
+ for (i=0; i<((pCoeff->hdr.LENGTH >> 2) + 1); i++, p++)
+ {
+ fprintf (stderr, "%08X ", *p);
+ }
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function DXS_SDD_DcDcConfigBBD
+
+ \param pCh - pointer to DXS channel structure
+ \param data - SDD_DcDcConfig command payload
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_DcDcConfigBBD (DXS_CHANNEL_t *pCh, struct DXS_DcDcConfigData *data)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err;
+ DXS_CHANNEL_t *pChMaster;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* Block dcdc reconfiguration */
+ if (p->flag & SDD_DCDC_CONFIGURED)
+ return DXS_statusBbdDcDcReconfig;
+
+ p->dcdc_config.dcdc_data = *data;
+
+ /* Download dcdc_config for both channels in case of combined DC/DC */
+ if (pCh->pParent->dcdcType == DXS_DCDC_CIBB12 ||
+ pCh->pParent->dcdcType == DXS_DCDC_CIFB12 ||
+ pCh->pParent->dcdcType == DXS_DCDC_CBB48)
+ {
+ DXS_CHANNEL_t *pChNeighbour;
+ DXS_SDD_Ch_Resource_t *pN;
+
+ pChNeighbour =
+ pCh->nCh ? &pCh->pParent->pChannel[0] : &pCh->pParent->pChannel[1];
+ pN = (DXS_SDD_Ch_Resource_t*) pChNeighbour->sdd;
+ if (!(pN->flag & SDD_DCDC_CONFIGURED))
+ {
+ pN->dcdc_config.dcdc_data = *data;
+ /* In case of CmdWrite error for neighbour channel do not return an
+ error but clear BBD_DOWNLOAD and do not set DCDC_CONFIGURED flags */
+ if (CmdWrite(pChNeighbour->pParent, (uint32_t *)&pN->dcdc_config) !=
+ DXS_statusOk)
+ pChNeighbour->flags &= ~DXS_CH_BBD_DOWNLOADED;
+ else
+ pN->flag |= SDD_DCDC_CONFIGURED;
+ }
+ }
+
+ /* if master channel is available, write configuration
+ only for master channel */
+ if (pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ pChMaster = DXS_DCDC_HW_SharedDcDcMasterChGetInt(pCh->pParent);
+ if (pChMaster == NULL)
+ {
+ DXS_RETURN(DXS_statusBbdDCDCMasterNotSet);
+ }
+
+ if (pCh == pChMaster)
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->dcdc_config);
+ else
+ err = DXS_statusOk;
+ }
+ else
+ {
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->dcdc_config);
+ }
+
+ if (err == DXS_statusOk)
+ p->flag |= SDD_DCDC_CONFIGURED;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function DXS_SDD_BasicConfigBBD
+
+ \param pCh - pointer to DXS channel structure
+ \param data - SDD_BasicConfig command payload
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_BasicConfigBBD (DXS_CHANNEL_t *pCh, struct DXS_basicConfigData *data)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+ p->basic_config.bc_data = *data;
+
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->basic_config);
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function DXS_SDD_RingConfigBBD
+
+ \param pCh - pointer to DXS channel structure
+ \param pRingConf - pointer to SDD ring configuration structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_RingConfigBBD (DXS_CHANNEL_t *pCh,
+ struct DXS_FW_SDD_RingConfig *pRingConf)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ p->ring_config.content = *pRingConf;
+
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->ring_config);
+ if (!err)
+ {
+ p->flag |= SDD_RING_CONFIGURED;
+ }
+
+ DXS_RETURN(err);
+}
+
+
+/**
+ Function DXS_SDD_RingConfigAPI
+
+ \param pCh - pointer to DXS channel structure
+ \param waveForm - waveform type
+ \param crestFactor - crest factor
+ \param frequency - frequency
+ \param amplitude - amplitude
+ \param dcOffset - DC offset
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_RingConfigAPI (DXS_CHANNEL_t *pCh, uint8_t waveForm,
+ uint8_t crestFactor, uint8_t frequency,
+ uint16_t amplitude, uint16_t dcOffset)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ uint16_t new_freq, new_amp, new_dcoff;
+ int32_t err = DXS_statusOk;
+ uint32_t tmp;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* parameter sanity check */
+ if (waveForm > 1 || crestFactor > SDD_RING_CF_MAX ||
+ frequency < SDD_RING_FREQ_MIN || frequency > SDD_RING_FREQ_MAX ||
+ (amplitude + dcOffset) > SDD_RING_AMP_MAX)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ if (!(p->flag & SDD_RING_CONFIGURED))
+ {
+ /* read configuration from the device */
+ err = DXS_CmdRead(pCh->pParent, (uint32_t *)&p->ring_config,
+ (uint32_t *)&p->ring_config);
+ if (err)
+ {
+ DXS_RETURN(err);
+ }
+ }
+
+ /* calculate new parameter values */
+
+ /* Frequency = (32768 * fring[Hz]) / 1000 */
+ tmp = frequency << 15;
+ new_freq = (uint16_t)DXS_Misc_RoundDiv(tmp, 1000);
+
+ /* Amplitude = V[Vp] * 2^15 / 144 */
+ tmp = amplitude << 15;
+ new_amp = (uint16_t)DXS_Misc_RoundDiv(tmp, 144);
+
+ /* DcOffset = Voltage[V] * 32768 / 144 */
+ tmp = dcOffset << 15;
+ new_dcoff = (uint16_t)DXS_Misc_RoundDiv(tmp, 144);
+
+ if (p->ring_config.content.WaveForm != waveForm ||
+ p->ring_config.content.CrestFact != crestFactor ||
+ p->ring_config.content.Frequency != new_freq ||
+ p->ring_config.content.Amplitude != new_amp ||
+ p->ring_config.content.DcOffset != new_dcoff)
+ {
+ p->ring_config.content.WaveForm = waveForm;
+ p->ring_config.content.CrestFact = crestFactor;
+ p->ring_config.content.Frequency = new_freq;
+ /* amplitude dependencies */
+ p->ring_config.content.Amplitude = new_amp;
+ if (amplitude >= 57/*~40Vrms*/)
+ {
+ p->ring_config.content.Vmin = 0x32AB;/*~40Vrms*/
+ }
+ else
+ {
+ p->ring_config.content.Vmin = p->ring_config.content.Amplitude;
+ }
+ /* DC offset dependencies */
+ p->ring_config.content.DcOffset = new_dcoff;
+ if (dcOffset >= 12)
+ {
+ p->ring_config.content.RingTripType = 0;
+ tmp = DXS_Misc_RoundDiv(dcOffset * 1000000,1700);
+ }
+ else
+ {
+ p->ring_config.content.RingTripType = 1;
+ tmp = DXS_Misc_RoundDiv(amplitude * 636620,1000);
+ }
+ p->ring_config.content.Thresh = (uint16_t)DXS_Misc_RoundDiv(tmp << 15, 100000);
+
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->ring_config);
+ if (err)
+ {
+ DXS_RETURN(err);
+ }
+ }
+
+ p->flag |= SDD_RING_CONFIGURED;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function DXS_SDD_MwlConfigBBD
+
+ \param pCh - pointer to DXS channel structure
+ \param pMwlConf - pointer to SDD MWL configuration structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_MwlConfigBBD (DXS_CHANNEL_t *pCh,
+ struct DXS_FW_SDD_MwlConfig *pMwlConf)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ p->mwl.content = *pMwlConf;
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->mwl);
+ if (!err)
+ {
+ p->flag |= SDD_MWL_CONFIGURED;
+ }
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function DXS_SDD_MwlConfigAPI
+
+ \param pCh - pointer to DXS channel structure
+ \param voltage - voltage
+ \param thresh - threshold
+ \param slope - slope
+ \param onTime - on-time
+ \param offTime - off-time
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_MwlConfigAPI(DXS_CHANNEL_t *pCh, uint8_t voltage,
+ uint8_t thresh, uint16_t slope, uint16_t onTime,
+ uint16_t offTime)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ uint16_t new_voltage, new_thresh, new_slope;
+ uint8_t new_onTime, new_offTime;
+ int32_t err = DXS_statusOk;
+ uint32_t tmp;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* parameter range check */
+ if (voltage >= SDD_MWL_VOLTAGE_MAX || thresh >= SDD_MWL_THRESH_MAX ||
+ slope < SDD_MWL_SLOPE_MIN || slope > SDD_MWL_SLOPE_MAX ||
+ onTime > SDD_MWL_ONOFFTIME_MAX || offTime > SDD_MWL_ONOFFTIME_MAX)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ /* MWL is not allowed for combined and shared DCDC variants */
+ if (pCh->pParent->dcdcType == DXS_DCDC_CIBB12 ||
+ pCh->pParent->dcdcType == DXS_DCDC_CIFB12 ||
+ pCh->pParent->dcdcType == DXS_DCDC_CBB48 ||
+ pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ DXS_RETURN(DXS_statusMwlNotAllowed);
+ }
+
+ if (!(p->flag & SDD_MWL_CONFIGURED))
+ {
+ /* read configuration from the device */
+ err = DXS_CmdRead(pCh->pParent, (uint32_t *)&p->mwl, (uint32_t *)&p->mwl);
+ if (err)
+ {
+ DXS_RETURN(err);
+ }
+ }
+
+ /* calculate new parameter values */
+
+ /* Voltage = V[Vp] * 2^15 / 144 */
+ tmp = (uint32_t)voltage << 15;
+ new_voltage = DXS_Misc_RoundDiv(tmp, 144);
+
+ /* Thresh = Current[A] * 32768 / 0.1 */
+ tmp = (uint32_t)thresh << 15;
+ new_thresh = DXS_Misc_RoundDiv(tmp, 100);
+
+ /* Slope = Slope[V/s] * 32768 / 144 / 2000 */
+ tmp = (uint32_t)slope << 15;
+ tmp = DXS_Misc_RoundDiv(tmp, 144);
+ new_slope = DXS_Misc_RoundDiv(tmp, 2000);
+
+ /* OnTime = time[s] / 0.025 */
+ new_onTime = DXS_Misc_RoundDiv(onTime, 25);
+
+ /* OffTime = time[s] / 0.025 */
+ new_offTime = DXS_Misc_RoundDiv(offTime, 25);
+
+ if (p->mwl.content.Voltage != new_voltage ||
+ p->mwl.content.Thresh != new_thresh ||
+ p->mwl.content.Slope != new_slope ||
+ p->mwl.content.OnTime != new_onTime ||
+ p->mwl.content.OffTime != new_offTime)
+ {
+ /* write new values */
+ p->mwl.content.Voltage = new_voltage;
+ p->mwl.content.Thresh = new_thresh;
+ p->mwl.content.Slope = new_slope;
+ p->mwl.content.OnTime = new_onTime;
+ p->mwl.content.OffTime = new_offTime;
+
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->mwl);
+ if (err)
+ {
+ DXS_RETURN(err);
+ }
+ }
+
+ p->flag |= SDD_MWL_CONFIGURED;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function DXS_SDD_GainSet
+
+ \param pCh - pointer to DXS channel structure
+ \param TxGain - digital gain in units of 0.1 dB (A->D direction)
+ \param RxGain - digital gain in units of 0.1 dB (D->A direction)
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_GainSet(DXS_CHANNEL_t *pCh, int16_t TxGain, int16_t RxGain)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk;
+ uint16_t new_gain_tx, new_gain_rx;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* parameter range check */
+ if (TxGain < SDD_TX_GAIN_MIN || TxGain > SDD_TX_GAIN_MAX ||
+ RxGain < SDD_RX_GAIN_MIN || RxGain > SDD_RX_GAIN_MAX)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ /* calculate new parameter values */
+ if (TxGain >= 0)
+ {
+ new_gain_tx = dxs_sdd_tx_gain_precalc[TxGain];
+ }
+ else
+ {
+ new_gain_tx = DXS_Misc_MulQ15(20224, DXS_Misc_LeveldB_to_Factor(TxGain));
+ }
+
+ new_gain_rx = DXS_Misc_MulQ15(30720, DXS_Misc_LeveldB_to_Factor(RxGain));
+
+ if (new_gain_tx != p->gain.TxGain || new_gain_rx != p->gain.RxGain)
+ {
+ /* write new values */
+ p->gain.TxGain = new_gain_tx;
+ p->gain.RxGain = new_gain_rx;
+
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->gain);
+ if (err)
+ {
+ DXS_RETURN(err);
+ }
+ }
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function DXS_SDD_GainGet
+
+ \param pCh - pointer to DXS channel structure
+ \param pTxGain - pointer to a digital gain value in dB, A->D direction
+ \param pRxGain - pointer to a digital gain value in dB, D->A direction
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_GainGet(DXS_CHANNEL_t *pCh, int16_t *pTxGain, int16_t *pRxGain)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk, qFactor /* in Q15.16 scale */;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* read gains from device */
+ err = DXS_CmdRead(pCh->pParent, (uint32_t *)&p->gain,
+ (uint32_t *)&p->gain);
+
+ if (err == DXS_statusOk)
+ {
+ /* Tx */
+ qFactor = DXS_Misc_Q15_16_Div(p->gain.TxGain, 20224);
+ *pTxGain = dxs_gain_get_calc(qFactor);
+
+ /* Rx */
+ qFactor = DXS_Misc_Q15_16_Div(p->gain.RxGain, 30720);
+ *pRxGain = dxs_gain_get_calc(qFactor);
+ }
+ else
+ {
+ err = DXS_statusError;
+ }
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function to set line mode
+
+ \param pCh - pointer to DXS channel structure
+ \param mode - line mode
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_LineModeSet(DXS_CHANNEL_t *pCh, int mode)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (!(pCh->flags & DXS_CH_BBD_DOWNLOADED) && (mode != DXS_LINE_FEED_DISABLED))
+ {
+ DXS_RETURN(DXS_statusBbdNotDownloaded);
+ }
+
+ /* The following checks can be skipped for mode=DISABLED */
+ if (mode != DXS_LINE_FEED_DISABLED)
+ {
+ /* Verify line mode id parameter */
+ /* From every valid line mode it is possible to switch to disabled,
+ therefore to check if the line mode is valid the line modes
+ transition table can be used. */
+ if (((mode < 0) || (mode > 31)) ||
+ (dxs_sdd_linemode_transition_check(mode, DXS_LINE_FEED_DISABLED)
+ == DXS_statusLineModeInvalidTransition))
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ /* following opmodes require device capabilities check */
+ if ((mode == DXS_LINE_FEED_ACTIVE_HOWL ||
+ mode == DXS_LINE_FEED_ACTIVE_HOWL_REVPOL) &&
+ !DXS_IsFeatureSupported(pCh->pParent, dxs_cap_howler))
+ {
+ DXS_RETURN(DXS_statusFeatNotSupportedCaps);
+ }
+
+ /* Combined DC/DC have restrictions */
+ if (pCh->pParent->dcdcType == DXS_DCDC_CIBB12 ||
+ pCh->pParent->dcdcType == DXS_DCDC_CIFB12 ||
+ pCh->pParent->dcdcType == DXS_DCDC_CBB48 ||
+ pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8)
+ {
+ if (mode == DXS_LINE_FEED_ACTIVE_MWI)
+ {
+ /* Message Waiting Lamp is not allowed for combined and shared DCDC variants */
+ DXS_RETURN(DXS_statusMwlNotAllowed);
+ }
+ }
+ }
+
+ /* update current opmode,
+ wait while an opmode change is ongoing */
+ err = dxs_sdd_opmode_get(p);
+ if (err == DXS_statusSddEvtWaitError)
+ {
+ DXS_RETURN(err);
+ }
+
+#if (DXS_SHARED_DCDC_STANDBY_MODE_WKR==1)
+ if (pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8 &&
+ mode == DXS_LINE_FEED_STANDBY)
+ {
+ /* temporary workaround: replace STBY with ACT */
+ mode = DXS_LINE_FEED_ACTIVE;
+ }
+#endif /* DXS_SHARED_DCDC_STANDBY_MODE_WKR */
+
+ if (p->curr_opmode == mode)
+ {
+ /* parameters aren't changed */
+ return DXS_statusOk;
+ }
+
+ /* Check if line mode transition is valid */
+ err = dxs_sdd_linemode_transition_check(p->curr_opmode, mode);
+ if (err == DXS_statusLineModeInvalidTransition)
+ {
+ DXS_RETURN(err);
+ }
+
+ /* handle DC/DC HW specific limitations */
+ if (mode == DXS_LINE_FEED_RING_BURST || mode == DXS_LINE_FEED_RINGING_REVPOL)
+ {
+ if ((err = DXS_DCDC_HW_RingingCapsCheck(pCh)) != DXS_statusOk)
+ {
+ DXS_RETURN(err);
+ }
+ }
+
+ p->bOpmodeChangePending = 1;
+
+ p->opmode.OpMode = mode;
+
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->opmode);
+ if (err)
+ {
+ DXS_RETURN(DXS_statusSddOpmodeSetError);
+ }
+ /* Set flag so that we can detect the end of calibration */
+ if (mode == DXS_LINE_FEED_CALIBRATE)
+ p->bCalibrationRunning = 1;
+
+ return DXS_statusOk;
+}
+
+/**
+ Function to get line mode
+
+ \param pCh - pointer to DXS channel structure
+ \param pMode - pointer to line mode
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_LineModeGet(DXS_CHANNEL_t *pCh, int *pMode)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* update current opmode,
+ wait while an opmode change is ongoing */
+ err = dxs_sdd_opmode_get(p);
+ if (err == DXS_statusSddEvtWaitError)
+ {
+ DXS_RETURN(err);
+ }
+
+ *pMode = p->curr_opmode;
+
+ return DXS_statusOk;
+}
+
+
+/* ========================================================================== */
+/* Calibration stuff */
+/* ========================================================================== */
+#if 0
+/**
+ Start calibration process for analog channel.
+
+ Run calibration mechanism and check new calibration offsets
+
+ \param pCh Pointer to the DxS channel structure.
+
+ \return
+ - DXS_statusOk if successful, error code otherwise
+*/
+static int32_t DXS_SDD_CalibrationStart(DXS_CHANNEL_t *pCh)
+{
+ DXS_SDD_Ch_Resource_t *p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ int32_t ret = DXS_statusOk;
+
+ /* Remember if started from API or driver internal. */
+ p->bCalibrationInternal = 1;
+ /* Start calibration */
+ ret = DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_CALIBRATE);
+ DXS_RETURN(ret);
+}
+#endif
+
+
+/**
+ Finish calibration process on the analog line.
+
+ This function is called after the firmware indicated that calibration has
+ finished. An event is sent to the application
+ to inform about the end of the calibration process, if calibration was
+ started using API (DxsLineModeSet).
+
+ \param pCh Pointer to the DxS channel structure.
+
+ \return
+ - DXS_statusOk if successful, error code otherwise
+*/
+int32_t DXS_SDD_Calibration_Finish(DXS_CHANNEL_t *pCh,
+ DXS_Event_t *pEvent)
+{
+ DXS_SDD_Ch_Resource_t *p;
+
+ /* sanity check */
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ p->bCalibrationRunning = 0;
+ p->bCalibrationNeeded = 0;
+ if (p->bCalibrationInternal)
+ {
+ /* Wake the waiting call in DXS_SDD_Calibration below. */
+ sem_post(&p->calibration_wait_sem);
+ }
+ else
+ {
+ pEvent->id = DXS_EVENT_CALIBRATION_END;
+ DXS_EventDispatch(pCh->pParent, pEvent);
+ }
+
+ return DXS_statusOk;
+}
+
+
+/**
+ Used internally to start calibration on the given analog line.
+
+ This function is called after a BBD download was done to calibrate the
+ analog channel where the download has just been done. This function blocks
+ until the finished event has been received.
+
+ \param pCh Pointer to the DXT channel structure.
+
+ \return
+ - DXS_statusOk if successful
+ - DXS_statusInvalidParam Invalid parameters
+*/
+int32_t DXS_SDD_Calibration(DXS_CHANNEL_t *pCh)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t ret;
+
+ /* sanity check */
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (p->bCalibrationRunning == 1)
+ {
+ /* Current line mode is CALIBRATE */
+ DXS_RETURN (DXS_statusCalInProgress);
+ }
+ p->bCalibrationInternal = 1;
+ /* Start calibration */
+ ret = DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_CALIBRATE);
+
+ if (ret == DXS_statusOk)
+ {
+ /* Block until the semaphore is given in the calibration finished
+ function */
+ ret = sem_wait(&p->calibration_wait_sem);
+ if (ret)
+ DXS_RETURN(ret);
+ }
+
+ DXS_RETURN(ret);
+}
+
+
+/**
+ Function to read the results of calibration measurements
+
+ \param pCh - pointer to DXS channel structure
+ \param pCalibration - pointer to calibration structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_CalibrationGet(DXS_CHANNEL_t *pCh,
+ DXS_Calibration_t *pCalibration)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk;
+
+ if (pCh == NULL || pCalibration == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+ if (pCalibration->version != DXS_CALIBRATION_VERSION)
+ {
+ DXS_RETURN(DXS_statusCalVersInvalid);
+ }
+ if (p->bCalibrationRunning == 1)
+ {
+ /* Current line mode is CALIBRATE */
+ DXS_RETURN (DXS_statusCalInProgress);
+ }
+
+ /* read results from the device */
+ err = DXS_CmdRead(pCh->pParent, (uint32_t *)&p->calibrate,
+ (uint32_t *)&p->calibrate);
+ if (err)
+ {
+ DXS_RETURN(err);
+ }
+
+ /* Set the parameters */
+ /* Note: DXS_cpb2dw() is needed for dxs_CRC_8_CCITT() */
+ DXS_cpb2dw(pCalibration->data, &p->calibrate.data1_8[0], sizeof(uint32_t));
+ DXS_cpb2dw(pCalibration->data + 1, &p->calibrate.data2_8[0], sizeof(uint32_t));
+ pCalibration->crc8ccitt = dxs_CRC_8_CCITT((uint8_t *)pCalibration->data,
+ sizeof(pCalibration->data));
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ /* Restore the values for output after processing dxs_CRC_8_CCITT() */
+ pCalibration->data[0] = p->calibrate.data1_32;
+ pCalibration->data[1] = p->calibrate.data2_32;
+#endif
+
+ DXS_RETURN(err);
+}
+
+
+/**
+ Function to write calibration hardware configuration values
+
+ \param pCh - pointer to DXS channel structure
+ \param pCalibration - pointer to calibration structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_CalibrationSet(DXS_CHANNEL_t *pCh,
+ DXS_Calibration_t *pCalibration)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t ret = DXS_statusOk;
+ uint8_t nCRC;
+ uint32_t pDataOrdered[2];
+
+ if (pCh == NULL || pCalibration == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+ if (pCalibration->version != DXS_CALIBRATION_VERSION)
+ {
+ DXS_RETURN(DXS_statusCalVersInvalid);
+ }
+ if (p->bCalibrationRunning == 1)
+ {
+ /* Current line mode is CALIBRATE */
+ DXS_RETURN (DXS_statusCalInProgress);
+ }
+
+ /* Get the parameters */
+ p->calibrate.data1_32 = pCalibration->data[0];
+ p->calibrate.data2_32 = pCalibration->data[1];
+ /* DXS_cpb2dw() is needed for dxs_CRC_8_CCITT() */
+ DXS_cpb2dw(pDataOrdered, &p->calibrate.data1_8[0], sizeof(uint32_t));
+ DXS_cpb2dw(pDataOrdered + 1, &p->calibrate.data2_8[0], sizeof(uint32_t));
+ nCRC = dxs_CRC_8_CCITT((uint8_t *)pDataOrdered, sizeof(pDataOrdered));
+
+ /* If CRC is correct and at least one of data fields is non-zero, write
+ * calibration data to device */
+ if (nCRC == pCalibration->crc8ccitt && (p->calibrate.data1_32 != 0 ||
+ p->calibrate.data2_32 != 0))
+ ret = DXS_CmdWrite(pCh->pParent, (uint32_t *)&p->calibrate);
+ else
+ {
+ ret = DXS_SDD_Calibration(pCh);
+ if (ret != DXS_statusOk)
+ {
+ /* Automatic calibration failed. */
+ ret = DXS_statusAutomaticCalibrationFailed;
+ }
+ }
+
+ DXS_RETURN(ret);
+}
+
+#ifdef DXS_FEAT_CAPMEAS
+/**
+ Function to get capacitance measurement result
+
+ \param pCh - pointer to DXS channel structure
+ \param bCalibrated - flag to return calibrated values
+ \param pCapacitance - pointer to capacitance measurement result structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_CapMeasurementResultGet(DXS_CHANNEL_t *pCh, uint8_t bCalibrated,
+ DXS_Capacitance_t *pCapacitance)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk;
+
+ if (pCh == NULL || pCapacitance == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* read results from the device */
+ err = DXS_CmdRead(pCh->pParent, (uint32_t *)&p->capmeasur_res,
+ (uint32_t *)&p->capmeasur_res);
+ if (err)
+ {
+ DXS_RETURN(err);
+ }
+
+ /* Set the parameters */
+#ifdef DXS_FEAT_GR909
+ if (bCalibrated)
+ {
+ pCapacitance->Cap_R2G =
+ p->capmeasur_res.CapR2G >= p->ol_cap_meas_res.Cap_R2G ?
+ p->capmeasur_res.CapR2G - p->ol_cap_meas_res.Cap_R2G : 0;
+ pCapacitance->Cap_T2G =
+ p->capmeasur_res.CapT2G >= p->ol_cap_meas_res.Cap_T2G ?
+ p->capmeasur_res.CapT2G - p->ol_cap_meas_res.Cap_T2G : 0;
+ pCapacitance->Cap_T2R = p->ol_cap_meas_res.Cap_T2R + DXS_Misc_RoundDiv(
+ (uint32_t) pCapacitance->Cap_R2G + pCapacitance->Cap_T2G, 4);
+ pCapacitance->Cap_T2R = p->capmeasur_res.CapT2R >= pCapacitance->Cap_T2R ?
+ p->capmeasur_res.CapT2R - pCapacitance->Cap_T2R : 0;
+ }
+ else
+#endif /* DXS_FEAT_GR909 */
+ {
+ pCapacitance->Cap_R2G = p->capmeasur_res.CapR2G;
+ pCapacitance->Cap_T2G = p->capmeasur_res.CapT2G;
+ pCapacitance->Cap_T2R = p->capmeasur_res.CapT2R;
+ }
+
+ DXS_RETURN(err);
+}
+#endif /* DXS_FEAT_CAPMEAS */
+
+/**
+ Function to get continuous measurement result
+
+ \param pCh - pointer to DXS channel structure
+ \param pContMeasurement - pointer to continuous measurement result structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_ContMeasurementResultGet(DXS_CHANNEL_t *pCh,
+ DXS_ContMeasurementResult_t *pContMeasurement)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk;
+
+ POINTER_ASSERT(pCh);
+ POINTER_ASSERT(pContMeasurement);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* read results from the device */
+ err = DXS_CmdRead(pCh->pParent, (uint32_t *)&p->contmeasur_res,
+ (uint32_t *)&p->contmeasur_res);
+ if (err)
+ DXS_RETURN(err);
+
+ /* Set the parameters */
+
+ /* Output voltage of DC regulation. (with conversion to milivolts) */
+ /* V [V] = Vline / 2^15 * 144 */
+ pContMeasurement->Vline =
+ (((int64_t) p->contmeasur_res.Vline * 144000) + 0x4000) / 0x8000;
+ /* Value of the actual line current. (with conversion to microampere) */
+ /* I[A] = Itrans / 2^15 * 0.1 */
+ pContMeasurement->Itrans =
+ (((int64_t) p->contmeasur_res.Itrans * 100000) + 0x4000) / 0x8000;
+ /* Value of the last ring burst current. RMS valueof ring current
+ within the last ring period. (with conversion to microampere) */
+ /* I[A RMS ] = Iring / 2^15 * 0.07071 */
+ pContMeasurement->Iring =
+ (((uint64_t) p->contmeasur_res.Iring * 70710) + 0x4000) / 0x8000;
+ /* Value of the last ring burst voltage. RMS value of VDAC sine.
+ (with conversion to milivolts) */
+ /* V[V RMS ] = Vring / 2^15 * 101.82 */
+ pContMeasurement->Vring =
+ (((uint64_t) p->contmeasur_res.Vring * 101820) + 0x4000) / 0x8000;
+
+ DXS_RETURN(err);
+}
+
+#ifdef DXS_FEAT_GR909
+/**
+ Function to set GR-909 limits
+
+ \param pCh - pointer to DXS channel structure
+ \param pGR909Conf - pointer to SDD GR909 configuration structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_GR909LimitsSet(DXS_CHANNEL_t *pCh,
+ DXS_GR909Config_t *pGR909Conf)
+{
+ int32_t err = DXS_statusOk;
+ DXS_SDD_Ch_Resource_t *p;
+ uint16_t settle_time, HPT_W2G_AC_Lim, HPT_W2W_AC_Lim, HPT_W2G_DC_Lim,
+ HPT_W2W_DC_Lim, FEMF_W2G_AC_Lim, FEMF_W2W_AC_Lim, FEMF_W2G_DC_Lim,
+ FEMF_W2W_DC_Lim, RFT_Res_Lim, ROH_Lin_Lim, RIT_Low_Lim, RIT_High_Lim;
+
+ POINTER_ASSERT(pCh);
+ POINTER_ASSERT(pGR909Conf);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* Parameters' sanity check */
+ if (pGR909Conf->settle_time > SDD_GR909_SETTLE_TIME_MAX ||
+ pGR909Conf->HPT_W2G_AC_Lim > SDD_GR909_AC_LIMIT_MAX ||
+ pGR909Conf->HPT_W2W_AC_Lim > SDD_GR909_AC_LIMIT_MAX ||
+ pGR909Conf->FEMF_W2G_AC_Lim > SDD_GR909_AC_LIMIT_MAX ||
+ pGR909Conf->FEMF_W2W_AC_Lim > SDD_GR909_AC_LIMIT_MAX ||
+ pGR909Conf->HPT_W2G_DC_Lim > SDD_GR909_DC_LIMIT_MAX ||
+ pGR909Conf->HPT_W2W_DC_Lim > SDD_GR909_DC_LIMIT_MAX ||
+ pGR909Conf->FEMF_W2G_DC_Lim > SDD_GR909_DC_LIMIT_MAX ||
+ pGR909Conf->FEMF_W2W_DC_Lim > SDD_GR909_DC_LIMIT_MAX ||
+ pGR909Conf->RFT_Res_Lim > SDD_GR909_RFT_RIT_MAX ||
+ pGR909Conf->ROH_Lin_Lim > SDD_GR909_ROH_LIN_MAX ||
+ pGR909Conf->RIT_Low_Lim > SDD_GR909_RFT_RIT_MAX ||
+ pGR909Conf->RIT_High_Lim > SDD_GR909_RFT_RIT_MAX)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ /* Settle Time after Discharge, [ms] */
+ /* SettleTime = Time[ms] / 128 */
+ settle_time = DXS_Misc_RoundDiv(pGR909Conf->settle_time, 128);
+ /* HPT Wire to GND AC Limit, [mVrms] */
+ /* HptW2gAcLim = V lim [V rms ] * 141.4 */
+ HPT_W2G_AC_Lim = DXS_Misc_RoundDiv(pGR909Conf->HPT_W2G_AC_Lim * 1414, 10000);
+ /* HPT Wire to Wire AC Limit, [mVrms] */
+ /* HptW2wAcLim = V lim [V rms ] * 141.4 */
+ HPT_W2W_AC_Lim = DXS_Misc_RoundDiv(pGR909Conf->HPT_W2W_AC_Lim * 1414, 10000);
+ /* HPT Wire to GND DC Limit, [mV] */
+ /* HptW2gDcLim = V lim [V] * 100 */
+ HPT_W2G_DC_Lim = DXS_Misc_RoundDiv(pGR909Conf->HPT_W2G_DC_Lim, 10);
+ /* HPT Wire to Wire DC Limit, [mV] */
+ /* HptW2wDcLim = V lim [V] * 100 */
+ HPT_W2W_DC_Lim = DXS_Misc_RoundDiv(pGR909Conf->HPT_W2W_DC_Lim, 10);
+ /* FEMF Wire to GND AC Limit, [mVrms] */
+ /* FemfW2gAcLim = V lim [V rms ] * 141.4 */
+ FEMF_W2G_AC_Lim = DXS_Misc_RoundDiv(
+ pGR909Conf->FEMF_W2G_AC_Lim * 1414, 10000);
+ /* FEMF Wire to Wire AC Limit, [mVrms] */
+ /* FemfW2wAcLim = V lim [V rms ] * 141.4 */
+ FEMF_W2W_AC_Lim = DXS_Misc_RoundDiv(
+ pGR909Conf->FEMF_W2W_AC_Lim * 1414, 10000);
+ /* FEMF Wire to GND DC Limit, [mV] */
+ /* FemfW2gDcLim = V lim [V] * 100 */
+ FEMF_W2G_DC_Lim = DXS_Misc_RoundDiv(pGR909Conf->FEMF_W2G_DC_Lim, 10);
+ /* FEMF Wire to Wire DC Limit, [mV] */
+ /* FemfW2wDcLim = V lim [V] * 100 */
+ FEMF_W2W_DC_Lim = DXS_Misc_RoundDiv(pGR909Conf->FEMF_W2W_DC_Lim, 10);
+ /* RFT Resistance Limit, [Ohm] */
+ /* RftResLim = R lim [Ohm] / 16 */
+ RFT_Res_Lim = DXS_Misc_RoundDiv(pGR909Conf->RFT_Res_Lim, 16);
+ /* ROH Linearity Limit, [%] */
+ /* RohLinLim = Limit[%] */
+ ROH_Lin_Lim = pGR909Conf->ROH_Lin_Lim;
+ /* RIT Lower Limit, [Ohm] */
+ /* RitLowLim = Z lim [Ohm] / 16 */
+ RIT_Low_Lim = DXS_Misc_RoundDiv(pGR909Conf->RIT_Low_Lim, 16);
+ /* RIT Higher Limit, [Ohm] */
+ /* RitHighLim = Z lim [Ohm] / 16 */
+ RIT_High_Lim = DXS_Misc_RoundDiv(pGR909Conf->RIT_High_Lim, 16);
+
+ if (settle_time != p->gr909cfg.SettleTime ||
+ HPT_W2G_AC_Lim != p->gr909cfg.HptW2gAcLim ||
+ HPT_W2W_AC_Lim != p->gr909cfg.HptW2wAcLim ||
+ HPT_W2G_DC_Lim != p->gr909cfg.HptW2gDcLim ||
+ HPT_W2W_DC_Lim != p->gr909cfg.HptW2wDcLim ||
+ FEMF_W2G_AC_Lim != p->gr909cfg.FemfW2gAcLim ||
+ FEMF_W2W_AC_Lim != p->gr909cfg.FemfW2wAcLim ||
+ FEMF_W2G_DC_Lim != p->gr909cfg.FemfW2gDcLim ||
+ FEMF_W2W_DC_Lim != p->gr909cfg.FemfW2wDcLim ||
+ RFT_Res_Lim != p->gr909cfg.RftResLim ||
+ ROH_Lin_Lim != p->gr909cfg.RohLinLim ||
+ RIT_Low_Lim != p->gr909cfg.RitLowLim ||
+ RIT_High_Lim != p->gr909cfg.RitHighLim)
+ {
+ /* write new values */
+ p->gr909cfg.SettleTime = settle_time;
+ p->gr909cfg.HptW2gAcLim = HPT_W2G_AC_Lim;
+ p->gr909cfg.HptW2wAcLim = HPT_W2W_AC_Lim;
+ p->gr909cfg.HptW2gDcLim = HPT_W2G_DC_Lim;
+ p->gr909cfg.HptW2wDcLim = HPT_W2W_DC_Lim;
+ p->gr909cfg.FemfW2gAcLim = FEMF_W2G_AC_Lim;
+ p->gr909cfg.FemfW2wAcLim = FEMF_W2W_AC_Lim;
+ p->gr909cfg.FemfW2gDcLim = FEMF_W2G_DC_Lim;
+ p->gr909cfg.FemfW2wDcLim = FEMF_W2W_DC_Lim;
+ p->gr909cfg.RftResLim = RFT_Res_Lim;
+ p->gr909cfg.RohLinLim = ROH_Lin_Lim;
+ p->gr909cfg.RitLowLim = RIT_Low_Lim;
+ p->gr909cfg.RitHighLim = RIT_High_Lim;
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->gr909cfg);
+ if (err)
+ DXS_RETURN(err);
+ }
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function to get GR-909 limits
+
+ \param pCh - pointer to DXS channel structure
+ \param pGR909Conf - pointer to SDD GR909 configuration structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_GR909LimitsGet(DXS_CHANNEL_t *pCh,
+ DXS_GR909Config_t *pGR909Conf)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk;
+ POINTER_ASSERT(pCh);
+ POINTER_ASSERT(pGR909Conf);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* read configuration from the device */
+ err = DXS_CmdRead(pCh->pParent, (uint32_t *)&p->gr909cfg,
+ (uint32_t *)&p->gr909cfg);
+ if (err)
+ DXS_RETURN(err);
+
+ /* Calculate the parameters */
+
+ /* Settle Time after Discharge, [ms] */
+ /* SettleTime = Time[ms] / 128 */
+ pGR909Conf->settle_time = p->gr909cfg.SettleTime * 128;
+ /* HPT Wire to GND AC Limit, [mVrms] */
+ /* HptW2gAcLim = V lim [V rms ] * 141.4 */
+ pGR909Conf->HPT_W2G_AC_Lim =
+ DXS_Misc_RoundDiv(p->gr909cfg.HptW2gAcLim * 10000, 1414);
+ /* HPT Wire to Wire AC Limit, [mVrms] */
+ /* HptW2wAcLim = V lim [V rms ] * 141.4 */
+ pGR909Conf->HPT_W2W_AC_Lim =
+ DXS_Misc_RoundDiv(p->gr909cfg.HptW2wAcLim * 10000, 1414);
+ /* HPT Wire to GND DC Limit, [mV] */
+ /* HptW2gDcLim = V lim [V] * 100 */
+ pGR909Conf->HPT_W2G_DC_Lim = p->gr909cfg.HptW2gDcLim * 10;
+ /* HPT Wire to Wire DC Limit, [mV] */
+ /* HptW2wDcLim = V lim [V] * 100 */
+ pGR909Conf->HPT_W2W_DC_Lim = p->gr909cfg.HptW2wDcLim * 10;
+ /* FEMF Wire to GND AC Limit, [mVrms] */
+ /* FemfW2gAcLim = V lim [V rms ] * 141.4 */
+ pGR909Conf->FEMF_W2G_AC_Lim =
+ DXS_Misc_RoundDiv(p->gr909cfg.FemfW2gAcLim * 10000, 1414);
+ /* FEMF Wire to Wire AC Limit, [mVrms] */
+ /* FemfW2wAcLim = V lim [V rms ] * 141.4 */
+ pGR909Conf->FEMF_W2W_AC_Lim =
+ DXS_Misc_RoundDiv(p->gr909cfg.FemfW2wAcLim * 10000, 1414);
+ /* FEMF Wire to GND DC Limit, [mV] */
+ /* FemfW2gDcLim = V lim [V] * 100 */
+ pGR909Conf->FEMF_W2G_DC_Lim = p->gr909cfg.FemfW2gDcLim * 10;
+ /* FEMF Wire to Wire DC Limit, [mV] */
+ /* FemfW2wDcLim = V lim [V] * 100 */
+ pGR909Conf->FEMF_W2W_DC_Lim = p->gr909cfg.FemfW2wDcLim * 10;
+ /* RFT Resistance Limit, [Ohm] */
+ /* RftResLim = R lim [Ohm] / 16 */
+ pGR909Conf->RFT_Res_Lim = p->gr909cfg.RftResLim * 16;
+ /* ROH Linearity Limit, [%] */
+ /* RohLinLim = Limit[%] */
+ pGR909Conf->ROH_Lin_Lim = p->gr909cfg.RohLinLim;
+ /* RIT Lower Limit, [Ohm] */
+ /* RitLowLim = Z lim [Ohm] / 16 */
+ pGR909Conf->RIT_Low_Lim = p->gr909cfg.RitLowLim * 16;
+ /* RIT Higher Limit, [Ohm] */
+ /* RitHighLim = Z lim [Ohm] / 16 */
+ pGR909Conf->RIT_High_Lim = p->gr909cfg.RitHighLim * 16;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function to get GR-909 result
+
+ \param pCh - pointer to DXS channel structure
+ \param pGR909Result - pointer to SDD GR909 result structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_GR909ResultGet(DXS_CHANNEL_t *pCh,
+ DXS_GR909Result_t *pGR909Result)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk;
+
+ POINTER_ASSERT(pCh);
+ POINTER_ASSERT(pGR909Result);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* read results from the device */
+ err = DXS_CmdRead(pCh->pParent, (uint32_t *)&p->gr909res,
+ (uint32_t *)&p->gr909res);
+ if (err)
+ DXS_RETURN(err);
+
+ /* Calculate the parameters */
+ /* The results of the last RIT test are valid. */
+ pGR909Result->HPT_Valid = p->gr909res.HptValid;
+ pGR909Result->FEMF_Valid = p->gr909res.FemfValid;
+ pGR909Result->RFT_Valid = p->gr909res.RftValid;
+ pGR909Result->ROH_Valid = p->gr909res.RohValid;
+ pGR909Result->RIT_Valid = p->gr909res.RitValid;
+ /* The HPT test passed within the limits. */
+ pGR909Result->HPT_Pass = p->gr909res.HptPass;
+ pGR909Result->FEMF_Pass = p->gr909res.FemfPass;
+ pGR909Result->RFT_Pass = p->gr909res.RftPass;
+ pGR909Result->ROH_Pass = p->gr909res.RohPass;
+ pGR909Result->RIT_Pass = p->gr909res.RitPass;
+
+ if ((pGR909Result->HPT_Valid) || (pGR909Result->FEMF_Valid))
+ {
+ /* Convert to milivolts all the values below */
+ /* Test Result HPT or FEMF AC Ring to GND */
+ /* V [Vrms] = HptAcR2g * 0.00707 */
+ pGR909Result->HPT_AC_R2G =
+ DXS_Misc_RoundDiv(p->gr909res.HptAcR2g * 707, 100);
+ /* Test Result HPT or FEMF AC Tip to GND */
+ /* V [Vrms] = HptAcT2g * 0.00707 */
+ pGR909Result->HPT_AC_T2G =
+ DXS_Misc_RoundDiv(p->gr909res.HptAcT2g * 707, 100);
+ /* Test Result HPT or FEMF AC Tip to Ring */
+ /* V [Vrms] = HptAcT2r * 0.00707 */
+ pGR909Result->HPT_AC_T2R =
+ DXS_Misc_RoundDiv(p->gr909res.HptAcT2r * 707, 100);
+ /* Test Result HPT or FEMF DC Ring to GND */
+ /* V [V] = HptDcR2g * 0.01 */
+ pGR909Result->HPT_DC_R2G = p->gr909res.HptDcR2g * 10;
+ /* Test Result HPT or FEMF DC Tip to GND */
+ /* V [V] = HptDcT2g * 0.01 */
+ pGR909Result->HPT_DC_T2G = p->gr909res.HptDcT2g * 10;
+ /* Test Result HPT or FEMF DC Tip to Ring */
+ /* V [V] = HptDcT2r * 0.01 */
+ pGR909Result->HPT_DC_T2R = p->gr909res.HptDcT2r * 10;
+ }
+ if (pGR909Result->RFT_Valid)
+ {
+ /* Resistive Fault Ring to Ground Result */
+ /* The returned value is represented by a 12-bit mantissa and a 4-
+ bit shift factor (MMMM MMMM MMMM SSSS).
+ R [Ohm] = floor(RftR2g/16)*2^(RftR2g&0xF) */
+ pGR909Result->RFT_R2G = (p->gr909res.RftR2g >> 4) *
+ (1 << (0xF & p->gr909res.RftR2g));
+ /* Saturate to 3 MOhm */
+ pGR909Result->RFT_R2G = pGR909Result->RFT_R2G > 3000000 ?
+ 3000000 : pGR909Result->RFT_R2G;
+ /* Resistive Fault Tip to Ground Result */
+ /* The returned value is represented by a 12-bit mantissa and a 4-
+ bit shift factor (MMMM MMMM MMMM SSSS).
+ R [Ohm] = floor(RftT2g/16)*2^(RftT2g&0xF) */
+ pGR909Result->RFT_T2G = (p->gr909res.RftT2g >> 4) *
+ (1 << (0xF & p->gr909res.RftT2g));
+ /* Saturate to 3 MOhm */
+ pGR909Result->RFT_T2G = pGR909Result->RFT_T2G > 3000000 ?
+ 3000000 : pGR909Result->RFT_T2G;
+ /* Resistive Fault Tip to Ring Result */
+ /* The returned value is represented by a 12-bit mantissa and a 4-
+ bit shift factor (MMMM MMMM MMMM SSSS).
+ R [Ohm] = integer(RftT2r/16)*2^(RftT2r&0xF) */
+ pGR909Result->RFT_T2R = (p->gr909res.RftT2r >> 4) *
+ (1 << (0xF & p->gr909res.RftT2r));
+ /* Saturate to 3 MOhm */
+ pGR909Result->RFT_T2R = pGR909Result->RFT_T2R > 3000000 ?
+ 3000000 : pGR909Result->RFT_T2R;
+ }
+ if (pGR909Result->ROH_Valid)
+ {
+ /* Test Result ROH Low */
+ /* R [Ohm] = RohLow * 16 */
+ pGR909Result->ROH_Low = p->gr909res.RohLow * 16;
+ /* Test Result ROH High */
+ /* R [Ohm] = RohHigh * 16 */
+ pGR909Result->ROH_High = p->gr909res.RohHigh * 16;
+ }
+ if (pGR909Result->RIT_Valid)
+ {
+ /* Test Result RIT */
+ /* Z [Ohm] = RitRes * 16 */
+ pGR909Result->RIT_Res = p->gr909res.RitRes * 16;
+ }
+
+ DXS_RETURN(err);
+}
+#endif /* DXS_FEAT_GR909 */
+
+
+int32_t DXS_SDD_CalibrationNeededSet(DXS_CHANNEL_t *pCh, uint8_t value)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ p->bCalibrationNeeded = value;
+
+ return DXS_statusOk;
+}
+
+int32_t DXS_SDD_CalibrationNeededGet(DXS_CHANNEL_t *pCh, uint8_t* value)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ *value = p->bCalibrationNeeded;
+
+ return DXS_statusOk;
+}
+
+int32_t DXS_SDD_CalibrationInternalSet(DXS_CHANNEL_t *pCh, uint8_t value)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ p->bCalibrationInternal = value;
+
+ return DXS_statusOk;
+}
+
+int32_t DXS_SDD_CalibrationInternalGet(DXS_CHANNEL_t *pCh, uint8_t* value)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ *value = p->bCalibrationInternal;
+
+ return DXS_statusOk;
+}
+
+
+int32_t DXS_SDD_CalibrationRunningSet(DXS_CHANNEL_t *pCh, uint8_t value)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ p->bCalibrationRunning = value;
+
+ return DXS_statusOk;
+}
+
+
+int32_t DXS_SDD_CalibrationRunningGet(DXS_CHANNEL_t *pCh, uint8_t* value)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ if (p == NULL || !(p->flag & SDD_CH_INITIALIZED))
+ return DXS_statusInvalidParam;
+ *value = p->bCalibrationRunning;
+
+ return DXS_statusOk;
+}
+
+#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
+/**
+ Function to wait for the opmode to be DISABLED (2 seconds).
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - DXS_status_t
+*/
+static int32_t dxs_sdd_olc_wait_opmode_disabled(DXS_CHANNEL_t *pCh)
+{
+ int32_t err;
+ struct timespec ts = {0, 100000000};
+ uint32_t i;
+ DXS_LINE_MODE_t iMode;
+
+ POINTER_ASSERT(pCh);
+
+ for (i = 0; i < 20; i++)
+ {
+ err = DXS_SDD_LineModeGet(pCh, (int*) &iMode);
+ if (!err)
+ {
+ if (iMode == DXS_LINE_FEED_DISABLED)
+ {
+ DXS_RETURN(DXS_statusOk);
+ }
+ }
+ else
+ {
+ DXS_RETURN(err);
+ }
+ nanosleep(&ts, NULL);
+ }
+
+ DXS_RETURN(DXS_statusOLCalibrationWaitError);
+}
+
+/**
+ Function to run open loop calibration
+
+ \param pCh - pointer to DXS channel structure
+ \param unLoops - number of loops
+ \param pOLCalibrationResult - pointer to Open Loop Calibration structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_OLCalibration(DXS_CHANNEL_t *pCh, uint8_t unLoops,
+ DXS_OLCalibration_t *pOLCalibrationResult)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk;
+ DXS_Capacitance_t xCapMeasurementResult;
+ uint32_t i, uiR2Gtmp, uiT2Gtmp, uiT2Rtmp, uiValTmp, uiValidLoops;
+ struct timespec ts = {0};
+
+ POINTER_ASSERT(pCh);
+ POINTER_ASSERT(pOLCalibrationResult);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* Return if OL calibration is already running */
+ if (p->bOLCalibrationRunning)
+ DXS_RETURN(DXS_statusOLCalibrationInProgress);
+
+ /* Set flag that OL calibration process is started */
+ p->bOLCalibrationRunning = 1;
+
+ /* Set conductance parameters to 0 */
+ p->ol_calibration.GRG = 0;
+ p->ol_calibration.GTG = 0;
+ p->ol_calibration.GTR = 0;
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->ol_calibration);
+ if (err)
+ {
+ p->bOLCalibrationRunning = 0;
+ DXS_RETURN(err);
+ }
+
+ /* Run GR-909 for N times */
+ uiValidLoops = 0;
+ uiR2Gtmp = uiT2Gtmp = uiT2Rtmp = 0;
+ for (i = 0; i < unLoops; i++)
+ {
+ /* Start GR-909 */
+ err = DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_GR909);
+ if (!err)
+ {
+ /* Block untill results are received */
+ clock_gettime (CLOCK_REALTIME, &ts);
+ ts.tv_sec += 5;
+ if (sem_timedwait(&p->ol_calibration_wait_sem, &ts))
+ {
+ /* If timeout occured - stop calibration immediately */
+ p->bOLCalibrationRunning = 0;
+ DXS_RETURN(DXS_statusOLCalibrationNoResults);
+ }
+ /* Verify that new results are received */
+ if (p->bOLCalibrationNltResultRdy)
+ {
+ /* Clear flag in any case */
+ p->bOLCalibrationNltResultRdy = 0;
+ /* Read results */
+ err = DXS_CmdRead(pCh->pParent, (uint32_t *)&p->gr909res,
+ (uint32_t *)&p->gr909res);
+ if (!err)
+ {
+ /* Verify that measurements are valid */
+ if (p->gr909res.RftValid)
+ {
+ /* GTG = 2^16 * 1158 * Gtg[S],
+ Where Gtg = 1/RftT2g. Default value is 0.
+ Note: RftT2g is the resistance value measured during open
+ loop resistance measurement (see SDD_GR909ResultsRead) */
+ uiValTmp = (p->gr909res.RftR2g >> 4) *
+ (1 << (0xF & p->gr909res.RftR2g));
+ if (uiValTmp)
+ {
+ uiValTmp = DXS_Misc_RoundDiv(75890688, uiValTmp);
+ uiR2Gtmp = uiR2Gtmp + (uiValTmp > 255 ? 255 : uiValTmp);
+ }
+ uiValTmp = (p->gr909res.RftT2g >> 4) *
+ (1 << (0xF & p->gr909res.RftT2g));
+ if (uiValTmp)
+ {
+ uiValTmp = DXS_Misc_RoundDiv(75890688, uiValTmp);
+ uiT2Gtmp = uiT2Gtmp + (uiValTmp > 255 ? 255 : uiValTmp);
+ }
+ /* GTR = 2^19 * 1158 * Gtr[S] */
+ uiValTmp = (p->gr909res.RftT2r >> 4) *
+ (1 << (0xF & p->gr909res.RftT2r));
+ if (uiValTmp)
+ {
+ uiValTmp = DXS_Misc_RoundDiv(607125504, uiValTmp);
+ uiT2Rtmp = uiT2Rtmp + (uiValTmp > 255 ? 255 : uiValTmp);
+ }
+ uiValidLoops++;
+ }
+ /* Wait for the line feed mode to be restored to DISABLED */
+ err = dxs_sdd_olc_wait_opmode_disabled(pCh);
+ }
+ }
+ else
+ err = DXS_statusOLCalibrationNoResults;
+ }
+ if (err)
+ {
+ p->bOLCalibrationRunning = 0;
+ DXS_RETURN(err);
+ }
+ }
+ /* Calculate average conductances */
+ if (!uiValidLoops)
+ {
+ p->bOLCalibrationRunning = 0;
+ DXS_RETURN(DXS_statusOLCalibrationNoResults);
+ }
+ pOLCalibrationResult->GRG = DXS_Misc_RoundDiv(uiR2Gtmp, uiValidLoops);
+ pOLCalibrationResult->GTG = DXS_Misc_RoundDiv(uiT2Gtmp, uiValidLoops);
+ pOLCalibrationResult->GTR = DXS_Misc_RoundDiv(uiT2Rtmp, uiValidLoops);
+
+ /* Run uncalibrated capacitance measurements for N times */
+ uiR2Gtmp = uiT2Gtmp = uiT2Rtmp = 0;
+ for (i = 0; i < unLoops; i++)
+ {
+ /* Start Capacitance measurements */
+ err = DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_CAP_MEAS);
+ if (!err)
+ {
+ /* Block untill results are received */
+ clock_gettime (CLOCK_REALTIME, &ts);
+ ts.tv_sec += 5;
+ if (sem_timedwait(&p->ol_calibration_wait_sem, &ts))
+ {
+ /* If timeout occured - stop calibration immediately */
+ p->bOLCalibrationRunning = 0;
+ DXS_RETURN(DXS_statusOLCalibrationNoResults);
+ }
+ /* Verify that new results are received */
+ if (p->bOLCalibrationNltResultRdy)
+ {
+ /* Clear flag in any case */
+ p->bOLCalibrationNltResultRdy = 0;
+ /* Read uncalibrated results */
+ err = DXS_SDD_CapMeasurementResultGet(pCh, 0, &xCapMeasurementResult);
+ if (!err)
+ {
+ /* Sum up the values */
+ uiR2Gtmp = uiR2Gtmp + xCapMeasurementResult.Cap_R2G;
+ uiT2Gtmp = uiT2Gtmp + xCapMeasurementResult.Cap_T2G;
+ uiT2Rtmp = uiT2Rtmp + xCapMeasurementResult.Cap_T2R;
+ /* Wait for the line feed mode to be restored to DISABLED */
+ err = dxs_sdd_olc_wait_opmode_disabled(pCh);
+ }
+ }
+ else
+ err = DXS_statusOLCalibrationNoResults;
+ }
+ if (err)
+ {
+ p->bOLCalibrationRunning = 0;
+ DXS_RETURN(err);
+ }
+ }
+ /* Calculate average capacitances */
+ pOLCalibrationResult->CRG = DXS_Misc_RoundDiv(uiR2Gtmp, unLoops);
+ pOLCalibrationResult->CTG = DXS_Misc_RoundDiv(uiT2Gtmp, unLoops);
+ pOLCalibrationResult->CTR = DXS_Misc_RoundDiv(uiT2Rtmp, unLoops);
+
+ /* Write conductance parameters to the firmware */
+ p->ol_calibration.GRG = pOLCalibrationResult->GRG;
+ p->ol_calibration.GTG = pOLCalibrationResult->GTG;
+ p->ol_calibration.GTR = pOLCalibrationResult->GTR;
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->ol_calibration);
+ if (err)
+ {
+ p->bOLCalibrationRunning = 0;
+ DXS_RETURN(err);
+ }
+
+ /* Set capacitance parameters */
+ p->ol_cap_meas_res.Cap_R2G = pOLCalibrationResult->CRG;
+ p->ol_cap_meas_res.Cap_T2G = pOLCalibrationResult->CTG;
+ p->ol_cap_meas_res.Cap_T2R = pOLCalibrationResult->CTR;
+
+ /* Clear OL calibration flag */
+ p->bOLCalibrationRunning = 0;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function to set the Open Loop Calibration configuration
+
+ \param pCh - pointer to DXS channel structure
+ \param pOLCalibration - pointer to Open Loop Calibration structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_OLCalibrationConfigSet(DXS_CHANNEL_t *pCh,
+ DXS_OLCalibration_t *pOLCalibration)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk;
+
+ POINTER_ASSERT(pCh);
+ POINTER_ASSERT(pOLCalibration);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* Return if OL calibration is running */
+ if (p->bOLCalibrationRunning)
+ DXS_RETURN(DXS_statusOLCalibrationInProgress);
+
+ /* Write conductance parameters to the firmware */
+ p->ol_calibration.GRG = pOLCalibration->GRG;
+ p->ol_calibration.GTG = pOLCalibration->GTG;
+ p->ol_calibration.GTR = pOLCalibration->GTR;
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->ol_calibration);
+ if (err)
+ DXS_RETURN(err);
+
+ /* Set capacitance parameters */
+ p->ol_cap_meas_res.Cap_R2G = pOLCalibration->CRG;
+ p->ol_cap_meas_res.Cap_T2G = pOLCalibration->CTG;
+ p->ol_cap_meas_res.Cap_T2R = pOLCalibration->CTR;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function to get the Open Loop Calibration configuration
+
+ \param pCh - pointer to DXS channel structure
+ \param pOLCalibration - pointer to Open Loop Calibration structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_OLCalibrationConfigGet(DXS_CHANNEL_t *pCh,
+ DXS_OLCalibration_t *pOLCalibration)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t err = DXS_statusOk;
+
+ POINTER_ASSERT(pCh);
+ POINTER_ASSERT(pOLCalibration);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* Read conductance parameters from the firmware */
+ err = DXS_CmdRead(pCh->pParent, (uint32_t *)&p->ol_calibration,
+ (uint32_t *)&p->ol_calibration);
+ if (err)
+ DXS_RETURN(err);
+
+ pOLCalibration->GRG = p->ol_calibration.GRG;
+ pOLCalibration->GTG = p->ol_calibration.GTG;
+ pOLCalibration->GTR = p->ol_calibration.GTR;
+ /* Get capacitance parameters */
+ pOLCalibration->CRG = p->ol_cap_meas_res.Cap_R2G;
+ pOLCalibration->CTG = p->ol_cap_meas_res.Cap_T2G;
+ pOLCalibration->CTR = p->ol_cap_meas_res.Cap_T2R;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function to signal OLCalibration that Capacitance or GR-909 measurements are
+ finished.
+
+ \param pCh - pointer to DXS channel structure
+ \param bAbort - indicates that measurements were aborted
+
+ \return
+ - DXS_status_t
+*/
+int32_t obx_DXS_SDD_OLCalibrationFinished(DXS_CHANNEL_t *pCh, uint8_t bAbort)
+{
+ DXS_SDD_Ch_Resource_t *p;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ /* Indicate that results are ready and wake up ol_calibration */
+ if (p->bOLCalibrationRunning)
+ {
+ if (!bAbort)
+ p->bOLCalibrationNltResultRdy = 1;
+ sem_post(&p->ol_calibration_wait_sem);
+ }
+
+ DXS_RETURN(DXS_statusOk);
+}
+#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
+
+#ifdef DXS_FEAT_ACMETER
+/**
+ ACLM gain calculator.
+
+ \param qFactor - factor in Q4.27 format
+ \return
+ - int32_t calculated gain in 0.1[dB] units
+*/
+static int32_t dxs_aclm_gain_calc (int32_t qFactor)
+{
+ int32_t qCorrection_dB = 0, qTmp, qGain;
+
+ if (qFactor != 0)
+ {
+ /* calculate gain correction, dB */
+ while ((qTmp = DXS_Misc_Q4_27_Mul(qFactor, Q4_27_TEN)) < Q4_27_ONE)
+ {
+ qCorrection_dB += Q15_16_ONE;
+ qFactor = qTmp;
+ }
+ /* shift to Q15.16 scale */
+ qFactor >>= 11;
+ /* calculate log10 */
+ qGain = DXS_Misc_Q15_16_Log10(qFactor);
+ /* apply gain correction, dB */
+ qGain -= qCorrection_dB;
+ /* final gain, dB, in Q15.16 */
+ qGain = DXS_Misc_Q15_16_Mul(Q15_16_TEN, qGain) + Q15_16__3_14;
+ /* switch to 0.1 dB units */
+ qGain = DXS_Misc_Q15_16_Mul(qGain, Q15_16_TEN);
+ /* round up */
+ qGain += (qGain >= 0 ? Q15_16_HALF : -(Q15_16_HALF));
+ }
+ else
+ {
+ /* -87.17 dBm0 */
+ qGain = 0xFC98500C;
+ }
+
+ return (int32_t)DXS_Misc_Q15_16_to_Float(qGain);
+}
+
+/**
+ ACLM core function. Called for all measurement types.
+
+ \param pCh - pointer to DXS channel structure
+ \param inb - ACLM measurement inband result
+ \param outb - ACLM measurement outband result
+
+ \return
+ - DXS_status_t
+*/
+static int32_t dxs_aclm (DXS_CHANNEL_t *pCh, int32_t *inb, int32_t *outb)
+{
+ /* no parameter sanity check - already done in a calling function */
+ DXS_SDD_Ch_Resource_t *p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ DXS_FW_SDD_AcLevelMeterControl_t *pAcLmCtrl = &p->aclm_ctrl;
+ int32_t err;
+ DXS_FW_SDD_AcLevelMeterResult_t *pAclmRes = &p->aclm_result;
+ struct timespec ts = {0};
+
+ /* enable AC measurement */
+ pAcLmCtrl->EN = 1;
+ err = CmdWrite(pCh->pParent, (uint32_t *)pAcLmCtrl);
+ if (err)
+ DXS_RETURN(err);
+
+ clock_gettime (CLOCK_REALTIME, &ts);
+ ts.tv_sec += 3;
+ err = sem_timedwait(&p->aclm_sig_sem, &ts);
+ if (!err)
+ {
+ /* read the measurement result */
+ err = DXS_CmdRead(pCh->pParent,
+ (uint32_t *)pAclmRes, (uint32_t *)pAclmRes);
+
+ if (!err)
+ {
+ DXS_FW_SDD_AcLevelMeterConfig_t *pAclmConf = &p->aclm_config;
+ int32_t shift, qPeakLevel;
+ float fInput;
+
+ /* inband calculation */
+ shift = 21 - pAclmRes->AcInbSh;
+ if (shift >= 0)
+ {
+ /* input value */
+ fInput =
+ (float)pAclmRes->AcInb/(1 << shift)/(pAclmConf->Int << 3);
+ /* peak level in Q4.27 */
+ qPeakLevel = DXS_Misc_Float_to_Q4_27(fInput);
+ /* calculate resulting gain from factor */
+ *inb = dxs_aclm_gain_calc(qPeakLevel);
+ }
+ else
+ {
+ DXS_RETURN(DXS_statusAclmInbCalcError);
+ }
+
+ /* outband calculation */
+ shift = 21 - pAclmRes->AcOutbSh;
+ if (shift >= 0)
+ {
+ /* input value */
+ fInput =
+ (float)pAclmRes->AcOutb/(1 << shift)/(pAclmConf->Int << 3);
+ /* peak level in Q4.27 */
+ qPeakLevel = DXS_Misc_Float_to_Q4_27(fInput);
+ /* calculate resulting gain from factor */
+ *outb = dxs_aclm_gain_calc(qPeakLevel);
+ }
+ else
+ {
+ DXS_RETURN(DXS_statusAclmOutbCalcError);
+ }
+ }
+ }
+ DXS_RETURN(err);
+}
+
+/**
+ ACLM function for Frequency Response and Transhybrid measurements.
+
+ \param pCh - pointer to DXS channel structure
+ \param type - ACLM measurement code
+
+ \return
+ - DXS_status_t
+*/
+static int32_t dxs_aclm_fr_th(DXS_CHANNEL_t *pCh, DXS_ACLM_Measurement_t type)
+{
+ DXS_SDD_Ch_Resource_t *pRes = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ DXS_FW_SDD_AcLevelMeterConfig_t *pAcLmCfg;
+ int32_t err, inband, outband, ref_level=0;
+ uint16_t freq;
+ int16_t level;
+ uint8_t mpoint=0, measurements;
+
+ if (!(pRes->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ if (pRes->aclm_meas_status == dxs_aclm_in_progress)
+ /* measurement is already running */
+ DXS_RETURN(DXS_statusAclmInProgress);
+
+ /* ACLM start is possible either from DISABLED or ACTIVE opmode */
+ if (pRes->curr_opmode != DXS_LINE_FEED_DISABLED &&
+ pRes->curr_opmode != DXS_LINE_FEED_ACTIVE)
+ DXS_RETURN(DXS_statusAclmStartErrInvOpmode);
+
+ if (pRes->curr_opmode == DXS_LINE_FEED_DISABLED)
+ {
+ DXS_LINE_MODE_t opmode;
+
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE);
+ /* continue only if line mode has really switched to ACTIVE */
+ if (DXS_statusOk == DXS_SDD_LineModeGet(pCh, (int *)&opmode) &&
+ opmode == DXS_LINE_FEED_ACTIVE)
+ {
+ struct timespec ts = {0, 150000000L};
+
+ /* delay 150 ms */
+ nanosleep(&ts, NULL);
+ pRes->bAclmRestoreDisabled = 1;
+ }
+ else
+ {
+ DXS_RETURN(DXS_statusAclmStartErrActOpmodeTmout);
+ }
+ }
+ else
+ {
+ pRes->bAclmRestoreDisabled = 0;
+ }
+
+ pRes->aclm_current_meas = type;
+ pRes->aclm_meas_status = dxs_aclm_in_progress;
+
+ /* configure the AC measurement */
+ pAcLmCfg = &pRes->aclm_config;
+ pAcLmCfg->Int = DXS_ACLM_INT_TIME_MS_DEFAULT;
+ pAcLmCfg->Del = DXS_ACLM_AC_DELAY_MS_DEFAULT;
+ pAcLmCfg->BP = 0;
+ if (type == DXS_ACLM_FR)
+ {
+ measurements = DXS_ACLM_FR_MEASUREMENTS;
+ freq = DXS_ACLM_FR_FREQ_CENTER_HZ;
+ level = -100; /* -10.0 dBm0 */
+ pAcLmCfg->TH = 0;
+ }
+ else
+ {
+ measurements = DXS_ACLM_TH_MEASUREMENTS;
+ freq = DXS_ACLM_FR_TH_FREQ_MIN_HZ;
+ level = 0; /* 0.0 dBm0 */
+ pAcLmCfg->TH = 1;
+ }
+ err = CmdWrite(pCh->pParent, (uint32_t *)pAcLmCfg);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+
+ /* configure TG */
+ err = dxs_tone_config(pCh, -869, level, 0, freq, 0, 0);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+
+ /* enable the TG */
+ err = dxs_tone_start(pCh);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+
+#if 0
+ /* for Frequency Response measurement -
+ get the reference level from inband */
+ if (type == DXS_ACLM_FR)
+ {
+ err = dxs_aclm (pCh, &ref_level, &outband);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ dxs_tone_stop(pCh);
+ DXS_RETURN(err);
+ }
+ }
+#endif
+
+ for (freq = DXS_ACLM_FR_TH_FREQ_MIN_HZ; mpoint < measurements;
+ mpoint++, freq += DXS_ACLM_FR_TH_FREQ_STEP_HZ)
+ {
+ /* configure TG */
+ err = dxs_tone_config(pCh, -869, level, 0, freq, 0, 0);
+ if (err)
+ break;
+
+ /* run the measurement */
+ err = dxs_aclm (pCh, &inband, &outband);
+ if (err == DXS_statusOk)
+ {
+#if 0
+ /* for Frequency Response measurement -
+ subtract the reference level */
+ if (type == DXS_ACLM_FR)
+ {
+ inband -= ref_level;
+ outband -= ref_level;
+ }
+#else
+ if (type == DXS_ACLM_FR && freq == 1000)
+ {
+ ref_level = inband;
+ }
+#endif /*0*/
+
+ /* store the result in a resource context */
+ pRes->aclm_result_tbl_idx = mpoint;
+ pRes->aclm_results[mpoint].arg = freq;
+ pRes->aclm_results[mpoint].value = inband;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (type == DXS_ACLM_FR && err == DXS_statusOk)
+ {
+ /* for Frequency Response measurement -
+ subtract the reference level @1000Hz */
+ for (mpoint = 0; mpoint < measurements; mpoint++)
+ {
+ pRes->aclm_results[mpoint].value -= ref_level;
+ }
+ }
+
+ /* stop TG */
+ dxs_tone_stop(pCh);
+
+ if (pRes->bAclmRestoreDisabled)
+ {
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
+ }
+
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ }
+ else
+ {
+ pRes->aclm_meas_status = dxs_aclm_finished;
+ }
+
+ DXS_RETURN(err);
+}
+
+/**
+ ACLM function for Gain Tracking measurement.
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - DXS_status_t
+*/
+static int32_t dxs_aclm_gt (DXS_CHANNEL_t *pCh)
+{
+ DXS_SDD_Ch_Resource_t *pRes = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ DXS_FW_SDD_AcLevelMeterConfig_t *pAcLmCfg;
+ int32_t err, ref_level, inband, outband, level;
+ uint8_t mpoint=0;
+
+ if (!(pRes->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ if (pRes->aclm_meas_status == dxs_aclm_in_progress)
+ /* measurement is already running */
+ DXS_RETURN(DXS_statusAclmInProgress);
+
+ /* ACLM start is possible either from DISABLED or ACTIVE opmode */
+ if (pRes->curr_opmode != DXS_LINE_FEED_DISABLED &&
+ pRes->curr_opmode != DXS_LINE_FEED_ACTIVE)
+ DXS_RETURN(DXS_statusAclmStartErrInvOpmode);
+
+ if (pRes->curr_opmode == DXS_LINE_FEED_DISABLED)
+ {
+ DXS_LINE_MODE_t opmode;
+
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE);
+ /* continue only if line mode has really switched to ACTIVE */
+ if (DXS_statusOk == DXS_SDD_LineModeGet(pCh, (int *)&opmode) &&
+ opmode == DXS_LINE_FEED_ACTIVE)
+ {
+ struct timespec ts = {0, 150000000L};
+
+ /* delay 150 ms */
+ nanosleep(&ts, NULL);
+ pRes->bAclmRestoreDisabled = 1;
+ }
+ else
+ {
+ DXS_RETURN(DXS_statusAclmStartErrActOpmodeTmout);
+ }
+ }
+ else
+ {
+ pRes->bAclmRestoreDisabled = 0;
+ }
+
+ pRes->aclm_current_meas = DXS_ACLM_GT;
+ pRes->aclm_meas_status = dxs_aclm_in_progress;
+
+ /* configure the AC measurement */
+ pAcLmCfg = &pRes->aclm_config;
+ pAcLmCfg->Int = DXS_ACLM_INT_TIME_MS_DEFAULT;
+ pAcLmCfg->Del = DXS_ACLM_AC_DELAY_MS_DEFAULT;
+ pAcLmCfg->BP = 0;
+ pAcLmCfg->TH = 0;
+ err = CmdWrite(pCh->pParent, (uint32_t *)pAcLmCfg);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+ /* configure TG */
+ err = dxs_tone_config(pCh, -869, -100, 0, DXS_ACLM_FR_FREQ_CENTER_HZ, 0, 0);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+ /* enable the TG */
+ err = dxs_tone_start(pCh);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+ /* measure reference tone from inband */
+ err = dxs_aclm (pCh, &ref_level, &outband);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ dxs_tone_stop(pCh);
+ DXS_RETURN(err);
+ }
+
+ ref_level += 100;
+
+ for (level = DXS_ACLM_GT_LEVEL_MIN_DBM0; mpoint < DXS_ACLM_GT_MEASUREMENTS;
+ mpoint++, level += DXS_ACLM_GT_SNR_LEVEL_STEP_DBM0)
+ {
+ err = dxs_tone_config(pCh, -869, (level*10), 0, DXS_ACLM_FR_FREQ_CENTER_HZ, 0, 0);
+ if (err)
+ break;
+
+ /* run the measurement */
+ err = dxs_aclm (pCh, &inband, &outband);
+ if (err == DXS_statusOk)
+ {
+ /* Should the tone level be read back here to avoid rounding effects?
+ Currently no action is taken. */
+
+ inband = inband - 10*level - ref_level;
+
+ /* store the result in a resource context */
+ pRes->aclm_result_tbl_idx = mpoint;
+ pRes->aclm_results[mpoint].arg = level*10;
+ pRes->aclm_results[mpoint].value = inband;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ /* stop TG */
+ dxs_tone_stop(pCh);
+
+ if (pRes->bAclmRestoreDisabled)
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
+
+ if (err)
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ else
+ pRes->aclm_meas_status = dxs_aclm_finished;
+
+ DXS_RETURN(err);
+}
+
+/**
+ ACLM function for Signal to Noise Ratio measurement.
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - DXS_status_t
+*/
+static int32_t dxs_aclm_snr (DXS_CHANNEL_t *pCh)
+{
+ DXS_SDD_Ch_Resource_t *pRes = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+ DXS_FW_SDD_AcLevelMeterConfig_t *pAcLmCfg;
+ int32_t err, inband, outband, level;
+ uint8_t mpoint=0;
+ int16_t rxGain, txGain, txGainOriginal;
+
+ if (!(pRes->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ if (pRes->aclm_meas_status == dxs_aclm_in_progress)
+ /* measurement is already running */
+ DXS_RETURN(DXS_statusAclmInProgress);
+
+ /* ACLM start is possible either from DISABLED or ACTIVE opmode */
+ if (pRes->curr_opmode != DXS_LINE_FEED_DISABLED &&
+ pRes->curr_opmode != DXS_LINE_FEED_ACTIVE)
+ DXS_RETURN(DXS_statusAclmStartErrInvOpmode);
+
+ if (pRes->curr_opmode == DXS_LINE_FEED_DISABLED)
+ {
+ DXS_LINE_MODE_t opmode;
+
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE);
+ /* continue only if line mode has really switched to ACTIVE */
+ if (DXS_statusOk == DXS_SDD_LineModeGet(pCh, (int *)&opmode) &&
+ opmode == DXS_LINE_FEED_ACTIVE)
+ {
+ struct timespec ts = {0, 150000000L};
+
+ /* delay 150 ms */
+ nanosleep(&ts, NULL);
+ pRes->bAclmRestoreDisabled = 1;
+ }
+ else
+ {
+ DXS_RETURN(DXS_statusAclmStartErrActOpmodeTmout);
+ }
+ }
+ else
+ {
+ pRes->bAclmRestoreDisabled = 0;
+ }
+
+ pRes->aclm_current_meas = DXS_ACLM_SNR;
+ pRes->aclm_meas_status = dxs_aclm_in_progress;
+
+ /* configure the AC measurement */
+ pAcLmCfg = &pRes->aclm_config;
+ pAcLmCfg->Int = DXS_ACLM_INT_TIME_MS_DEFAULT;
+ pAcLmCfg->Del = 50;
+ pAcLmCfg->BP = 1;
+ pAcLmCfg->TH = 0;
+ pAcLmCfg->BW = 864;
+ pAcLmCfg->CF = 22804;
+ err = CmdWrite(pCh->pParent, (uint32_t *)pAcLmCfg);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+
+ /* configure TxRx gain to 0 dBr */
+ err = DXS_SDD_GainGet(pCh, &txGain, &rxGain);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+ /* remember original Tx gain */
+ txGainOriginal = txGain;
+ err = DXS_SDD_GainSet(pCh, 0, rxGain);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+
+ /* configure TG */
+ err = dxs_tone_config(pCh, -869, (DXS_ACLM_SNR_LEVEL_MIN_DBM0*10), 0, DXS_ACLM_FR_FREQ_CENTER_HZ, 0, 0);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+ /* enable the TG */
+ err = dxs_tone_start(pCh);
+ if (err)
+ {
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ DXS_RETURN(err);
+ }
+
+ for (level = DXS_ACLM_SNR_LEVEL_MIN_DBM0; mpoint < DXS_ACLM_SNR_MEASUREMENTS;
+ mpoint++, level += DXS_ACLM_GT_SNR_LEVEL_STEP_DBM0)
+ {
+ err = dxs_tone_config(pCh, -869, (level*10), 0, DXS_ACLM_FR_FREQ_CENTER_HZ, 0, 0);
+ if (err)
+ break;
+
+#if 0
+ if (level > -10)
+ {
+ /* set gain 10 dBr */
+ DXS_SDD_GainSet(pCh, -100, rxGain);
+ }
+#else
+ /* automatically increase the attenuation in TX
+ depending on the actual RX gain */
+ txGain = -(200 + rxGain + (level*10));
+ if (txGain > 0)
+ txGain = 0;
+
+ DXS_SDD_GainSet(pCh, txGain, rxGain);
+#endif
+
+ /* run the measurement */
+ err = dxs_aclm (pCh, &inband, &outband);
+ if (err == DXS_statusOk)
+ {
+ /* Should the tone level be read back here to avoid rounding effects?
+ Currently no action is taken. */
+
+ /* store the result in a resource context */
+ pRes->aclm_result_tbl_idx = mpoint;
+ pRes->aclm_results[mpoint].arg = level*10;
+ pRes->aclm_results[mpoint].value = inband - outband;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ /* stop TG */
+ dxs_tone_stop(pCh);
+
+ /* restore original Tx gain */
+ DXS_SDD_GainSet(pCh, txGainOriginal, rxGain);
+
+ if (pRes->bAclmRestoreDisabled)
+ DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
+
+ if (err)
+ pRes->aclm_meas_status = dxs_aclm_aborted;
+ else
+ pRes->aclm_meas_status = dxs_aclm_finished;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function to start the ACLM measurement.
+
+ \param pCh - pointer to DXS channel structure
+ \param type - ACLM measurement code
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_ACLM_Start(DXS_CHANNEL_t *pCh, DXS_ACLM_Measurement_t type)
+{
+ int32_t ret, ret1;
+ POINTER_ASSERT(pCh);
+
+ /* check if ACLM measurement feature is supported */
+ if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_aclm))
+ DXS_RETURN(DXS_statusFeatNotSupportedCaps);
+
+ /* mute PCM channel */
+ if ((ret = dxs_pcm_ch_mute(pCh, 1)) != DXS_statusOk)
+ DXS_RETURN(ret);
+
+ switch (type)
+ {
+ case DXS_ACLM_FR:
+ case DXS_ACLM_TH:
+ ret = dxs_aclm_fr_th(pCh, type);
+ break;
+ case DXS_ACLM_GT:
+ ret = dxs_aclm_gt(pCh);
+ break;
+ case DXS_ACLM_SNR:
+ ret = dxs_aclm_snr(pCh);
+ break;
+ default:
+ ret = DXS_statusParamsOutRange;
+ }
+
+ /* unmute PCM channel */
+ if ((ret1 = dxs_pcm_ch_mute(pCh, 0)) != DXS_statusOk)
+ DXS_RETURN(ret1);
+
+ /* return code
+ from the measurement */
+ DXS_RETURN(ret);
+}
+
+/**
+ Function to retrieve the ACLM measurement results.
+
+ \param pCh - pointer to DXS channel structure
+ \param type - ACLM measurement code
+ \param what - what to output: result number, argument or value
+ \param index - ACLM measurement index (point)
+ \param output - output placeholder
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SDD_ACLM_ResultGet(DXS_CHANNEL_t *pCh, DXS_ACLM_Measurement_t type,
+ uint8_t what, int32_t index, int32_t *output)
+{
+ DXS_SDD_Ch_Resource_t *p;
+ int32_t ret = DXS_statusOk;
+
+ POINTER_ASSERT(pCh);
+
+ p = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ if (!(p->flag & SDD_CH_INITIALIZED))
+ DXS_RETURN(DXS_statusNotInitResource);
+
+ if (p->aclm_current_meas == type &&
+ p->aclm_meas_status == dxs_aclm_finished)
+ {
+ switch (what)
+ {
+ case DXS_ACLM_RESULT_NUMBER:
+ *output = p->aclm_result_tbl_idx + 1;
+ break;
+ case DXS_ACLM_RESULT_ARG:
+ *output = p->aclm_results[index].arg;
+ break;
+ case DXS_ACLM_RESULT_VALUE:
+ *output = p->aclm_results[index].value;
+ break;
+ default:
+ ret = DXS_statusParamsOutRange;
+ }
+ }
+ else
+ {
+ *output = 0;
+ ret = DXS_statusAclmResultsNotAvail;
+ }
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function to unlock the waiting semaphore.
+ Called from outbox handler.
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - none
+*/
+void obx_DXS_SDD_ACLM_Finish(DXS_CHANNEL_t *pCh)
+{
+ DXS_SDD_Ch_Resource_t *pRes = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ sem_post(&pRes->aclm_sig_sem);
+}
+#endif /* DXS_FEAT_ACMETER */
+
+/**
+ Return the ringer status for a channel
+
+ \param none
+ \return
+ non-zero value if the channel is currently generating
+ ringing voltage, otherwise zero
+*/
+int32_t DXS_SDD_IsRingingUnprot (DXS_CHANNEL_t *pCh)
+{
+ int32_t err;
+ DXS_SDD_Ch_Resource_t *pRes = (DXS_SDD_Ch_Resource_t *)pCh->sdd;
+
+ /* update current opmode,
+ wait while an opmode change is ongoing */
+ err = dxs_sdd_opmode_get(pRes);
+ if (err != DXS_statusOk)
+ {
+ DXS_ERROR_PUSH(err);
+ return 0;
+ }
+
+ if (pRes->curr_opmode == DXS_LINE_FEED_RING_BURST ||
+ pRes->curr_opmode == DXS_LINE_FEED_RINGING_REVPOL)
+ return 1;
+
+ return 0;
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_sdd.h b/marvell/services/dxslic/api_lib/src/dxs_sdd.h
new file mode 100644
index 0000000..d98d765
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_sdd.h
@@ -0,0 +1,108 @@
+#ifndef __DXS_SDD_H__
+#define __DXS_SDD_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_sdd.h
+ This file contains the declaration of the functions for SDD operations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_lib.h"
+#include "dxs_fw_cmd.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_ACLM_RESULT_NUMBER 100
+#define DXS_ACLM_RESULT_ARG 101
+#define DXS_ACLM_RESULT_VALUE 102
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern void *DXS_SDD_ChInit (uint8_t dev, uint8_t ch);
+extern int32_t DXS_SDD_ChExit (DXS_CHANNEL_t *pCh);
+extern int32_t DXS_SDD_BasicConfigBBD (DXS_CHANNEL_t *pCh,
+ struct DXS_basicConfigData *pData);
+extern int32_t DXS_SDD_RingConfigBBD (DXS_CHANNEL_t *pCh,
+ struct DXS_FW_SDD_RingConfig *pRingConf);
+extern int32_t DXS_SDD_DcDcConfigBBD (DXS_CHANNEL_t *pCh,
+ struct DXS_DcDcConfigData *pData);
+extern int32_t DXS_SDD_MwlConfigBBD (DXS_CHANNEL_t *pCh,
+ struct DXS_FW_SDD_MwlConfig *pMwlConf);
+extern int32_t DXS_SDD_RingConfigAPI (DXS_CHANNEL_t *pCh,
+ uint8_t waveForm,
+ uint8_t crestFactor,
+ uint8_t frequency,
+ uint16_t amplitude,
+ uint16_t dcOffset);
+extern int32_t DXS_SDD_MwlConfigAPI(DXS_CHANNEL_t *pCh,
+ uint8_t voltage,
+ uint8_t thresh,
+ uint16_t slope,
+ uint16_t onTime,
+ uint16_t offTime);
+extern int32_t DXS_SDD_CoeffBBD(DXS_CHANNEL_t *pCh,
+ uint8_t dest,
+ uint16_t blk_offset,
+ uint8_t blk_len,
+ uint8_t *pData,
+ uint16_t padding);
+extern int32_t DXS_SDD_LineModeSet(DXS_CHANNEL_t *pCh, int mode);
+extern int32_t DXS_SDD_LineModeGet(DXS_CHANNEL_t *pCh, int *pMode);
+extern void obx_DXS_SDD_OpmodeUpdate(DXS_CHANNEL_t *pCh, DXS_LINE_MODE_t mode, uint8_t bOPC);
+
+extern int32_t DXS_SDD_GainSet(DXS_CHANNEL_t *pCh, int16_t usGain, int16_t dsGain);
+extern int32_t DXS_SDD_GainGet(DXS_CHANNEL_t *pCh, int16_t *txGain, int16_t *rxGain);
+extern int32_t DXS_SDD_Calibration(DXS_CHANNEL_t *pCh);
+extern int32_t DXS_SDD_Calibration_Finish(DXS_CHANNEL_t *pCh, DXS_Event_t *pEvent);
+extern int32_t DXS_SDD_CalibrationNeededSet(DXS_CHANNEL_t *pCh, uint8_t value);
+extern int32_t DXS_SDD_CalibrationNeededGet(DXS_CHANNEL_t *pCh, uint8_t* value);
+extern int32_t DXS_SDD_CalibrationInternalSet(DXS_CHANNEL_t *pCh, uint8_t value);
+extern int32_t DXS_SDD_CalibrationInternalGet(DXS_CHANNEL_t *pCh, uint8_t* value);
+extern int32_t DXS_SDD_CalibrationRunningSet(DXS_CHANNEL_t *pCh, uint8_t value);
+extern int32_t DXS_SDD_CalibrationRunningGet(DXS_CHANNEL_t *pCh, uint8_t* value);
+extern int32_t DXS_SDD_CalibrationGet(DXS_CHANNEL_t *pCh, DXS_Calibration_t *pCalibration);
+extern int32_t DXS_SDD_CalibrationSet(DXS_CHANNEL_t *pCh, DXS_Calibration_t *pCalibration);
+extern int32_t DXS_SDD_ContMeasurementResultGet(DXS_CHANNEL_t *pCh,
+ DXS_ContMeasurementResult_t *pContMeasurement);
+extern int32_t DXS_SDD_CapMeasurementResultGet(DXS_CHANNEL_t *pCh,
+ uint8_t bCalibrated, DXS_Capacitance_t *pCapacitance);
+extern int32_t DXS_SDD_GR909LimitsSet(DXS_CHANNEL_t *pCh,
+ DXS_GR909Config_t *pGR909Conf);
+extern int32_t DXS_SDD_GR909LimitsGet(DXS_CHANNEL_t *pCh,
+ DXS_GR909Config_t *pGR909Conf);
+extern int32_t DXS_SDD_GR909ResultGet(DXS_CHANNEL_t *pCh,
+ DXS_GR909Result_t *pGR909Result);
+extern int32_t DXS_SDD_OLCalibration(DXS_CHANNEL_t *pCh, uint8_t unLoops,
+ DXS_OLCalibration_t *pOLCalibrationResult);
+extern int32_t DXS_SDD_OLCalibrationConfigSet(DXS_CHANNEL_t *pCh,
+ DXS_OLCalibration_t *pOLCalibration);
+extern int32_t DXS_SDD_OLCalibrationConfigGet(DXS_CHANNEL_t *pCh,
+ DXS_OLCalibration_t *pOLCalibration);
+extern int32_t obx_DXS_SDD_OLCalibrationFinished(DXS_CHANNEL_t *pCh,
+ uint8_t bAbort);
+extern int32_t DXS_SDD_ACLM_Start(DXS_CHANNEL_t *pCh,
+ DXS_ACLM_Measurement_t type);
+extern int32_t DXS_SDD_ACLM_ResultGet(DXS_CHANNEL_t *pCh,
+ DXS_ACLM_Measurement_t type, uint8_t what,
+ int32_t index, int32_t *output);
+extern void obx_DXS_SDD_ACLM_Finish(DXS_CHANNEL_t *pCh);
+extern int32_t DXS_SDD_IsRingingUnprot (DXS_CHANNEL_t *pCh);
+#endif /* __DXS_SDD_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_sig.c b/marvell/services/dxslic/api_lib/src/dxs_sig.c
new file mode 100644
index 0000000..56e827f
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_sig.c
@@ -0,0 +1,1418 @@
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_sig.c
+ Implementation of signalling channel functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs.h"
+#include "dxs_config.h"
+#include "dxs_lib.h"
+#include "dxs_fw_cmd.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+#include "dxs_misc.h"
+#include "dxs_init.h"
+#include "dxs_access.h"
+#include "dxs_sdd.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+/** Maximum number of CID data bytes sent via one message */
+#define DXS_CID_GEN_DATA_MAX 27
+#define DXS_CID_V23_BEL202 0
+#define DXS_CID_V23_ITU_T 1
+#define DXS_CID_AUTODEACT_OFF 0
+#define DXS_CID_AUTODEACT_ON 1
+#define DXS_CID_HLEV_HIGH 1
+#define DXS_CID_MAX_SEIZURE 32767
+#define DXS_CID_MAX_MARK 32767
+#define DXS_CID_MAX_LEVEL 31
+#define DXS_CID_MIN_LEVEL -929
+
+/** Maximum number of tones in UTD table */
+#define UTD_COEF_TABLE_MAX 5
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+/** Data structure for DTMF receiver coefficients firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Minimum Signal Level */
+ uint32_t LEVEL : 16;
+ /** Maximal Allowed Signal Twist */
+ uint32_t TWIST : 16;
+#else
+ CMD_HEAD_LE;
+ /** Maximal Allowed Signal Twist */
+ uint32_t TWIST : 16;
+ /** Minimum Signal Level */
+ uint32_t LEVEL : 16;
+#endif
+} __attribute__ ((packed)) DXS_FW_DTMF_RecCoeff_t;
+#define DXS_FW_DTMF_RecCoeff_ECMD 12
+#define DXS_FW_DTMF_RecCoeff_LENGTH 4
+
+/** Data structure for DTMF receiver control firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Enable */
+ uint32_t EN : 1;
+ /** Reserved */
+ uint32_t Res02 : 31;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res02 : 31;
+ /** Enable */
+ uint32_t EN : 1;
+#endif
+} __attribute__ ((packed)) DXS_FW_DTMF_RecCtrl_t;
+#define DXS_FW_DTMF_RecCtrl_ECMD 4
+#define DXS_FW_DTMF_RecCtrl_LENGTH 4
+
+/** Data structure for DTMF generator coefficients firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Level for Frequency 1 (Lower Frequency) */
+ uint32_t LEVEL1 : 16;
+ /** Level for Frequency 2 (Higher Frequency) */
+ uint32_t LEVEL2 : 16;
+ /** Frequency 1 of Tone */
+ uint32_t FREQ1 : 16;
+ /** Frequency 2 of Tone */
+ uint32_t FREQ2 : 16;
+#else
+ CMD_HEAD_LE;
+ /** Level for Frequency 2 (Higher Frequency) */
+ uint32_t LEVEL2 : 16;
+ /** Level for Frequency 1 (Lower Frequency) */
+ uint32_t LEVEL1 : 16;
+ /** Frequency 2 of Tone */
+ uint32_t FREQ2 : 16;
+ /** Frequency 1 of Tone */
+ uint32_t FREQ1 : 16;
+#endif
+} __attribute__ ((packed)) DXS_FW_DTMF_AT_GenCoeff_t;
+#define DXS_FW_DTMF_AT_GenCoeff_ECMD 10
+#define DXS_FW_DTMF_AT_GenCoeff_LENGTH 8
+
+/** Data structure for DTMF generator control firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Status of DTMF/AT Generator */
+ uint32_t EN : 1;
+ /** Reserved */
+ uint32_t Res02 : 14;
+ /** Amplitude Modulation */
+ uint32_t AM : 1;
+ /** Reserved */
+ uint32_t Res03 : 16;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res03 : 16;
+ /** Amplitude Modulation */
+ uint32_t AM : 1;
+ /** Reserved */
+ uint32_t Res02 : 14;
+ /** Status of DTMF/AT Generator */
+ uint32_t EN : 1;
+#endif
+} __attribute__ ((packed)) DXS_FW_DTMF_AT_GenCtrl_t;
+#define DXS_FW_DTMF_AT_GenCtrl_ECMD 3
+#define DXS_FW_DTMF_AT_GenCtrl_LENGTH 4
+
+/** Data structure for FSK generator control firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Status of CID sender */
+ uint32_t EN : 1;
+ /** Reserved */
+ uint32_t Res02 : 1;
+ /** Auto Deactivation */
+ uint32_t AD : 1;
+ /** High Level CID Generation Mode */
+ uint32_t HLEV : 1;
+ /** CID Specification */
+ uint32_t V23 : 1;
+ /** Reserved */
+ uint32_t Res03 : 27;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res02 : 27;
+ /** CID Specification */
+ uint32_t V23 : 1;
+ /** High Level CID Generation Mode */
+ uint32_t HLEV : 1;
+ /** Auto Deactivation */
+ uint32_t AD : 1;
+ /** Reserved */
+ uint32_t Res03 : 1;
+ /** Status of CID sender */
+ uint32_t EN : 1;
+#endif
+} __attribute__ ((packed)) DXS_FW_FSK_GenCtrl_t;
+#define DXS_FW_FSK_GenCtrl_ECMD 2
+#define DXS_FW_FSK_GenCtrl_LENGTH 4
+
+/** Data structure for FSK generator coefficients firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** CID Send Level */
+ uint32_t LEVEL : 16;
+ /** Number of Seizure Bits */
+ uint32_t SEIZURE : 16;
+ /** Number of Mark Bits */
+ uint32_t MARK : 16;
+ /** Reserved */
+ uint32_t Res02 : 16;
+#else
+ CMD_HEAD_LE;
+ /** Number of Seizure Bits */
+ uint32_t SEIZURE : 16;
+ /** CID Send Level */
+ uint32_t LEVEL : 16;
+ /** Reserved */
+ uint32_t Res02 : 16;
+ /** Number of Mark Bits */
+ uint32_t MARK : 16;
+
+#endif
+} __attribute__ ((packed)) DXS_FW_FSK_GenCoeff_t;
+#define DXS_FW_FSK_GenCoeff_ECMD 8
+#define DXS_FW_FSK_GenCoeff_LENGTH 8
+
+/** Data structure for FSK generator data firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Number of Data Bytes following */
+ uint32_t NRDATA : 8;
+ /** Data Byte 0 */
+ uint32_t DATA0 : 8;
+ /** Data Byte 1 */
+ uint32_t DATA1 : 8;
+ /** Data Byte 2 */
+ uint32_t DATA2 : 8;
+#else
+ CMD_HEAD_LE;
+ /** Data Byte 2 */
+ uint32_t DATA2 : 8;
+ /** Data Byte 1 */
+ uint32_t DATA1 : 8;
+ /** Data Byte 0 */
+ uint32_t DATA0 : 8;
+ /** Number of Data Bytes following */
+ uint32_t NRDATA : 8;
+#endif
+ /** Data Bytes 3-26 */
+ uint32_t DATA[DXS_CID_GEN_DATA_MAX >> 2];
+} __attribute__ ((packed)) DXS_FW_FSK_GenData_t;
+#define DXS_FW_FSK_GenData_ECMD 9
+#define DXS_FW_FSK_GenData_LENGTH 28
+
+/** Data structure for metering pulse control firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Bit to start or stop the metering pulse */
+ uint32_t EN : 1;
+ /** Reserved */
+ uint32_t Res02 : 31;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res02 : 31;
+ /** Bit to start or stop the metering pulse */
+ uint32_t EN : 1;
+#endif
+} __attribute__ ((packed)) DXS_FW_MeterPulseCtrl_t;
+#define DXS_FW_MeterPulseCtrl_ECMD 4
+#define DXS_FW_MeterPulseCtrl_LENGTH 4
+
+/** Data structure for UTD coefficients firmware command */
+typedef struct
+{
+ struct DXS_FW_Cmd_Header hdr;
+ struct DXS_FW_SIG_UtdCoeff content;
+} __attribute__ ((packed)) DXS_FW_SIG_UtdCoeff_t;
+#define DXS_FW_SIG_UtdCoeff_ECMD 18
+#define DXS_FW_SIG_UtdCoeff_LENGTH 16
+
+/** Data structure for UTD control firmware command */
+typedef struct
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ CMD_HEAD_BE;
+ /** Bit to enable or disable universal tone detector */
+ uint32_t EN : 1;
+ /** Reserved */
+ uint32_t Res02 : 14;
+ /** With this bit the UTD direction can be configured */
+ uint32_t DIR : 1;
+ /** Reserved */
+ uint32_t Res03 : 16;
+#else
+ CMD_HEAD_LE;
+ /** Reserved */
+ uint32_t Res03 : 16;
+ /** With this bit the UTD direction can be configured */
+ uint32_t DIR : 1;
+ /** Reserved */
+ uint32_t Res02 : 14;
+ /** Bit to enable or disable universal tone detector */
+ uint32_t EN : 1;
+#endif
+} __attribute__ ((packed)) DXS_FW_SIG_UtdCtrl_t;
+#define DXS_FW_SIG_UtdCtrl_ECMD 17
+#define DXS_FW_SIG_UtdCtrl_LENGTH 4
+
+/** Data structure for signalling channel resource */
+typedef struct
+{
+ /** status flag */
+ uint32_t flag;
+#define SIG_CH_INITIALIZED 0x00000001
+
+#ifdef DXS_FEAT_DTMFD
+ /** DTMF Receiver Coefficients */
+ DXS_FW_DTMF_RecCoeff_t dtmf_rec_coef;
+ /** DTMF Receiver Control */
+ DXS_FW_DTMF_RecCtrl_t dtmf_rec_ctrl;
+#endif /* DXS_FEAT_DTMFD */
+
+#ifdef DXS_FEAT_TG
+ /** DTMF and AT Generator Coefficients */
+ DXS_FW_DTMF_AT_GenCoeff_t dtmf_at_gen_coef;
+ /** DTMF and AT Generator Control */
+ DXS_FW_DTMF_AT_GenCtrl_t dtmf_at_gen_ctrl;
+#endif /* DXS_FEAT_TG */
+
+#ifdef DXS_FEAT_FSK
+ /** Caller ID Control */
+ DXS_FW_FSK_GenCtrl_t fsk_ctrl;
+ /** Caller ID Coefficients */
+ DXS_FW_FSK_GenCoeff_t fsk_coef;
+ /** Caller ID Data */
+ DXS_FW_FSK_GenData_t fsk_data;
+#endif /* DXS_FEAT_FSK */
+
+#ifdef DXS_FEAT_METERING
+ /** Metering pulse current status */
+ uint8_t bMeterPulse;
+ /** Metering Pulse Control */
+ DXS_FW_MeterPulseCtrl_t meter_ctrl;
+#endif /* DXS_FEAT_METERING */
+
+#ifdef DXS_FEAT_UTD
+ /** UTD Control */
+ DXS_FW_SIG_UtdCtrl_t utd_ctrl;
+ /** UTD coefficients */
+ DXS_FW_SIG_UtdCoeff_t utd_coeff;
+ /** Tone index of last active UTD */
+ uint16_t utd_tone_idx;
+#endif /* DXS_FEAT_UTD */
+
+} DXS_SIG_Ch_Resource_t;
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+static DXS_SIG_Ch_Resource_t sig_chan[DXS_MAX_DEVICES * CH_PER_DEVICE] = {0};
+
+static uint16_t dBm0_level_tbl[] = {
+/* 0.0 dBm0 */ 0x592a,
+/* 0.1 dBm0 */ 0x5a32,
+/* 0.2 dBm0 */ 0x5b3e,
+/* 0.3 dBm0 */ 0x5c4c,
+/* 0.4 dBm0 */ 0x5d5e,
+/* 0.5 dBm0 */ 0x5e73,
+/* 0.6 dBm0 */ 0x5f8b,
+/* 0.7 dBm0 */ 0x60a6,
+/* 0.8 dBm0 */ 0x61c4,
+/* 0.9 dBm0 */ 0x62e6,
+/* 1.0 dBm0 */ 0x640b,
+/* 1.1 dBm0 */ 0x6534,
+/* 1.2 dBm0 */ 0x6660,
+/* 1.3 dBm0 */ 0x678f,
+/* 1.4 dBm0 */ 0x68c2,
+/* 1.5 dBm0 */ 0x69f9,
+/* 1.6 dBm0 */ 0x6b33,
+/* 1.7 dBm0 */ 0x6c71,
+/* 1.8 dBm0 */ 0x6db2,
+/* 1.9 dBm0 */ 0x6ef7,
+/* 2.0 dBm0 */ 0x7040,
+/* 2.1 dBm0 */ 0x718d,
+/* 2.2 dBm0 */ 0x72de,
+/* 2.3 dBm0 */ 0x7432,
+/* 2.4 dBm0 */ 0x758b,
+/* 2.5 dBm0 */ 0x76e7,
+/* 2.6 dBm0 */ 0x7847,
+/* 2.7 dBm0 */ 0x79ac,
+/* 2.8 dBm0 */ 0x7b15,
+/* 2.9 dBm0 */ 0x7c82,
+/* 3.0 dBm0 */ 0x7df3,
+/* 3.1 dBm0 */ 0x7f68
+};
+
+#ifdef DXS_FEAT_UTD
+static uint32_t uiUtdMtxInit = 0;
+static pthread_mutex_t utd_tone_mtx;
+static uint8_t UtdTonesNum = 0;
+static struct DXS_SIG_UtdCoefEntry
+{
+ uint16_t unToneIdx;
+ struct DXS_FW_SIG_UtdCoeff coef_data;
+} utd_coef_tbl[UTD_COEF_TABLE_MAX] = {0};
+#endif /* DXS_FEAT_UTD */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/**
+ Function dxs_sig_ch_init
+
+ \param dev - device number
+ \param ch - channel number
+ \param nBytes - size of the buffer
+
+*/
+void *dxs_sig_ch_init(uint8_t dev, uint8_t ch)
+{
+ DXS_SIG_Ch_Resource_t *p;
+
+ if (dev >= DXS_MAX_DEVICES || ch >= CH_PER_DEVICE)
+ return (void *)NULL;
+
+ p = &sig_chan[dev * CH_PER_DEVICE + ch];
+
+ p->flag = 0;
+
+#ifdef DXS_FEAT_DTMFD
+ p->dtmf_rec_coef.CMD = CMD_EOP;
+ p->dtmf_rec_coef.MOD = MOD_SIG_DET;
+ p->dtmf_rec_coef.ECMD = DXS_FW_DTMF_RecCoeff_ECMD;
+ p->dtmf_rec_coef.LENGTH = DXS_FW_DTMF_RecCoeff_LENGTH;
+ p->dtmf_rec_coef.CHAN = ch;
+
+ p->dtmf_rec_ctrl.CMD = CMD_EOP;
+ p->dtmf_rec_ctrl.MOD = MOD_SIG_DET;
+ p->dtmf_rec_ctrl.ECMD = DXS_FW_DTMF_RecCtrl_ECMD;
+ p->dtmf_rec_ctrl.LENGTH = DXS_FW_DTMF_RecCtrl_LENGTH;
+ p->dtmf_rec_ctrl.CHAN = ch;
+#endif /* DXS_FEAT_DTMFD */
+
+#ifdef DXS_FEAT_TG
+ p->dtmf_at_gen_coef.CMD = CMD_EOP;
+ p->dtmf_at_gen_coef.MOD = MOD_SIG_GEN;
+ p->dtmf_at_gen_coef.ECMD = DXS_FW_DTMF_AT_GenCoeff_ECMD;
+ p->dtmf_at_gen_coef.LENGTH = DXS_FW_DTMF_AT_GenCoeff_LENGTH;
+ p->dtmf_at_gen_coef.CHAN = ch;
+
+ p->dtmf_at_gen_ctrl.CMD = CMD_EOP;
+ p->dtmf_at_gen_ctrl.MOD = MOD_SIG_GEN;
+ p->dtmf_at_gen_ctrl.ECMD = DXS_FW_DTMF_AT_GenCtrl_ECMD;
+ p->dtmf_at_gen_ctrl.LENGTH = DXS_FW_DTMF_AT_GenCtrl_LENGTH;
+ p->dtmf_at_gen_ctrl.CHAN = ch;
+#endif /* DXS_FEAT_TG */
+
+#ifdef DXS_FEAT_FSK
+ p->fsk_ctrl.CMD = CMD_EOP;
+ p->fsk_ctrl.MOD = MOD_SIG_GEN;
+ p->fsk_ctrl.ECMD = DXS_FW_FSK_GenCtrl_ECMD;
+ p->fsk_ctrl.LENGTH = DXS_FW_FSK_GenCtrl_LENGTH;
+ p->fsk_ctrl.CHAN = ch;
+ /* Only high level is supported. */
+ p->fsk_ctrl.HLEV = DXS_CID_HLEV_HIGH;
+
+ p->fsk_coef.CMD = CMD_EOP;
+ p->fsk_coef.MOD = MOD_SIG_GEN;
+ p->fsk_coef.ECMD = DXS_FW_FSK_GenCoeff_ECMD;
+ p->fsk_coef.LENGTH = DXS_FW_FSK_GenCoeff_LENGTH;
+ p->fsk_coef.CHAN = ch;
+
+ p->fsk_data.CMD = CMD_EOP;
+ p->fsk_data.MOD = MOD_SIG_GEN;
+ p->fsk_data.ECMD = DXS_FW_FSK_GenData_ECMD;
+ p->fsk_data.LENGTH = DXS_FW_FSK_GenData_LENGTH;
+ p->fsk_data.CHAN = ch;
+#endif /* DXS_FEAT_FSK */
+
+#ifdef DXS_FEAT_METERING
+ p->bMeterPulse = 0;
+ p->meter_ctrl.CMD = CMD_EOP;
+ p->meter_ctrl.MOD = MOD_SIG_GEN;
+ p->meter_ctrl.ECMD = DXS_FW_MeterPulseCtrl_ECMD;
+ p->meter_ctrl.LENGTH = DXS_FW_MeterPulseCtrl_LENGTH;
+ p->meter_ctrl.CHAN = ch;
+#endif /* DXS_FEAT_METERING */
+
+#ifdef DXS_FEAT_UTD
+ p->utd_tone_idx = 0;
+
+ p->utd_coeff.hdr.CMD = CMD_EOP;
+ p->utd_coeff.hdr.MOD = MOD_SIG_DET;
+ p->utd_coeff.hdr.ECMD = DXS_FW_SIG_UtdCoeff_ECMD;
+ p->utd_coeff.hdr.LENGTH = DXS_FW_SIG_UtdCoeff_LENGTH;
+ p->utd_coeff.hdr.CHAN = ch;
+
+ p->utd_ctrl.CMD = CMD_EOP;
+ p->utd_ctrl.MOD = MOD_SIG_DET;
+ p->utd_ctrl.ECMD = DXS_FW_SIG_UtdCtrl_ECMD;
+ p->utd_ctrl.LENGTH = DXS_FW_SIG_UtdCtrl_LENGTH;
+ p->utd_ctrl.CHAN = ch;
+#endif /* DXS_FEAT_UTD */
+
+ p->flag |= SIG_CH_INITIALIZED;
+
+ return (void *)p;
+}
+
+#ifdef DXS_FEAT_UTD
+/**
+ Function to initialize UTD mutex
+
+*/
+void dxs_sig_utd_mtx_init()
+{
+ if (!uiUtdMtxInit)
+ pthread_mutex_init(&utd_tone_mtx, NULL);
+
+ uiUtdMtxInit++;
+}
+
+/**
+ Function to destroy UTD mutex and reset UTD tone table
+
+*/
+void dxs_sig_utd_mtx_destroy()
+{
+ int err;
+ if (uiUtdMtxInit)
+ uiUtdMtxInit--;
+
+ if (!uiUtdMtxInit)
+ {
+ err = pthread_mutex_unlock(&utd_tone_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ err = pthread_mutex_destroy(&utd_tone_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ UtdTonesNum = 0;
+ }
+}
+#endif /* DXS_FEAT_UTD */
+
+#ifdef DXS_FEAT_DTMFD
+
+/* ============================ DTMF Detection ============================== */
+
+#define DXS_SIG_DTMF_LEVEL_MIN (-369) /* in units of 0.1 dBm0 */
+#define DXS_SIG_DTMF_LEVEL_MAX (-29) /* in units of 0.1 dBm0 */
+
+#define DXS_SIG_DTMF_TWIST_MIN 10 /* in units of 0.1 dB */
+#define DXS_SIG_DTMF_TWIST_MAX 120 /* in units of 0.1 dB */
+
+/**
+ Function dxs_dtmf_config
+
+ \param pCh - pointer to DXS channel structure
+ \param level - minimum signal level
+ \param twist - maximum allowed twist
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_dtmf_config(DXS_CHANNEL_t *pCh, int16_t level, int16_t twist)
+{
+ DXS_SIG_Ch_Resource_t *p;
+ uint16_t new_LEVEL, new_TWIST;
+ int32_t ret = DXS_statusOk;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (level < DXS_SIG_DTMF_LEVEL_MIN || level > DXS_SIG_DTMF_LEVEL_MAX)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ if (twist < DXS_SIG_DTMF_TWIST_MIN || twist > DXS_SIG_DTMF_TWIST_MAX)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ /* calculate new values */
+ new_LEVEL = DXS_Misc_MulQ15(DXS_Misc_PowerdB_to_Factor(level), 14173);
+ new_TWIST = DXS_Misc_MulQ15(DXS_Misc_PowerdB_to_Factor(-twist), 29205);
+
+ if (new_LEVEL != p->dtmf_rec_coef.LEVEL ||
+ new_TWIST != p->dtmf_rec_coef.TWIST)
+ {
+ /* write new values */
+ p->dtmf_rec_coef.LEVEL = new_LEVEL;
+ p->dtmf_rec_coef.TWIST = new_TWIST;
+ ret = CmdWrite(pCh->pParent, (uint32_t *)&p->dtmf_rec_coef);
+ }
+
+ return ret;
+}
+
+/**
+ Function dxs_dtmf_enable
+
+ \param pCh - pointer to DXS channel structure
+ \param action - action enable/disable
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_dtmf_enable(DXS_CHANNEL_t *pCh, uint8_t action)
+{
+ DXS_SIG_Ch_Resource_t *p;
+ int32_t ret = DXS_statusOk;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (p->dtmf_rec_ctrl.EN != action)
+ {
+ p->dtmf_rec_ctrl.EN = action;
+ ret = CmdWrite(pCh->pParent, (uint32_t *)&p->dtmf_rec_ctrl);
+ }
+
+ return ret;
+}
+
+#endif /* DXS_FEAT_DTMFD */
+
+#ifdef DXS_FEAT_TG
+
+#define TG_LEVEL_MIN (-869) /* in units of 0.1 dBm0 */
+#define TG_LEVEL_MIN_API (-169) /* in units of 0.1 dBm0 */
+#define TG_LEVEL_MAX 31 /* in units of 0.1 dBm0 */
+
+#define TG_FREQ_MAX 4000 /* Hz */
+
+/**
+ Function dxs_tone_config
+
+ \param pCh - pointer to DXS channel structure
+ \param level1 - level for frequency 1
+ \param level2 - level for frequency 2
+ \param freq1 - tone frequency 1
+ \param freq2 - tone frequency 2
+ \param am - amplitude modulation flag
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_tone_config(DXS_CHANNEL_t *pCh,
+ int16_t level1, int16_t level2, uint16_t freq1,
+ uint16_t freq2, uint8_t am, uint8_t called_from_api)
+{
+ DXS_SIG_Ch_Resource_t *p;
+ uint16_t new_level1, new_level2, new_freq1, new_freq2;
+ unsigned long temp;
+ int32_t ret = DXS_statusOk;
+ int16_t tg_level_min = (called_from_api == 0) ? TG_LEVEL_MIN : TG_LEVEL_MIN_API;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (level1 < tg_level_min || level1 > TG_LEVEL_MAX)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+ if (level2 < tg_level_min || level2 > TG_LEVEL_MAX)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+ if (freq1 >= TG_FREQ_MAX || freq2 >= TG_FREQ_MAX)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+ if (am > 1)
+ {
+ DXS_RETURN(DXS_statusParamsOutRange);
+ }
+
+ /* calculate new values */
+ if (level1 >= 0)
+ {
+ new_level1 = dBm0_level_tbl[level1];
+ }
+ else
+ {
+ new_level1 = DXS_Misc_MulQ15(22826, DXS_Misc_LeveldB_to_Factor(level1));
+ }
+
+ if (level2 >= 0)
+ {
+ new_level2 = dBm0_level_tbl[level2];
+ }
+ else
+ {
+ new_level2 = DXS_Misc_MulQ15(22826, DXS_Misc_LeveldB_to_Factor(level2));
+ }
+
+ temp = 8192 * (unsigned long)freq1 / 1000;
+ new_freq1 = (uint16_t)temp;
+ temp = 8192 * (unsigned long)freq2 / 1000;
+ new_freq2 = (uint16_t)temp;
+
+ if (new_level1 != p->dtmf_at_gen_coef.LEVEL1 ||
+ new_level2 != p->dtmf_at_gen_coef.LEVEL2 ||
+ new_freq1 != p->dtmf_at_gen_coef.FREQ1 ||
+ new_freq2 != p->dtmf_at_gen_coef.FREQ2)
+ {
+ /* write new values */
+ p->dtmf_at_gen_coef.LEVEL1 = new_level1;
+ p->dtmf_at_gen_coef.LEVEL2 = new_level2;
+ p->dtmf_at_gen_coef.FREQ1 = new_freq1;
+ p->dtmf_at_gen_coef.FREQ2 = new_freq2;
+ ret = CmdWrite(pCh->pParent, (uint32_t *)&p->dtmf_at_gen_coef);
+ }
+
+ if (ret == DXS_statusOk)
+ {
+ p->dtmf_at_gen_ctrl.AM = am;
+ }
+
+ return ret;
+}
+
+/**
+ Function dxs_tone_start
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_tone_start(DXS_CHANNEL_t *pCh)
+{
+ DXS_SIG_Ch_Resource_t *p;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (p->dtmf_at_gen_ctrl.EN == 1)
+ {
+ /* parameters aren't changed */
+ return DXS_statusOk;
+ }
+
+ /* AM field is already set by dxs_tone_config() */
+
+ p->dtmf_at_gen_ctrl.EN = 1;
+
+ return CmdWrite(pCh->pParent, (uint32_t *)&p->dtmf_at_gen_ctrl);
+}
+
+/**
+ Function dxs_tone_stop
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_tone_stop(DXS_CHANNEL_t *pCh)
+{
+ DXS_SIG_Ch_Resource_t *p;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ if (p->dtmf_at_gen_ctrl.EN == 0)
+ {
+ /* parameters aren't changed */
+ return DXS_statusOk;
+ }
+
+ p->dtmf_at_gen_ctrl.EN = 0;
+
+ return CmdWrite(pCh->pParent, (uint32_t *)&p->dtmf_at_gen_ctrl);
+}
+#endif /* DXS_FEAT_TG */
+
+
+#ifdef DXS_FEAT_UTD
+
+/**
+ Get current tone index
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - tone index, uint8_t
+*/
+uint8_t DXS_UTD_ToneIdxGet(DXS_CHANNEL_t *pCh)
+{
+ DXS_SIG_Ch_Resource_t *p;
+
+ if (pCh == NULL)
+ {
+ return 0;
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ return (uint8_t) p->utd_tone_idx;
+}
+
+#endif /* DXS_FEAT_UTD */
+
+#ifdef DXS_FEAT_METERING
+/**
+ Function to enable metering pulse
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SIG_MeterPulseEnable(DXS_CHANNEL_t *pCh)
+{
+ int32_t err = DXS_statusOk;
+ DXS_SIG_Ch_Resource_t *p;
+ int line_mode;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* check if TTX feature is supported */
+ if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_ttx))
+ {
+ DXS_RETURN(DXS_statusFeatNotSupportedCaps);
+ }
+
+ /* Verify that line mode is set to Active (normal or reversed) */
+ line_mode = 0;
+ err = DXS_SDD_LineModeGet(pCh, &line_mode);
+ if (err != DXS_statusOk)
+ {
+ DXS_RETURN(err);
+ }
+ if ((line_mode != DXS_LINE_FEED_ACTIVE_REVPOL) &&
+ (line_mode != DXS_LINE_FEED_ACTIVE))
+ {
+ DXS_RETURN(DXS_statusMeteringLineModeNotActive);
+ }
+
+ /* Check if metering pulse is already enabled */
+ if (p->bMeterPulse)
+ {
+ DXS_RETURN(DXS_statusMeteringPreviousPulseNotFinished);
+ }
+
+ /* Enable metering pulse */
+ p->meter_ctrl.EN = 1;
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->meter_ctrl);
+ if (err == DXS_statusOk)
+ p->bMeterPulse = 1;
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function to disable metering pulse
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SIG_MeterPulseDisable(DXS_CHANNEL_t *pCh)
+{
+ int32_t err = DXS_statusOk;
+ DXS_SIG_Ch_Resource_t *p;
+ int line_mode;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* check if TTX feature is supported */
+ if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_ttx))
+ {
+ DXS_RETURN(DXS_statusFeatNotSupportedCaps);
+ }
+
+ /* Verify that line mode is set to Active (normal or reversed) */
+ line_mode = 0;
+ err = DXS_SDD_LineModeGet(pCh, &line_mode);
+ if (err != DXS_statusOk)
+ {
+ DXS_RETURN(err);
+ }
+ if ((line_mode != DXS_LINE_FEED_ACTIVE_REVPOL) &&
+ (line_mode != DXS_LINE_FEED_ACTIVE))
+ {
+ /* If line mode is not active then meterig pulse should be disabled already,
+ therefore success can be returned without cmd_read and cmd_write */
+ DXS_RETURN(err);
+ }
+
+ /* Disable metering pulse if it is enabled */
+ if (p->bMeterPulse)
+ {
+ p->meter_ctrl.EN = 0;
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->meter_ctrl);
+ if (err == DXS_statusOk)
+ p->bMeterPulse = 0;
+ }
+
+ DXS_RETURN(err);
+}
+
+/**
+ Function to clear metering pulse status
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - DXS_statusOk or DXS_statusInvalidParam
+*/
+int32_t obx_DXS_SIG_MeterPulseStatusClear(DXS_CHANNEL_t *pCh)
+{
+ int32_t err = DXS_statusOk;
+ DXS_SIG_Ch_Resource_t *p;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ p->bMeterPulse = 0;
+
+ DXS_RETURN(err);
+}
+#endif /* DXS_FEAT_METERING */
+
+#ifdef DXS_FEAT_FSK
+/**
+ CID Generator Coefficients update
+
+ \param pCh - pointer to DXS channel structure
+ \param level - FSK send level
+ \param seizure - number of seizure bytes
+ \param mark - number of mark bits
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_FSK_Configure(DXS_CHANNEL_t *pCh, int16_t level, uint16_t seizure,
+ uint16_t mark)
+{
+ DXS_SIG_Ch_Resource_t *p;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* check if CID/FSK feature is supported */
+ if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_cid))
+ {
+ DXS_RETURN(DXS_statusFeatNotSupportedCaps);
+ }
+
+ if (seizure > DXS_CID_MAX_SEIZURE)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ if (mark > DXS_CID_MAX_MARK)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ if ((level < DXS_CID_MIN_LEVEL) || (level > DXS_CID_MAX_LEVEL))
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ /* calculate new values */
+ if (level >= 0)
+ {
+ p->fsk_coef.LEVEL = dBm0_level_tbl[level];
+ }
+ else
+ {
+ p->fsk_coef.LEVEL = DXS_Misc_MulQ15(22826, DXS_Misc_LeveldB_to_Factor(level));
+ }
+
+ p->fsk_coef.SEIZURE = seizure;
+ p->fsk_coef.MARK = mark;
+
+ return CmdWrite(pCh->pParent, (uint32_t *)&p->fsk_coef);
+}
+
+/**
+ CID Generator Enable
+
+ \param pCh - pointer to DXS channel structure
+ \param standard - CID standard
+ \param autodeact - auto deactivation
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_FSK_Enable(DXS_CHANNEL_t *pCh, uint8_t standard, uint8_t autodeact)
+{
+ DXS_SIG_Ch_Resource_t *p;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* check if CID/FSK feature is supported */
+ if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_cid))
+ {
+ DXS_RETURN(DXS_statusFeatNotSupportedCaps);
+ }
+
+ if ((standard != DXS_CID_V23_BEL202) && (standard != DXS_CID_V23_ITU_T))
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ if ((autodeact != DXS_CID_AUTODEACT_ON) &&
+ (autodeact != DXS_CID_AUTODEACT_OFF))
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ /* The DTMF and the CID generator should not be enabled at the same time. */
+ if (p->dtmf_at_gen_ctrl.EN == 1)
+ {
+ DXS_RETURN(DXS_statusFskEnableNotAllowed);
+ }
+
+ /* CID Specification can only be changed if the EN bit is set to 0. */
+ if ((p->fsk_ctrl.V23 != standard) && (p->fsk_ctrl.EN == 1))
+ {
+ DXS_RETURN(DXS_statusFskStandardChangeNotAllowed);
+ }
+
+ p->fsk_ctrl.EN = 1;
+ p->fsk_ctrl.AD = autodeact;
+ p->fsk_ctrl.V23 = standard;
+
+ return CmdWrite(pCh->pParent, (uint32_t *)&p->fsk_ctrl);
+}
+
+/**
+ CID Generator Disable
+
+ \param pCh - pointer to DXS channel structure
+ \param autodeact - auto deactivation
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_FSK_Disable(DXS_CHANNEL_t *pCh, uint8_t autodeact)
+{
+ DXS_SIG_Ch_Resource_t *p;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* check if CID/FSK feature is supported */
+ if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_cid))
+ {
+ DXS_RETURN(DXS_statusFeatNotSupportedCaps);
+ }
+
+ if (p->fsk_ctrl.EN == 0)
+ {
+ /* parameters aren't changed */
+ return DXS_statusOk;
+ }
+
+ p->fsk_ctrl.EN = 0;
+ p->fsk_ctrl.AD = autodeact;
+
+ return CmdWrite(pCh->pParent, (uint32_t *)&p->fsk_ctrl);
+}
+
+/**
+ Send new data to the CID sender
+
+ \param pCh - pointer to DXS channel structure
+ \param nByte - data buffer size
+ \param pByte - pointer to data buffer
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_FSK_Data(DXS_CHANNEL_t *pCh, uint8_t nByte, uint8_t *pByte)
+{
+ DXS_SIG_Ch_Resource_t *p = NULL;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* check if CID/FSK feature is supported */
+ if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_cid))
+ {
+ DXS_RETURN(DXS_statusFeatNotSupportedCaps);
+ }
+
+ if (nByte > DXS_CID_GEN_DATA_MAX)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ if (pByte == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ /* Fill first 3 bytes of data */
+ if (nByte > 0)
+ {
+ p->fsk_data.DATA0 = pByte[0];
+ }
+
+ if (nByte > 1)
+ {
+ p->fsk_data.DATA1 = pByte[1];
+ }
+
+ if (nByte > 2)
+ {
+ p->fsk_data.DATA2 = pByte[2];
+ }
+
+ if (nByte > 3)
+ {
+ /* Copy the data with endianess respecting. */
+ DXS_cpb2dw(p->fsk_data.DATA, pByte + 3, nByte - 3);
+ }
+
+ /* Set the number of CID bytes to be transmitted. */
+ p->fsk_data.NRDATA = nByte;
+
+ return CmdWrite(pCh->pParent, (uint32_t *)&p->fsk_data);
+}
+#endif /* DXS_FEAT_FSK */
+
+#ifdef DXS_FEAT_UTD
+/**
+ Update tone coefficients in the tone table
+
+ \param pCh - pointer to DXS channel structure
+ \param unToneIdx - tone index
+ \param pUtdCoeff - pointer to UTD coefficients
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SIG_UtdCoeffUpdate(DXS_CHANNEL_t *pCh, uint16_t unToneIdx,
+ struct DXS_FW_SIG_UtdCoeff *pUtdCoeff)
+{
+ int32_t ret = DXS_statusOk, err;
+ uint32_t i;
+
+ if (pUtdCoeff == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ err = pthread_mutex_lock(&utd_tone_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ for (i = 0; i < UtdTonesNum; i++)
+ {
+ if (utd_coef_tbl[i].unToneIdx == unToneIdx)
+ break;
+ }
+
+ if (i < UTD_COEF_TABLE_MAX)
+ {
+ /* Tone index or empty record found */
+ if (i >= UtdTonesNum)
+ {
+ utd_coef_tbl[i].unToneIdx = unToneIdx;
+ UtdTonesNum++;
+ }
+ utd_coef_tbl[i].coef_data.BW = pUtdCoeff->BW;
+ utd_coef_tbl[i].coef_data.CF = pUtdCoeff->CF;
+ utd_coef_tbl[i].coef_data.NLEV = pUtdCoeff->NLEV;
+ utd_coef_tbl[i].coef_data.SLEV = pUtdCoeff->SLEV;
+ utd_coef_tbl[i].coef_data.DLEV = pUtdCoeff->DLEV;
+ utd_coef_tbl[i].coef_data.LPCOEFF = pUtdCoeff->LPCOEFF;
+ utd_coef_tbl[i].coef_data.DUP = pUtdCoeff->DUP;
+ }
+ else
+ {
+ /* Tone table is full */
+ ret = DXS_statusError;
+ }
+ err = pthread_mutex_unlock(&utd_tone_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function to enable UTD
+
+ \param pCh - pointer to DXS channel structure
+ \param unToneIdx - tone index
+ \param unDirection - direction
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SIG_UtdEnable(DXS_CHANNEL_t *pCh, uint16_t unToneIdx,
+ uint8_t unDirection)
+{
+ int32_t ret = DXS_statusOk, err;
+ DXS_SIG_Ch_Resource_t *p;
+ uint32_t i;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* check if UTD feature is supported */
+ if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_utd))
+ {
+ DXS_RETURN(DXS_statusFeatNotSupportedCaps);
+ }
+
+ /* Disable UTD if it is enabled */
+ if (p->utd_ctrl.EN)
+ {
+ p->utd_ctrl.EN = 0;
+ ret = CmdWrite(pCh->pParent, (uint32_t *)&p->utd_ctrl);
+ if (ret != DXS_statusOk)
+ {
+ p->utd_ctrl.EN = 1;
+ DXS_RETURN(ret);
+ }
+ }
+
+ err = pthread_mutex_lock(&utd_tone_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ /* Get UTD coefficients */
+ for (i = 0; i < UtdTonesNum; i++)
+ {
+ if (unToneIdx == utd_coef_tbl[i].unToneIdx)
+ break;
+ }
+ if (i >= UtdTonesNum)
+ {
+ /* Tone with the specified index was not loaded into the tone table */
+ ret = DXS_statusUtdToneIdxMissing;
+ }
+ else
+ {
+ /* Write UTD coefficients to the firmware */
+ p->utd_coeff.content = utd_coef_tbl[i].coef_data;
+ ret = CmdWrite(pCh->pParent, (uint32_t *)&p->utd_coeff);
+ }
+
+ err = pthread_mutex_unlock(&utd_tone_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ if (ret != DXS_statusOk)
+ {
+ DXS_RETURN(ret);
+ }
+
+ /* Enable UTD */
+ p->utd_ctrl.EN = 1;
+ p->utd_ctrl.DIR = unDirection ? 0 : 1;
+ ret = CmdWrite(pCh->pParent, (uint32_t *)&p->utd_ctrl);
+ if (ret != DXS_statusOk)
+ {
+ p->utd_ctrl.EN = 0;
+ DXS_RETURN(ret);
+ }
+
+ /* Update tone index */
+ p->utd_tone_idx = unToneIdx;
+
+ DXS_RETURN(ret);
+}
+
+/**
+ Function to disable UTD
+
+ \param pCh - pointer to DXS channel structure
+
+ \return
+ - DXS_status_t
+*/
+int32_t DXS_SIG_UtdDisable(DXS_CHANNEL_t *pCh)
+{
+ int32_t err = DXS_statusOk;
+ DXS_SIG_Ch_Resource_t *p;
+
+ if (pCh == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+ p = (DXS_SIG_Ch_Resource_t *)pCh->sig;
+
+ if (!(p->flag & SIG_CH_INITIALIZED))
+ {
+ DXS_RETURN(DXS_statusNotInitResource);
+ }
+
+ /* check if UTD feature is supported */
+ if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_utd))
+ {
+ DXS_RETURN(DXS_statusFeatNotSupportedCaps);
+ }
+
+ /* Disable UTD if it is enabled */
+ if (p->utd_ctrl.EN)
+ {
+ p->utd_ctrl.EN = 0;
+ err = CmdWrite(pCh->pParent, (uint32_t *)&p->utd_ctrl);
+ if (err != DXS_statusOk)
+ p->utd_ctrl.EN = 1;
+ }
+
+ DXS_RETURN(err);
+}
+#endif /* DXS_FEAT_UTD */
+
diff --git a/marvell/services/dxslic/api_lib/src/dxs_sig.h b/marvell/services/dxslic/api_lib/src/dxs_sig.h
new file mode 100644
index 0000000..d9397cc
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_sig.h
@@ -0,0 +1,62 @@
+#ifndef __DXS_SIG_H__
+#define __DXS_SIG_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_sig.h
+ Signalling channel functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs_lib.h"
+#include "dxs_fw_cmd.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern void *dxs_sig_ch_init(uint8_t dev, uint8_t ch);
+extern void dxs_sig_utd_mtx_init();
+extern void dxs_sig_utd_mtx_destroy();
+
+extern int32_t dxs_dtmf_config(DXS_CHANNEL_t *pCh, int16_t level,
+ int16_t twist);
+extern int32_t dxs_dtmf_enable(DXS_CHANNEL_t *pCh, uint8_t action);
+extern int32_t DXS_SIG_MeterPulseEnable(DXS_CHANNEL_t *pCh);
+extern int32_t DXS_SIG_MeterPulseDisable(DXS_CHANNEL_t *pCh);
+extern int32_t obx_DXS_SIG_MeterPulseStatusClear(DXS_CHANNEL_t *pCh);
+extern int32_t DXS_FSK_Configure(DXS_CHANNEL_t *pCh, int16_t level,
+ uint16_t seizure, uint16_t mark);
+extern int32_t DXS_FSK_Enable(DXS_CHANNEL_t *pCh, uint8_t standard, uint8_t autodeact);
+extern int32_t DXS_FSK_Disable(DXS_CHANNEL_t *pCh, uint8_t autodeact);
+extern int32_t DXS_FSK_Data(DXS_CHANNEL_t *pCh, uint8_t nByte, uint8_t *pByte);
+extern uint8_t DXS_UTD_ToneIdxGet(DXS_CHANNEL_t *pCh);
+extern int32_t DXS_SIG_UtdCoeffUpdate(DXS_CHANNEL_t *pCh, uint16_t unToneIdx,
+ struct DXS_FW_SIG_UtdCoeff *pUtdCoeff);
+extern int32_t DXS_SIG_UtdEnable(DXS_CHANNEL_t *pCh, uint16_t unToneIdx,
+ uint8_t unDirection);
+extern int32_t DXS_SIG_UtdDisable(DXS_CHANNEL_t *pCh);
+extern int32_t dxs_tone_start(DXS_CHANNEL_t *pCh);
+extern int32_t dxs_tone_stop(DXS_CHANNEL_t *pCh);
+extern int32_t dxs_tone_config(DXS_CHANNEL_t *pCh,
+ int16_t level1, int16_t level2, uint16_t freq1,
+ uint16_t freq2, uint8_t am, uint8_t called_from_api);
+#endif /* __DXS_SIG_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_spi.h b/marvell/services/dxslic/api_lib/src/dxs_spi.h
new file mode 100644
index 0000000..f77d725
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_spi.h
@@ -0,0 +1,42 @@
+#ifndef __DXS_SPI_H__
+#define __DXS_SPI_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_spi.h
+ SPI functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern int dxs_spi_linux_init(uint8_t cs, uint8_t access);
+extern void dxs_spi_linux_exit(int fd);
+extern int32_t dxs_spi_linux_read_write(
+ int fd,
+ uint8_t *tx_buf,
+ uint8_t *rx_buf,
+ uint32_t length);
+
+#endif /* __DXS_SPI_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_spi_linux.c b/marvell/services/dxslic/api_lib/src/dxs_spi_linux.c
new file mode 100644
index 0000000..0ad6596
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_spi_linux.c
@@ -0,0 +1,128 @@
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_spi_linux.c
+ Implementation of SPI functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <string.h>
+
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+
+#include "dxs_access.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+
+#include "dxslic_spi.h"
+#include "spidev.h"
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+/* TODO: pull to the API ? */
+#ifndef SPI_BUS_NUMBER
+#define SPI_BUS_NUMBER 32766
+#endif
+#define SPI_BITS_PER_WORD 8
+#define SPI_SPEED_HZ 8192000
+#define SPI_SPEED_CSI_HZ 2048000
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+/**
+ Function dxs_spi_linux_init
+
+ \param cs - cs
+
+ \return
+ - int
+*/
+int dxs_spi_linux_init(uint8_t cs, uint8_t access)
+{
+ return dxslic_spiObj.spi_fd;
+}
+
+/**
+ Function dxs_spi_linux_exit
+
+ \param fd - fd
+
+*/
+void dxs_spi_linux_exit(int fd)
+{
+ close (fd);
+}
+
+/**
+ Function dxs_spi_linux_read_write
+
+ \param fd - fd
+ \param tx_buf - pointer to tx buffer
+ \param rx_buf - pointer to rx buffer
+ \param length - size of the buffer
+
+ \remark Both buffers need to be of the same size which is given in the length
+ parameter.
+
+ \return
+ - DXS_statusOk or DXS_statusSpiTxLenError
+*/
+int32_t dxs_spi_linux_read_write(
+ int fd,
+ uint8_t *tx_buf,
+ uint8_t *rx_buf,
+ uint32_t length)
+{
+ int32_t ret = 0;
+
+ struct spi_ioc_transfer tr = {0};
+
+ /* Access SPI for full duplex reading and writing. */
+ tr.tx_buf = (unsigned long)tx_buf;
+ tr.rx_buf = (unsigned long)rx_buf;
+ tr.len = length;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 0)
+ {
+ fprintf (stderr, "%s:%d SPI_IOC_MESSAGE ret=%d\n",
+ __FILE__, __LINE__, ret);
+ DXS_RETURN(DXS_statusSpiAccError);
+ }
+
+ return ret == length ? DXS_statusOk : DXS_statusSpiTxLenError;
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_timer.c b/marvell/services/dxslic/api_lib/src/dxs_timer.c
new file mode 100644
index 0000000..fb3c1e7
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_timer.c
@@ -0,0 +1,881 @@
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_timer.c
+ This file contains the implementation of timers used in DXS driver.
+*/
+
+/* ========================================================================= */
+/* Includes */
+/* ========================================================================= */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <semaphore.h>
+#include <errno.h>
+
+#include "dxs_timer.h"
+
+/* ========================================================================= */
+/* Macro definitions */
+/* ========================================================================= */
+
+/** default timeout thread poll time (in milliseconds),
+ this is the polling time used to check if new entiries/events were added */
+#ifndef TIMEOUT_THREAD_POLL_TIME
+ #define TIMEOUT_THREAD_POLL_TIME 50
+#endif
+
+/** get pointer to payload of given entry */
+#define list_entry_data(ENTRY) ((void *)((char *)ENTRY + sizeof(struct list_entry)))
+
+/** check if list is empty */
+#define is_list_empty(LIST) \
+ (((LIST)->first_element.next == &(LIST)->first_element) ? DXS_TM_TRUE : DXS_TM_FALSE)
+#define foreach_list_entry_safe_ll(PLIST, ENTRY, NEXT_ENTRY) \
+ for ((ENTRY) = (PLIST)->next, (NEXT_ENTRY) = (ENTRY)->next; \
+ (ENTRY)->next != (PLIST)->next; \
+ (ENTRY) = (NEXT_ENTRY), (NEXT_ENTRY) = (ENTRY)->next)
+#define foreach_list_entry(PLIST, ENTRY) \
+ for ((ENTRY) = (PLIST)->first_element.next; \
+ (ENTRY)->next != (PLIST)->first_element.next; \
+ (ENTRY) = (ENTRY)->next)
+
+/* ========================================================================= */
+/* Type definitions */
+/* ========================================================================= */
+
+/** List entry */
+struct list_entry {
+ /** Previous list entry */
+ struct list_entry *next;
+ /** Next list entry */
+ struct list_entry *prev;
+};
+
+/** List structure */
+struct list {
+ /** Used list entries, this first element is empty
+ and can be used only to pint to other elements */
+ struct list_entry first_element;
+ /** Size of list entry data */
+ size_t payload_size;
+ /** List lock */
+ sem_t lock;
+};
+
+/** timeout descriptor structure */
+struct timeout {
+ /** set DXS_TM_TRUE if handler should be called periodically,
+ otherwise set DXS_TM_FALSE */
+ DXS_TM_BOOL_t bPeriodical;
+ /** timeout argument */
+ unsigned long arg1;
+ /** timeout handler */
+ TIMER_ENTRY handler;
+};
+
+/** timeout list entry */
+struct timeout_list_entry {
+ /** Time when the timeout becomes active (in milliseconds) */
+ time_t timeout_time;
+ /** Time to wait from setting the timeout, used for periodic events */
+ time_t time_in;
+ /** timeout descriptor */
+ struct timeout timeout;
+};
+
+/** timeout control structure */
+struct DXS_TM_Context {
+ /* DXS_TM_TRUE if timers were initialized */
+ DXS_TM_BOOL_t bTimersInialized;
+ /** timeout list */
+ struct list timeout_list;
+ /** Timeout thread control structure */
+ pthread_t timeout_thread_ctrl;
+};
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+
+/** \todo deleting/clean up of timers is missing for user space, it should
+ be called upon closing the tapi thread or even maybe for dev stop */
+/** control structure for timers in user's space */
+struct DXS_TM_Context G_timers /* = {.bTimersInialized = DXS_TM_FALSE} */;
+static volatile sig_atomic_t timer_thr_exit = 0;
+
+/* ========================================================================== */
+/* Local functions */
+/* ========================================================================== */
+
+static int32_t DXS_TM_list_init(struct list *list, size_t payload_size);
+static void DXS_TM_list_entry_free(struct list *list,
+ struct list_entry *entry);
+static int32_t DXS_TM_lockless_event_remove(struct DXS_TM_Context *context,
+ struct list_entry *entry_to_remove);
+static int32_t DXS_TM_timeout_event_remove(struct DXS_TM_Context *context,
+ struct list_entry *timer_entry);
+static void DXS_TM_timeout_event_stop(struct DXS_TM_Context *context,
+ struct list_entry *timer_entry);
+static struct list_entry *DXS_TM_next_active_event_get(struct DXS_TM_Context *context,
+ struct timeout *timeout,
+ time_t * time_to_next_entry);
+static void DXS_TM_list_entry_remove(struct list *list,
+ struct list_entry *entry);
+static void DXS_TM_lockless_event_stop(struct DXS_TM_Context *context,
+ struct list_entry *entry_to_stop);
+static void *DXS_TM_timeout_thread_main(void *arg);
+static void DXS_TM_list_delete(struct list *list);
+static int32_t DXS_TM_timeout_init(struct DXS_TM_Context *context);
+static struct list_entry *DXS_TM_event_entry_create(struct DXS_TM_Context *context,
+ const struct timeout *timeout);
+static struct list_entry *DXS_TM_timeout_event_create(struct DXS_TM_Context *context,
+ TIMER_ENTRY handler,
+ unsigned long arg1);
+static int32_t DXS_TM_timeout_event_start(struct DXS_TM_Context *context,
+ struct list_entry *timer_entry,
+ time_t timeout_time, DXS_TM_BOOL_t bPeriodical);
+static int32_t DXS_TM_event_entry_start(struct DXS_TM_Context *context,
+ struct list_entry *timer_entry,
+ time_t timeout_time,
+ DXS_TM_BOOL_t bPeriodical);
+static int32_t DXS_TM_lockless_event_entry_start(struct DXS_TM_Context *context,
+ struct list_entry *timer_entry,
+ time_t timeout_time);
+static void DXS_TM_list_entry_add_before(struct list *list,
+ struct list_entry *entry,
+ struct list_entry *new_entry);
+static void DXS_TM_list_entry_add_tail(struct list *list,
+ struct list_entry *new_entry);
+static void DXS_TM_list_entry_add_after(struct list *list,
+ struct list_entry *entry,
+ struct list_entry *new_entry);
+
+/**
+ Sleep for defined time period.
+
+ \param pTVal pointer to timespec structure
+
+ \return
+ - none
+*/
+static void dxs_nanosleep(struct timespec *pTVal)
+{
+ while (1)
+ {
+ int rval = nanosleep(pTVal, pTVal);
+ if (rval == 0)
+ {
+ return;
+ }
+ else
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ return;
+ }
+ }
+}
+
+/**
+ Sleep for an interval in ms.
+
+ \param sleepTime_ms sleep time in ms
+
+ \return
+ - none
+*/
+static void dxs_MSecSleep(time_t sleepTime_ms)
+{
+ struct timespec tv;
+ tv.tv_sec = sleepTime_ms/1000;
+ tv.tv_nsec = (long) ((sleepTime_ms - (tv.tv_sec * 1000)) * 1000 * 1000);
+
+ dxs_nanosleep(&tv);
+
+ return;
+}
+
+/**
+ Elapsed time in ms after given timestamp.
+
+ \param refTime_ms reference time in ms
+
+ \return
+ - elapsed time in ms as time_t value
+*/
+static time_t dxs_ElapsedTimeMSecGet(
+ time_t refTime_ms)
+{
+ struct timeval tv = {0};
+ time_t nTime_ms = 0;
+
+ gettimeofday(&tv, NULL);
+ nTime_ms = (time_t)(tv.tv_sec*1000 + (tv.tv_usec) / 1000);
+
+ if ( (refTime_ms == 0) || (refTime_ms > nTime_ms) )
+ {
+ return nTime_ms;
+ }
+
+ return (nTime_ms - refTime_ms);
+}
+
+/**
+ Create new list_entry element and assign a callback function to it.
+
+ \param context pointer to tapi timer context structure
+ \param handler pointer to callback function
+ \param arg1 private data for the callback, can be pointer or int
+
+ \return
+ - pointer to newly allocated list_entry
+ - NULL in case of error, return value of DXS_TM_event_entry_create()
+*/
+static struct list_entry *DXS_TM_timeout_event_create(struct DXS_TM_Context *context,
+ TIMER_ENTRY handler,
+ unsigned long arg1)
+{
+ struct timeout timeout;
+
+ timeout.handler = handler;
+ timeout.arg1 = arg1;
+ timeout.bPeriodical = DXS_TM_FALSE;
+
+ return DXS_TM_event_entry_create(context, &timeout);
+}
+
+/**
+ Create new list_entry element, allocate memory and copy timeout data.
+
+ \param context pointer to tapi timer context structure
+ \param timeout pointer to timeout stucture
+
+ \return
+ - pointer to newly allocated list_entry
+ - NULL in case of error
+*/
+static struct list_entry *DXS_TM_event_entry_create(struct DXS_TM_Context *context,
+ const struct timeout *timeout)
+{
+ struct list_entry *new_entry;
+ struct timeout_list_entry *new_timeout_entry;
+
+ if (sem_wait(&context->timeout_list.lock))
+ return NULL;
+ /* allocate memory for list entry with payload */
+ new_entry = malloc(sizeof(struct list_entry) + context->timeout_list.payload_size);
+ if (!new_entry) {
+ sem_post(&context->timeout_list.lock);
+ return NULL;
+ }
+
+ new_timeout_entry = list_entry_data(new_entry);
+
+ new_timeout_entry->timeout = *timeout;
+
+ sem_post(&context->timeout_list.lock);
+
+ return new_entry;
+}
+
+/**
+ Initialize DXS_TM_Context structure and its list and start timeout control
+ thread.
+
+ \param context pointer to tapi timer context structure
+
+ \return
+ - DXS_TM_SUCCESS or DXS_TM_ERROR in case of errors
+*/
+static int32_t DXS_TM_timeout_init(struct DXS_TM_Context *context)
+{
+ int32_t error;
+
+ error = DXS_TM_list_init(&context->timeout_list, sizeof(struct timeout_list_entry));
+
+ if (error)
+ {
+ fprintf( stderr,
+ ("DXS_API: DXS_TM_list_init() failed for timer Initialization\n"));
+ return error;
+ }
+ error = (DXS_TM_SUCCESS == pthread_create(&context->timeout_thread_ctrl,
+ NULL,
+ DXS_TM_timeout_thread_main,
+ (void *)context)) ? DXS_TM_SUCCESS : DXS_TM_ERROR;
+
+ if (error)
+ {
+ fprintf( stderr,
+ ("DXS_API: Thread init failed for timer Initialization\n"));
+ DXS_TM_list_delete(&context->timeout_list);
+ return error;
+ }
+ return DXS_TM_SUCCESS;
+}
+
+/**
+ Release memory and other resources used.
+
+ \param list pointer to list
+
+*/
+static void DXS_TM_list_delete(struct list *list)
+{
+ struct list_entry *entry, *tmp_entry;
+
+ foreach_list_entry_safe_ll(&list->first_element, entry, tmp_entry)
+ {
+ free(entry);
+ }
+ /* if list is empty fileds next and prev should point first_element */
+ list->first_element.next = &list->first_element;
+ list->first_element.prev = &list->first_element;
+ (void)sem_destroy(&list->lock);
+}
+
+/*
+ * exit from timer thread
+ */
+void terminate_timer_thread(int sig)
+{
+ timer_thr_exit = 1;
+}
+
+/** timeout events handling thread
+
+ \param[in] arg Thread arguments
+
+ \return 0
+*/
+static void *DXS_TM_timeout_thread_main(void *arg)
+{
+ struct DXS_TM_Context *context = (struct DXS_TM_Context *)arg;
+ struct timeout timer = {0};
+ struct list_entry *timer_to_execute_entry = NULL;
+ time_t wait_time;
+ struct sigaction act = {0};
+ int32_t ret;
+
+ act.sa_handler = terminate_timer_thread;
+ sigaction(SIGTERM, &act, NULL);
+
+ /* while thread is running */
+ while (!timer_thr_exit)
+ {
+ /* wait for message in FIFO */
+ while (!timer_thr_exit)
+ {
+ wait_time = 0;
+ ret = sem_wait(&context->timeout_list.lock);
+ if (ret)
+ break;
+ timer_to_execute_entry = DXS_TM_next_active_event_get(context, &timer,
+ &wait_time);
+ sem_post(&context->timeout_list.lock);
+ if (timer_to_execute_entry == NULL)
+ {
+ /* if time to the next timeout is longer than the poll time,
+ then wait only TIMEOUT_THREAD_POLL_TIME ms */
+ if ((wait_time == 0) || (wait_time > TIMEOUT_THREAD_POLL_TIME))
+ {
+ wait_time = TIMEOUT_THREAD_POLL_TIME;
+ }
+ /** \todo replace sleep with select, for this some sync mechanism
+ with add/start entry is needed, for example select could wait
+ for a pipe fd being readable, each function for add/start entry
+ would write to this pipe, this could replace the polling,
+ if above is implemented then wait_time could be set to exact
+ time to next timeout or wait forever untill and event/entry
+ is added */
+ dxs_MSecSleep((time_t) wait_time);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+#if 0
+ /* check if we are shutting down */
+ if (thr_params->bShutDown == DXS_TM_TRUE
+ || thr_params->bRunning == DXS_TM_FALSE)
+ {
+ break;
+ }
+#endif
+
+ ret = sem_wait(&context->timeout_list.lock);
+ if (ret)
+ {
+ break;
+ }
+ else
+ {
+ struct timeout_list_entry *periodical_timeout_entry;
+ time_t time_in;
+
+ periodical_timeout_entry = list_entry_data(timer_to_execute_entry);
+ DXS_TM_lockless_event_stop(context, timer_to_execute_entry);
+ if (periodical_timeout_entry && timer.bPeriodical)
+ {
+ /* for periodical events get time to next timeout and add new timeout */
+ time_in = periodical_timeout_entry->time_in;
+ (void) DXS_TM_lockless_event_entry_start(context, timer_to_execute_entry,
+ time_in);
+ }
+ }
+ sem_post(&context->timeout_list.lock);
+ if (timer.handler != NULL)
+ {
+ (void) timer.handler((Timer_ID) timer_to_execute_entry, (void *) timer.arg1);
+ }
+ else
+ {
+ fprintf( stderr,
+ ("DXS_TM_timeout_thread_main - ERROR: found event without timer handler"));
+ }
+ }
+ return 0;
+}
+
+/**
+ Lockless version of DXS_TM_timeout_event_remove.
+
+ \param context pointer to tapi timer context structure
+ \param entry_to_stop pointer to tapi entry structure
+
+ \return
+ - DXS_TM_SUCCESS
+*/
+static void DXS_TM_lockless_event_stop(struct DXS_TM_Context *context,
+ struct list_entry *entry_to_stop)
+{
+ struct list_entry *current_entry;
+
+ if (is_list_empty(&context->timeout_list))
+ {
+ return;
+ }
+ foreach_list_entry(&context->timeout_list, current_entry)
+ {
+ if (current_entry == entry_to_stop)
+ {
+ DXS_TM_list_entry_remove(&context->timeout_list, current_entry);
+ return;
+ }
+ }
+ return;
+}
+
+/**
+ Remove entry from the list.
+
+ \param list pointer to list structure
+ \param entry pointer to entry structure that will be removed
+*/
+static void DXS_TM_list_entry_remove(struct list *list,
+ struct list_entry *entry)
+{
+ entry->next->prev = entry->prev;
+ entry->prev->next = entry->next;
+ entry->prev = NULL;
+ entry->next = NULL;
+ if (list->first_element.next == entry)
+ {
+ list->first_element.next = &list->first_element;
+ }
+}
+
+/** Get next timeouted event
+
+ \param[in] context timer context pointer
+ \param[out] timeout Returns timeout descriptor
+ \param[out] time_to_next_entry time till the next timeout expires,
+ set only if no entry was found
+
+ \return first entry on the list for which timeout expired or NULL
+*/
+static struct list_entry *DXS_TM_next_active_event_get(struct DXS_TM_Context *context,
+ struct timeout *timeout,
+ time_t * time_to_next_entry)
+{
+ struct timeout_list_entry *first_entry;
+ time_t currentTime;
+
+ if (is_list_empty(&context->timeout_list)) {
+ return NULL;
+ }
+
+ /* get the first entry from the list,
+ should be the one for which timeout expires first */
+ first_entry = list_entry_data(context->timeout_list.first_element.next);
+ if (!first_entry)
+ {
+ return NULL;
+ }
+ currentTime = (time_t)dxs_ElapsedTimeMSecGet(0);
+ if (first_entry->timeout_time <= currentTime)
+ {
+ /* timeout occured for this entry */
+ *timeout = first_entry->timeout;
+ return context->timeout_list.first_element.next;
+ }
+ else
+ {
+ /* get time to next timeout */
+ *time_to_next_entry = first_entry->timeout_time - currentTime;
+ }
+ return NULL;
+}
+
+/** Stop handling of given entry
+
+ \param[in] context timer context pointer
+ \param[in] timer_entry timer entry to stop
+
+ \return always DXS_TM_SUCCESS as DXS_TM_lockless_event_stop does
+*/
+static void DXS_TM_timeout_event_stop(struct DXS_TM_Context *context,
+ struct list_entry *timer_entry)
+{
+ struct timeout_list_entry *timeout_entry_to_start;
+
+ sem_wait(&context->timeout_list.lock);
+ timeout_entry_to_start = list_entry_data(timer_entry);
+ timeout_entry_to_start->timeout.bPeriodical = DXS_TM_FALSE;
+ DXS_TM_lockless_event_stop(context, timer_entry);
+ sem_post(&context->timeout_list.lock);
+
+ return;
+}
+
+/** Remove given entry from the list
+
+ \param[in] context timer context pointer
+ \param[in] timer_entry timer entry to remove
+
+ \return always DXS_TM_SUCCESS as DXS_TM_lockless_event_remove does
+*/
+static int32_t DXS_TM_timeout_event_remove(struct DXS_TM_Context *context,
+ struct list_entry *timer_entry)
+{
+ int32_t error;
+
+ sem_wait(&context->timeout_list.lock);
+ error = DXS_TM_lockless_event_remove(context, timer_entry);
+ sem_post(&context->timeout_list.lock);
+
+ return error;
+}
+
+/** Lockless version of DXS_TM_timeout_event_remove
+
+ \param[in] context timer context pointer
+ \param[in] entry_to_remove entry to remove
+
+ \return always DXS_TM_SUCCESS
+ */
+static int32_t DXS_TM_lockless_event_remove(struct DXS_TM_Context *context,
+ struct list_entry *entry_to_remove)
+{
+ struct list_entry *current_entry;
+
+ if (is_list_empty(&context->timeout_list))
+ {
+ return DXS_TM_SUCCESS;
+ }
+ foreach_list_entry(&context->timeout_list, current_entry)
+ {
+ if (current_entry == entry_to_remove)
+ {
+ DXS_TM_list_entry_free(&context->timeout_list, current_entry);
+ return DXS_TM_SUCCESS;
+ }
+ }
+ return DXS_TM_SUCCESS;
+}
+
+/** Release memory allocated for given entry
+
+ \param[in] list pointeer to the list - unused
+ \param[in] entry entry to remove and free memory
+ */
+static void DXS_TM_list_entry_free(struct list *list,
+ struct list_entry *entry)
+{
+ if ((NULL != entry->next) && (NULL != entry->prev))
+ {
+ entry->next->prev = entry->prev;
+ entry->prev->next = entry->next;
+ }
+ free(entry);
+}
+
+/** Release memory allocated for given entry
+
+ \param[in] list pointeer to the list
+ \param[in] payload_size size of memory in bytes needed to hold the entry data
+
+ \return value sem_init() call
+ */
+static int32_t DXS_TM_list_init(struct list *list, size_t payload_size)
+{
+ /* for first element next and prev point to first element if list is empty */
+ list->first_element.next = &list->first_element;
+ list->first_element.prev = &list->first_element;
+ list->payload_size = payload_size;
+ /* get the lock */
+ return sem_init(&list->lock, 0, 1);
+}
+
+/** Start handling of given timeout entry
+
+ \param[in] context timer context pointer
+ \param[in] timer_entry timer entry to start
+ \param[in] timeout_time timoeout time for new timer entry
+ \param[in] bPeriodical if DXS_TM_TRUE, then timeout for event will be
+ checked periodicaly to execute the handler
+
+ \return always DXS_TM_SUCCESS as DXS_TM_event_entry_start does
+*/
+static int32_t DXS_TM_timeout_event_start(struct DXS_TM_Context *context,
+ struct list_entry *timer_entry,
+ time_t timeout_time, DXS_TM_BOOL_t bPeriodical)
+{
+ /** \todo add a check if timers are initialized */
+ return DXS_TM_event_entry_start(context, timer_entry, timeout_time, bPeriodical);
+}
+
+/** Start handling of given timeout entry
+
+ \param[in] context timer context pointer
+ \param[in] timer_entry timer entry to start
+ \param[in] timeout_time timoeout time for new timer entry
+ \param[in] bPeriodical if DXS_TM_TRUE, then timeout for event will be
+ checked periodicaly to execute the handler
+
+ \return always DXS_TM_SUCCESS
+*/
+static int32_t DXS_TM_event_entry_start(struct DXS_TM_Context *context,
+ struct list_entry *timer_entry,
+ time_t timeout_time,
+ DXS_TM_BOOL_t bPeriodical)
+{
+ struct timeout_list_entry *timeout_entry_to_start;
+ int32_t ret;
+
+ sem_wait(&context->timeout_list.lock);
+ timeout_entry_to_start = list_entry_data(timer_entry);
+ timeout_entry_to_start->timeout.bPeriodical = bPeriodical;
+ ret = DXS_TM_lockless_event_entry_start(context, timer_entry, timeout_time);
+ sem_post(&context->timeout_list.lock);
+
+ return ret;
+}
+
+/** Add timeout event
+
+ \param[in] context timer context pointer
+ \param[in] timer_entry timer entry to start
+ \param[in] timeout_time timoeout time for new timer entry (in ms)
+
+ \return always DXS_TM_SUCCESS
+*/
+static int32_t DXS_TM_lockless_event_entry_start(struct DXS_TM_Context *context,
+ struct list_entry *timer_entry,
+ time_t timeout_time)
+{
+ struct list_entry *current_entry;
+ struct timeout_list_entry *timeout_entry, *timeout_entry_to_start;
+ DXS_TM_BOOL_t added = DXS_TM_FALSE;
+
+ if (timer_entry == NULL)
+ return DXS_TM_ERROR;
+ timeout_entry_to_start = list_entry_data(timer_entry);
+ if (timeout_entry_to_start == NULL)
+ return DXS_TM_ERROR;
+ /* get timeout time to compare with current time read
+ with dxs_ElapsedTimeMSecGet(0) */
+ timeout_entry_to_start->timeout_time = dxs_ElapsedTimeMSecGet(0) + timeout_time;
+ timeout_entry_to_start->time_in = timeout_time;
+ foreach_list_entry(&context->timeout_list, current_entry)
+ {
+ timeout_entry = list_entry_data(current_entry);
+ if (timeout_entry->timeout_time >
+ timeout_entry_to_start->timeout_time)
+ {
+ DXS_TM_list_entry_add_before(&context->timeout_list, current_entry,
+ timer_entry);
+ added = DXS_TM_TRUE;
+ break;
+ }
+ }
+ if (!added)
+ {
+ DXS_TM_list_entry_add_tail(&context->timeout_list, timer_entry);
+ }
+ return DXS_TM_SUCCESS;
+}
+
+/** Add add new entry before entry that is already on the list
+
+ \param[in] list the list - unused
+ \param[in] entry entry from the list
+ \param[in] new_entry entry to add
+*/
+static void DXS_TM_list_entry_add_before(struct list *list,
+ struct list_entry *entry,
+ struct list_entry *new_entry)
+{
+ entry->prev->next = new_entry;
+ new_entry->prev = entry->prev;
+ new_entry->next = entry;
+ entry->prev = new_entry;
+}
+
+/** Add add new entry at the end of the list
+
+ \param[in] list the list
+ \param[in] entry entry to add
+*/
+static void DXS_TM_list_entry_add_tail(struct list *list,
+ struct list_entry *new_entry)
+{
+ DXS_TM_list_entry_add_after(list, list->first_element.prev, new_entry);
+}
+
+/** Add add new entry after entry that is already on the list
+
+ \param[in] list the list - unused
+ \param[in] entry entry from the list
+ \param[in] new_entry entry to add
+*/
+static void DXS_TM_list_entry_add_after(struct list *list,
+ struct list_entry *entry,
+ struct list_entry *new_entry)
+{
+ entry->next->prev = new_entry;
+ new_entry->next = entry->next;
+ entry->next = new_entry;
+ new_entry->prev = entry;
+}
+
+/* ========================================================================== */
+/* Public functions */
+/* ========================================================================== */
+
+/**
+ Create a timer.
+
+ \param pTimerEntry Function pointer to the call back function.
+ \param nArgument Pointer to DXS channel structure.
+
+ \return
+ Timer_ID Pointer to internal timer structure.
+
+ \remarks
+ Initialize a task queue which will be scheduled once a timer interrupt occurs
+ to execute the appropriate operation in a process context, process in which
+ semaphores ... are allowed.
+ Please notice that this task has to run under the keventd process, in which
+ it can be executed thousands of times within a single timer tick.
+*/
+Timer_ID DXS_TimerCreate(TIMER_ENTRY pTimerEntry, void *nArgument)
+{
+ if (DXS_TM_TRUE != G_timers.bTimersInialized)
+ {
+ /* timeout thread needs to be started only once */
+ G_timers.bTimersInialized = DXS_TM_TRUE;
+ DXS_TM_timeout_init(&G_timers);
+ }
+ return (Timer_ID) DXS_TM_timeout_event_create(&G_timers, pTimerEntry,
+ (unsigned long)nArgument);
+}
+
+/**
+ Sets a timer to the specified time and starts it. It can be choose if the
+ timer starts periodically.
+
+ \param Timer_ID Pointer to internal timer structure.
+ \param nTime Time in ms.
+ \param bPeriodically Starts the timer periodically or not.
+ \param bRestart Restart the timer or normal start.
+
+ \return
+ Returns an error code: DXS_TM_TRUE / DXS_TM_FALSE
+*/
+DXS_TM_BOOL_t DXS_TimerSet(Timer_ID Timer, uint32_t nTime, DXS_TM_BOOL_t bPeriodically,
+ DXS_TM_BOOL_t bRestart)
+{
+ /** \todo add a check if timers are initialized */
+ if (bRestart == DXS_TM_TRUE)
+ {
+ DXS_TM_timeout_event_stop(&G_timers, (struct list_entry *) Timer);
+ }
+
+ if (DXS_TM_timeout_event_start(&G_timers,
+ (struct list_entry *) Timer,
+ (time_t) nTime,
+ bPeriodically) != 0)
+ {
+ fprintf ( stderr, ("DXS_TimerSet: failed to start timer\n"));
+ return DXS_TM_FALSE;
+ }
+
+ return DXS_TM_TRUE;
+}
+
+/**
+ Stop a timer.
+
+ \param Timer_ID Pointer to internal timer structure.
+
+ \return
+ Returns an error code: DXS_TM_TRUE / DXS_TM_FALSE
+*/
+DXS_TM_BOOL_t DXS_TimerStop(Timer_ID Timer)
+{
+ if(Timer)
+ DXS_TM_timeout_event_stop(&G_timers, (struct list_entry *) Timer);
+
+ return DXS_TM_TRUE;
+}
+
+/**
+ Delete a timer.
+
+ \param Timer_ID Pointer to internal timer structure.
+
+ \return
+ Returns an error code: DXS_TM_TRUE / DXS_TM_FALSE
+*/
+DXS_TM_BOOL_t DXS_TimerDestroy(Timer_ID Timer)
+{
+ if (Timer == NULL)
+ return DXS_TM_FALSE;
+
+ DXS_TimerStop(Timer);
+
+ /* free memory */
+ (void) DXS_TM_timeout_event_remove(&G_timers, (struct list_entry *)Timer);
+
+ return DXS_TM_TRUE;
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_timer.h b/marvell/services/dxslic/api_lib/src/dxs_timer.h
new file mode 100644
index 0000000..843b5cf
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_timer.h
@@ -0,0 +1,54 @@
+#ifndef __DXS_TIMER_H__
+#define __DXS_TIMER_H__
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_timer.h
+ This file contains the declaration of the functions for timers.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include <stdint.h>
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+#define DXS_TM_SUCCESS 0
+#define DXS_TM_ERROR (-1)
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+typedef enum
+{
+ DXS_TM_FALSE = 0,
+ DXS_TM_TRUE
+} DXS_TM_BOOL_t;
+
+typedef void* Timer_ID;
+typedef void (*TIMER_ENTRY)(Timer_ID timer_id, void *arg);
+
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+extern Timer_ID DXS_TimerCreate(TIMER_ENTRY pTimerEntry, void *nArgument);
+extern DXS_TM_BOOL_t DXS_TimerSet(Timer_ID Timer,
+ uint32_t nTime,
+ DXS_TM_BOOL_t bPeriodically,
+ DXS_TM_BOOL_t bRestart);
+extern DXS_TM_BOOL_t DXS_TimerStop(Timer_ID Timer);
+extern DXS_TM_BOOL_t DXS_TimerDestroy(Timer_ID Timer);
+
+#endif /* __DXS_TIMER_H__ */
diff --git a/marvell/services/dxslic/api_lib/src/dxs_wait.c b/marvell/services/dxslic/api_lib/src/dxs_wait.c
new file mode 100644
index 0000000..f42a215
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_wait.c
@@ -0,0 +1,391 @@
+/******************************************************************************
+
+ Copyright (c) 2014-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2016, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_wait.c
+ Implementation of WaitList functions.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+#include "dxs.h"
+#include "dxs_lib.h"
+#include "dxs_fifo.h"
+#include "dxs_errno.h"
+#include "dxs_error.h"
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+/* max number of waiting lists */
+#define DXS_MAX_WAITLISTS 16
+/* max elements in a single waiting list */
+#define DXS_MAX_WAITLIST_OBJ 32
+/* max total waiting list elements */
+#define DXS_MAX_WAITLIST_ELEMENTS (DXS_MAX_WAITLISTS*DXS_MAX_WAITLIST_OBJ)
+
+#define DXS_WAITLIST_MAGIC 0x574C7853
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+struct __waitlist
+{
+ uint32_t magic;
+ uint8_t in_use;
+ pthread_mutex_t op_mtx;
+ sem_t wait_sem;
+ struct __waiting_obj *head;
+};
+
+struct __waiting_obj
+{
+ DXS_DEVICE_t *pDev;
+ struct __waiting_obj *next;
+};
+
+/* ========================================================================== */
+/* Global variables */
+/* ========================================================================== */
+static struct __waitlist waitlists[DXS_MAX_WAITLISTS] = {{0},};
+static struct __waiting_obj wobjects[DXS_MAX_WAITLIST_ELEMENTS] = {{NULL},};
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function implementation */
+/* ========================================================================== */
+
+/*
+ *
+ * FIXME: current limitation:
+ * a device can be a member of the one waiting list
+ *
+ */
+
+ /**
+ Function dxs_wl_init
+
+ \return
+ - waiting list instance or NULL
+*/
+DXS_WaitList_t dxs_wl_init()
+{
+ int i, err;
+ struct __waitlist *wl;
+
+ /* find the next free list */
+ for (i=0; i<DXS_MAX_WAITLISTS; i++)
+ {
+ wl = &waitlists[i];
+ if (!wl->in_use)
+ break;
+ }
+ if (i == DXS_MAX_WAITLISTS)
+ {
+ /* list not found */
+ return (DXS_WaitList_t)NULL;
+ }
+
+ pthread_mutex_init(&wl->op_mtx, NULL);
+
+ err = pthread_mutex_lock (&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ wl->magic = DXS_WAITLIST_MAGIC;
+ wl->in_use = 1;
+ wl->head = NULL;
+
+ /* initialize wait sem */
+ sem_init(&wl->wait_sem, 0, 0);
+
+ err = pthread_mutex_unlock (&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ return (DXS_WaitList_t)wl;
+}
+
+/**
+ Function dxs_wl_destroy
+
+ \param wlist - WaitList
+
+*/
+void dxs_wl_destroy(DXS_WaitList_t wlist)
+{
+ struct __waitlist *wl = (struct __waitlist *)wlist;
+ int err;
+ if (wl == NULL || wl->magic != DXS_WAITLIST_MAGIC)
+ return;
+
+ err = pthread_mutex_lock (&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ wl->in_use = 0;
+ wl->magic = 0;
+
+ sem_destroy(&wl->wait_sem);
+
+ err = pthread_mutex_unlock (&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ err = pthread_mutex_destroy(&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+}
+
+/**
+ Function dxs_wl_dev_add
+
+ \param pDev - pointer to DXS device structure
+ \param wlist - WaitList
+
+ \return
+ - DXS_status_t
+*/
+int32_t dxs_wl_dev_add(DXS_DEVICE_t *pDev, DXS_WaitList_t wlist)
+{
+ struct __waitlist *wl = (struct __waitlist *)wlist;
+ struct __waiting_obj *wo;
+ int i, err;
+
+ if (wl == NULL || wl->magic != DXS_WAITLIST_MAGIC)
+ {
+ DXS_RETURN(DXS_statusWaitListObjInv);
+ }
+
+ if (pDev == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ err = pthread_mutex_lock (&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ /* check if pDev was already added to the list */
+ if (wl->head != NULL)
+ {
+ uint8_t found = 0;
+ struct __waiting_obj *w = wl->head;
+
+ while (w != NULL)
+ {
+ if (w->pDev == pDev)
+ {
+ found = 1;
+ break;
+ }
+ w = w->next;
+ }
+
+ if (found)
+ {
+ /* device was already added - not an error */
+ err = pthread_mutex_unlock (&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ return DXS_statusOk;
+ }
+ }
+
+ /* get the next free element */
+ for (i=0; i<DXS_MAX_WAITLIST_ELEMENTS; i++)
+ {
+ wo = &wobjects[i];
+ if (wo->pDev == NULL)
+ break;
+ }
+ if (i == DXS_MAX_WAITLIST_ELEMENTS)
+ {
+ /* cannot add a device into the list */
+ err = pthread_mutex_unlock (&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+ DXS_RETURN(DXS_statusWaitListDevAddErr);
+ }
+
+ wo->pDev = pDev;
+ wo->next = NULL;
+
+ /* add to the tail of the list */
+ if (wl->head == NULL)
+ {
+ wl->head = wo;
+ }
+ else
+ {
+ struct __waiting_obj *w = wl->head;
+
+ while (w->next != NULL)
+ w = w->next;
+
+ w->next = wo;
+ }
+
+ /* link pDev with wl
+ TODO: introduce a list of wl as a device
+ might be a member of more than one wl */
+ pDev->wait_list = wlist;
+
+ err = pthread_mutex_unlock (&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ return DXS_statusOk;
+}
+
+/**
+ Function dxs_wl_dev_remove
+
+ \param pDev - pointer to DXS device structure
+ \param wlist - WaitList
+
+ \return
+ - int32_t 0 or -1
+*/
+int32_t dxs_wl_dev_remove(DXS_DEVICE_t *pDev, DXS_WaitList_t wlist)
+{
+ struct __waitlist *wl = (struct __waitlist *)wlist;
+ struct __waiting_obj *wo, *prev;
+ int err;
+
+ if (wl == NULL || wl->magic != DXS_WAITLIST_MAGIC)
+ {
+ DXS_RETURN(DXS_statusWaitListObjInv);
+ }
+
+ if (pDev == NULL)
+ {
+ DXS_RETURN(DXS_statusInvalidParam);
+ }
+
+ err = pthread_mutex_lock (&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ wo = wl->head;
+ prev = NULL;
+
+ while (wo != NULL)
+ {
+ if (wo->pDev == pDev)
+ {
+ if (prev == NULL)
+ {
+ wl->head = wo->next;
+ }
+ else
+ {
+ prev->next = wo->next;
+ }
+ wo->pDev = NULL;
+ wo->next = NULL;
+ break;
+ }
+
+ prev = wo;
+ wo = wo->next;
+ }
+
+ err = pthread_mutex_unlock (&wl->op_mtx);
+ if (err != 0)
+ DXS_ERROR_PUSH(err);
+
+ DXS_RETURN(DXS_statusOk);
+}
+
+/**
+ Function dxs_wait
+
+ \param wlist - WaitList
+
+ \return
+ - device number
+*/
+int32_t dxs_wait(DXS_WaitList_t wlist)
+{
+ struct __waitlist *wl = (struct __waitlist *)wlist;
+ struct __waiting_obj *wo;
+ int32_t ret;
+
+ if (wl == NULL || wl->magic != DXS_WAITLIST_MAGIC)
+ {
+ return -1;
+ }
+
+ if (wl->head == NULL)
+ {
+ return -2;
+ }
+
+ wo = wl->head;
+
+ while (wo != NULL)
+ {
+ FIFO_t *evq = wo->pDev->event_queue;
+
+ if (0 < fifo_count (evq))
+ {
+ return wo->pDev->nDevNum;
+ }
+
+ wo = wo->next;
+ }
+
+ ret = sem_wait (&wl->wait_sem);
+ if (ret)
+ {
+ return ret;
+ }
+
+ wo = wl->head;
+
+ while (wo != NULL)
+ {
+ FIFO_t *evq = wo->pDev->event_queue;
+
+ if (0 < fifo_count (evq))
+ {
+ return wo->pDev->nDevNum;
+ }
+
+ wo = wo->next;
+ }
+
+ /* unreachable */
+ return 0;
+}
+
+/**
+ Function dxs_wakeup
+
+ \param pDev - pointer to DXS device structure
+
+*/
+void dxs_wakeup(DXS_DEVICE_t *pDev)
+{
+ struct __waitlist *wl;
+
+ if (pDev != NULL && pDev->wait_list != NULL)
+ {
+ wl = (struct __waitlist *)pDev->wait_list;
+
+ sem_post (&wl->wait_sem);
+ }
+}
diff --git a/marvell/services/dxslic/api_lib/src/dxs_wait.h b/marvell/services/dxslic/api_lib/src/dxs_wait.h
new file mode 100644
index 0000000..033cfd6
--- /dev/null
+++ b/marvell/services/dxslic/api_lib/src/dxs_wait.h
@@ -0,0 +1,42 @@
+#ifndef __DXS_WAIT_H__
+#define __DXS_WAIT_H__
+/******************************************************************************
+
+ Copyright (c) 2006-2015 Lantiq Deutschland GmbH
+ Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
+ Copyright 2018, Intel Corporation.
+
+ For licensing information, see the file 'LICENSE' in the root folder of
+ this software module.
+
+******************************************************************************/
+
+/**
+ \file dxs_wait.h
+ WaitList functions declarations.
+*/
+
+/* ========================================================================== */
+/* Includes */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Macro definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Type definitions */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Function prototypes */
+/* ========================================================================== */
+
+extern DXS_WaitList_t dxs_wl_init();
+extern void dxs_wl_destroy(DXS_WaitList_t wlist);
+extern int32_t dxs_wl_dev_add(DXS_DEVICE_t *pDev, DXS_WaitList_t wlist);
+extern int32_t dxs_wl_dev_remove(DXS_DEVICE_t *pDev, DXS_WaitList_t wlist);
+extern int32_t dxs_wait(DXS_WaitList_t wlist);
+extern void dxs_wakeup(DXS_DEVICE_t *pDev);
+
+#endif /* __DXS_WAIT_H__ */