-/*****************************************************************************\r
- * win_api_common.h Windows Sangoma API Code Library\r
- *\r
- * Author(s): David Rokhvarg <davidr@sangoma.com>\r
- *\r
- * Copyright: (c) 1984-2006 Sangoma Technologies Inc.\r
- *\r
- * ============================================================================\r
- */\r
-\r
-#ifndef _WIN_API_COMMON_H\r
-#define _WIN_API_COMMON_H\r
-\r
+/*****************************************************************************
+ * sangoma_tdm_api.h Sangoma API Code Library
+ *
+ * Author(s): David Rokhvarg <davidr@sangoma.com>
+ *
+ * Copyright: (c) 1984-2006 Sangoma Technologies Inc.
+ *
+ * ============================================================================
+ */
+
+#ifndef _SANGOMA_TDM_API_H
+#define _SANGOMA_TDM_API_H
+
+#ifndef __WINDOWS__
+#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)
+#define __WINDOWS__
+#endif
+#endif
+
+#ifdef __WINDOWS__
+#ifdef _MSC_VER
+/* disable warning for zero length array in a struct */
+/* this will cause errors on c99 and ansi compliant compilers and will need to be fixed in the wanpipe header files */
+#pragma warning(disable:4200 4201 4214)
+#endif
+#include <windows.h>
+#define WP_INVALID_SOCKET INVALID_HANDLE_VALUE
+#else
+#define WP_INVALID_SOCKET -1
+#include <stropts.h>
+#endif
+
+#include <wanpipe_defines.h>
+#include <wanpipe_cfg.h>
+#include <wanpipe_tdm_api.h>
+#include <sdla_te1_pmc.h>
+#ifdef __WINDOWS__
+#include <sang_status_defines.h>
+#include <sang_api.h>
+#endif
+#include <sdla_aft_te1.h>
+
+#define FNAME_LEN 50
#define DEV_NAME_LEN 100
char device_name[DEV_NAME_LEN];
+
+#ifdef __WINDOWS__
+
/* IOCTL management structures and variables*/
wan_udp_hdr_t wan_udp;
static wan_cmd_api_t api_cmd;
-static api_tx_hdr_t *tx_hdr = (api_tx_hdr_t *)api_cmd.data;\r
-\r
-/* keeps the LAST (and single) event received */\r
-static wp_tdm_api_rx_hdr_t last_tdm_api_event_buffer;\r
-\r
-static \r
-int \r
-tdmv_api_ioctl(\r
- HANDLE fd, \r
- wanpipe_tdm_api_cmd_t *tdm_api_cmd\r
- )\r
-{\r
- DWORD ln;\r
- unsigned char id = 0;\r
- int err = 0;\r
-\r
- wan_udp.wan_udphdr_request_reply = 0x01;\r
- wan_udp.wan_udphdr_id = id;\r
- wan_udp.wan_udphdr_return_code = WAN_UDP_TIMEOUT_CMD;\r
-\r
- wan_udp.wan_udphdr_command = WAN_TDMV_API_IOCTL;\r
- wan_udp.wan_udphdr_data_len = sizeof(wanpipe_tdm_api_cmd_t);\r
-\r
- //copy data from caller's buffer to driver's buffer\r
- memcpy( wan_udp.wan_udphdr_data, \r
- (void*)tdm_api_cmd,\r
- sizeof(wanpipe_tdm_api_cmd_t));\r
-\r
- if(DeviceIoControl(\r
- fd,\r
- IoctlManagementCommand,\r
- (LPVOID)&wan_udp,\r
- sizeof(wan_udp_hdr_t),\r
- (LPVOID)&wan_udp,\r
- sizeof(wan_udp_hdr_t),\r
- (LPDWORD)(&ln),\r
- (LPOVERLAPPED)NULL\r
- ) == FALSE){\r
- //actual ioctl failed\r
- err = 1;\r
- return err;\r
- }else{\r
- err = 0;\r
- }\r
-\r
- if(wan_udp.wan_udphdr_return_code != WAN_CMD_OK){\r
- //ioctl ok, but command failed\r
- return 2;\r
- }\r
-\r
- //copy data from driver's buffer to caller's buffer\r
- memcpy( (void*)tdm_api_cmd,\r
- wan_udp.wan_udphdr_data, \r
- sizeof(wanpipe_tdm_api_cmd_t));\r
- return 0;\r
-}\r
-\r
-static \r
-int \r
-wanpipe_api_ioctl(\r
- HANDLE fd,\r
- wan_cmd_api_t *api_cmd\r
- )\r
-{\r
- DWORD ln;\r
- unsigned char id = 0;\r
- int err = 0;\r
-\r
- wan_udp.wan_udphdr_request_reply = 0x01;\r
- wan_udp.wan_udphdr_id = id;\r
- wan_udp.wan_udphdr_return_code = WAN_UDP_TIMEOUT_CMD;\r
-\r
- wan_udp.wan_udphdr_command = SIOC_WANPIPE_API;\r
- wan_udp.wan_udphdr_data_len = sizeof(wan_cmd_api_t);\r
-\r
- //copy data from caller's buffer to driver's buffer\r
- memcpy( wan_udp.wan_udphdr_data, \r
- (void*)api_cmd,\r
- sizeof(wan_cmd_api_t));\r
-\r
- if(DeviceIoControl(\r
- fd,\r
- IoctlManagementCommand,\r
- (LPVOID)&wan_udp,\r
- sizeof(wan_udp_hdr_t),\r
- (LPVOID)&wan_udp,\r
- sizeof(wan_udp_hdr_t),\r
- (LPDWORD)(&ln),\r
- (LPOVERLAPPED)NULL\r
- ) == FALSE){\r
- err = 1;\r
- return err;\r
- }else{\r
- err = 0;\r
- }\r
-\r
- if(wan_udp.wan_udphdr_return_code != WAN_CMD_OK){\r
- return 2;\r
- }\r
-\r
- //copy data from driver's buffer to caller's buffer\r
- memcpy( (void*)api_cmd,\r
- wan_udp.wan_udphdr_data, \r
- sizeof(wan_cmd_api_t));\r
- return 0;\r
-}\r
-\r
-// Blocking read command. If used after DoApiPollCommand(),\r
-// it will return immediatly, without blocking.\r
-static \r
-USHORT \r
-DoReadCommand(\r
- HANDLE drv, \r
- RX_DATA_STRUCT * pRx\r
- )\r
-{\r
- DWORD ln;\r
-\r
- if (DeviceIoControl(\r
- drv,\r
- IoctlReadCommand,\r
- (LPVOID)NULL,\r
- 0L,\r
- (LPVOID)pRx,\r
- sizeof(RX_DATA_STRUCT),\r
- (LPDWORD)(&ln),\r
- (LPOVERLAPPED)NULL\r
- ) == FALSE){\r
- //check messages log\r
- return 1;\r
- }else{\r
- return 0;\r
- }\r
-}\r
-\r
-// Blocking write command. If used after DoApiPollCommand(),\r
-// it will return immediatly, without blocking.\r
-static\r
-UCHAR \r
-DoWriteCommand(\r
- HANDLE drv, \r
- TX_DATA_STRUCT * pTx\r
- )\r
-{\r
- DWORD ln;\r
-\r
- if(DeviceIoControl(\r
- drv,\r
- IoctlWriteCommand,\r
- (LPVOID)pTx,\r
- (ULONG)sizeof(TX_DATA_STRUCT),\r
- (LPVOID)pTx,\r
- sizeof(TX_DATA_STRUCT),\r
- (LPDWORD)(&ln),\r
- (LPOVERLAPPED)NULL\r
- ) == FALSE){\r
- return 1;\r
- }else{\r
- return 0;\r
- }\r
-}\r
-\r
-// Blocking API Poll command.\r
-static\r
-USHORT \r
-DoApiPollCommand(\r
- HANDLE drv, \r
- API_POLL_STRUCT *api_poll_ptr\r
- )\r
-{\r
- DWORD ln;\r
-\r
- if (DeviceIoControl(\r
- drv,\r
- IoctlApiPoll,\r
- (LPVOID)NULL,\r
- 0L,\r
- (LPVOID)api_poll_ptr,\r
- sizeof(API_POLL_STRUCT),\r
- (LPDWORD)(&ln),\r
- (LPOVERLAPPED)NULL\r
- ) == FALSE){\r
- return 1;\r
- }else{\r
- return 0;\r
- }\r
-}\r
-\r
-static\r
-int \r
-DoManagementCommand(\r
- HANDLE drv, \r
- wan_udp_hdr_t* wan_udp\r
- )\r
-{\r
- DWORD ln;\r
- static unsigned char id = 0;\r
-\r
- wan_udp->wan_udphdr_request_reply = 0x01;\r
- wan_udp->wan_udphdr_id = id++;\r
- wan_udp->wan_udphdr_return_code = WAN_UDP_TIMEOUT_CMD;\r
-\r
- if(DeviceIoControl(\r
- drv,\r
- IoctlManagementCommand,\r
- (LPVOID)wan_udp,\r
- sizeof(wan_udp_hdr_t),\r
- (LPVOID)wan_udp,\r
- sizeof(wan_udp_hdr_t),\r
- (LPDWORD)(&ln),\r
- (LPOVERLAPPED)NULL\r
- ) == FALSE){\r
- return 1;\r
- }else{\r
- return 0;\r
- }\r
-}\r
-\r
-///////////////////////////////////////////////////////////////////////////\r
-//\r
-//structures and definitions used for queueing data\r
-//\r
-typedef struct\r
-{\r
- void* previous;\r
- TX_RX_DATA_STRUCT tx_rx_data;\r
-}api_queue_element_t;\r
-\r
-#define API_Q_MUTEX_TIMEOUT 1000//1 second\r
-#define API_Q_MAX_SIZE 100//optimal length. for short data may need longer queue\r
-\r
-enum API_Q_STATUS{\r
- API_Q_SUCCESS=0,\r
- API_Q_GEN_FAILURE,\r
- API_Q_MEM_ALLOC_FAILURE,\r
- API_Q_FULL,\r
- API_Q_EMPTY\r
-};\r
-\r
-typedef struct\r
-{\r
- //number of nodes in the list\r
- USHORT size;\r
- //insert at tail\r
- api_queue_element_t * tail;\r
- //remove from head\r
- api_queue_element_t * head;\r
- //mutex for synchronizing access to the queue\r
- HANDLE api_queue_mutex;\r
-}api_queue_t;\r
-\r
-\r
-static __inline int api_enqueue( api_queue_t* api_queue, \r
- unsigned char * buffer,\r
- unsigned short length)\r
-{\r
- api_queue_element_t *element;\r
- DWORD mresult;\r
-\r
- mresult = WaitForSingleObject(api_queue->api_queue_mutex, API_Q_MUTEX_TIMEOUT);\r
- if (mresult != WAIT_OBJECT_0) {\r
- return API_Q_GEN_FAILURE;\r
- }\r
-\r
- if(api_queue->size == API_Q_MAX_SIZE){\r
- ReleaseMutex(api_queue->api_queue_mutex);\r
- return API_Q_FULL;\r
- }\r
-\r
- element = malloc(sizeof(api_queue_element_t));\r
- if(element == NULL){\r
- ReleaseMutex(api_queue->api_queue_mutex);\r
- return API_Q_MEM_ALLOC_FAILURE;\r
- }\r
-\r
- //now copy everything in to the element\r
- memcpy(element->tx_rx_data.data, buffer, length);\r
- \r
- element->tx_rx_data.api_header.data_length = length;\r
- element->tx_rx_data.api_header.operation_status = SANG_STATUS_TX_TIMEOUT;\r
-\r
- //insert element at the tail of the queue\r
- element->previous = NULL;\r
-\r
- if(api_queue->size == 0){\r
- //special case of a previously empty queue\r
- api_queue->head = element;\r
- api_queue->tail = element;\r
- }else{\r
- api_queue->tail->previous = element;\r
- api_queue->tail = element;\r
- }\r
- api_queue->size++;\r
- ReleaseMutex(api_queue->api_queue_mutex);\r
- return API_Q_SUCCESS;\r
-}\r
-\r
-static __inline int api_dequeue( api_queue_t* api_queue,\r
- TX_RX_DATA_STRUCT* destination)\r
-{\r
- api_queue_element_t *element;\r
- DWORD mresult;\r
-\r
- mresult = WaitForSingleObject(api_queue->api_queue_mutex, API_Q_MUTEX_TIMEOUT);\r
- if (mresult != WAIT_OBJECT_0) {\r
- return API_Q_GEN_FAILURE;\r
- }\r
-\r
- if(api_queue->size == 0){\r
- //tx queue is empty\r
- ReleaseMutex(api_queue->api_queue_mutex);\r
- return API_Q_EMPTY;\r
- }\r
-\r
- //remove from the head of the queue\r
- element = api_queue->head;\r
- api_queue->head = element->previous;\r
-\r
- //now copy everything in to the user buffer\r
- memcpy(destination, &element->tx_rx_data, sizeof(TX_DATA_STRUCT));\r
-\r
- free(element);\r
- api_queue->size--;\r
- if(api_queue->size == 0){\r
- api_queue->head = NULL;\r
- api_queue->tail = NULL;\r
- }\r
- ReleaseMutex(api_queue->api_queue_mutex);\r
- return API_Q_SUCCESS;\r
-}\r
-\r
-//remove all elements from the queue\r
-static __inline void empty_api_queue(api_queue_t* api_queue)\r
-{\r
- TX_DATA_STRUCT tx_rx_data;\r
-\r
- while(api_dequeue(api_queue, &tx_rx_data) == 0){\r
- ;\r
- }\r
-}\r
-\r
-///////////////////////////////////////////////////////////////////////////\r
-#endif /* _WIN_API_COMMON_H */\r
+static api_tx_hdr_t *tx_hdr = (api_tx_hdr_t *)api_cmd.data;
+
+/* keeps the LAST (and single) event received */
+static wp_tdm_api_rx_hdr_t last_tdm_api_event_buffer;
+#endif
+
+#ifdef __WINDOWS__
+static int tdmv_api_ioctl(sng_fd_t fd, wanpipe_tdm_api_cmd_t *tdm_api_cmd)
+{
+ DWORD ln;
+ unsigned char id = 0;
+ int err = 0;
+
+ wan_udp.wan_udphdr_request_reply = 0x01;
+ wan_udp.wan_udphdr_id = id;
+ wan_udp.wan_udphdr_return_code = WAN_UDP_TIMEOUT_CMD;
+
+ wan_udp.wan_udphdr_command = WAN_TDMV_API_IOCTL;
+ wan_udp.wan_udphdr_data_len = sizeof(wanpipe_tdm_api_cmd_t);
+
+ //copy data from caller's buffer to driver's buffer
+ memcpy( wan_udp.wan_udphdr_data,
+ (void*)tdm_api_cmd,
+ sizeof(wanpipe_tdm_api_cmd_t));
+
+ if(DeviceIoControl(
+ fd,
+ IoctlManagementCommand,
+ (LPVOID)&wan_udp,
+ sizeof(wan_udp_hdr_t),
+ (LPVOID)&wan_udp,
+ sizeof(wan_udp_hdr_t),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL
+ ) == FALSE){
+ //actual ioctl failed
+ err = 1;
+ return err;
+ }else{
+ err = 0;
+ }
+
+ if(wan_udp.wan_udphdr_return_code != WAN_CMD_OK){
+ //ioctl ok, but command failed
+ return 2;
+ }
+
+ //copy data from driver's buffer to caller's buffer
+ memcpy( (void*)tdm_api_cmd,
+ wan_udp.wan_udphdr_data,
+ sizeof(wanpipe_tdm_api_cmd_t));
+ return 0;
+}
+
+#else
+static int tdmv_api_ioctl(sng_fd_t fd, wanpipe_tdm_api_cmd_t *tdm_api_cmd)
+{
+ return ioctl(fd, SIOC_WANPIPE_TDM_API, tdm_api_cmd);
+}
+#endif
+
+static sng_fd_t tdmv_api_open_span_chan(int span, int chan)
+{
+ char fname[FNAME_LEN];
+#if defined(__WINDOWS__)
+
+ //NOTE: under Windows Interfaces are zero based but 'chan' is 1 based.
+ // Subtract 1 from 'chan'.
+ _snprintf(fname , FNAME_LEN, "\\\\.\\WANPIPE%d_IF%d", span, chan - 1);
+
+ //prn(verbose, "Opening device: %s...\n", fname);
+
+ return CreateFile( fname,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ (LPSECURITY_ATTRIBUTES)NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
+ (HANDLE)NULL
+ );
+#else
+ int fd = WP_INVALID_SOCKET;
+
+ sprintf(fname,"/dev/wptdm_s%dc%d",span,chan);
+
+ fd = open(fname, O_RDWR);
+
+ if (fd < 0) {
+ fd = WP_INVALID_SOCKET;
+ }
+
+ return fd;
+#endif
+}
+
+#ifdef __WINDOWS__
+static int wanpipe_api_ioctl(sng_fd_t fd, wan_cmd_api_t *api_cmd)
+{
+ DWORD ln;
+ unsigned char id = 0;
+ int err = 0;
+
+ wan_udp.wan_udphdr_request_reply = 0x01;
+ wan_udp.wan_udphdr_id = id;
+ wan_udp.wan_udphdr_return_code = WAN_UDP_TIMEOUT_CMD;
+
+ wan_udp.wan_udphdr_command = SIOC_WANPIPE_API;
+ wan_udp.wan_udphdr_data_len = sizeof(wan_cmd_api_t);
+
+ //copy data from caller's buffer to driver's buffer
+ memcpy( wan_udp.wan_udphdr_data,
+ (void*)api_cmd,
+ sizeof(wan_cmd_api_t));
+
+ if(DeviceIoControl(
+ fd,
+ IoctlManagementCommand,
+ (LPVOID)&wan_udp,
+ sizeof(wan_udp_hdr_t),
+ (LPVOID)&wan_udp,
+ sizeof(wan_udp_hdr_t),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL
+ ) == FALSE){
+ err = 1;
+ return err;
+ }else{
+ err = 0;
+ }
+
+ if(wan_udp.wan_udphdr_return_code != WAN_CMD_OK){
+ return 2;
+ }
+
+ //copy data from driver's buffer to caller's buffer
+ memcpy( (void*)api_cmd,
+ wan_udp.wan_udphdr_data,
+ sizeof(wan_cmd_api_t));
+ return 0;
+}
+
+// Blocking read command. If used after DoApiPollCommand(),
+// it will return immediatly, without blocking.
+static
+USHORT
+DoReadCommand(
+ sng_fd_t drv,
+ RX_DATA_STRUCT * pRx
+ )
+{
+ DWORD ln;
+
+ if (DeviceIoControl(
+ drv,
+ IoctlReadCommand,
+ (LPVOID)NULL,
+ 0L,
+ (LPVOID)pRx,
+ sizeof(RX_DATA_STRUCT),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL
+ ) == FALSE){
+ //check messages log
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
+// Blocking write command. If used after DoApiPollCommand(),
+// it will return immediatly, without blocking.
+static
+UCHAR
+DoWriteCommand(
+ sng_fd_t drv,
+ TX_DATA_STRUCT * pTx
+ )
+{
+ DWORD ln;
+
+ if(DeviceIoControl(
+ drv,
+ IoctlWriteCommand,
+ (LPVOID)pTx,
+ (ULONG)sizeof(TX_DATA_STRUCT),
+ (LPVOID)pTx,
+ sizeof(TX_DATA_STRUCT),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL
+ ) == FALSE){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
+// Blocking API Poll command.
+static
+USHORT
+DoApiPollCommand(
+ sng_fd_t drv,
+ API_POLL_STRUCT *api_poll_ptr
+ )
+{
+ DWORD ln;
+
+ if (DeviceIoControl(
+ drv,
+ IoctlApiPoll,
+ (LPVOID)NULL,
+ 0L,
+ (LPVOID)api_poll_ptr,
+ sizeof(API_POLL_STRUCT),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL
+ ) == FALSE){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
+static
+int
+DoManagementCommand(
+ sng_fd_t drv,
+ wan_udp_hdr_t* wan_udp
+ )
+{
+ DWORD ln;
+ static unsigned char id = 0;
+
+ wan_udp->wan_udphdr_request_reply = 0x01;
+ wan_udp->wan_udphdr_id = id++;
+ wan_udp->wan_udphdr_return_code = WAN_UDP_TIMEOUT_CMD;
+
+ if(DeviceIoControl(
+ drv,
+ IoctlManagementCommand,
+ (LPVOID)wan_udp,
+ sizeof(wan_udp_hdr_t),
+ (LPVOID)wan_udp,
+ sizeof(wan_udp_hdr_t),
+ (LPDWORD)(&ln),
+ (LPOVERLAPPED)NULL
+ ) == FALSE){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+//structures and definitions used for queueing data
+//
+typedef struct
+{
+ void* previous;
+ TX_RX_DATA_STRUCT tx_rx_data;
+}api_queue_element_t;
+
+#define API_Q_MUTEX_TIMEOUT 1000//1 second
+#define API_Q_MAX_SIZE 100//optimal length. for short data may need longer queue
+
+enum API_Q_STATUS{
+ API_Q_SUCCESS=0,
+ API_Q_GEN_FAILURE,
+ API_Q_MEM_ALLOC_FAILURE,
+ API_Q_FULL,
+ API_Q_EMPTY
+};
+
+typedef struct
+{
+ //number of nodes in the list
+ USHORT size;
+ //insert at tail
+ api_queue_element_t * tail;
+ //remove from head
+ api_queue_element_t * head;
+ //mutex for synchronizing access to the queue
+ sng_fd_t api_queue_mutex;
+}api_queue_t;
+
+
+static __inline int api_enqueue( api_queue_t* api_queue,
+ unsigned char * buffer,
+ unsigned short length)
+{
+ api_queue_element_t *element;
+ DWORD mresult;
+
+ mresult = WaitForSingleObject(api_queue->api_queue_mutex, API_Q_MUTEX_TIMEOUT);
+ if (mresult != WAIT_OBJECT_0) {
+ return API_Q_GEN_FAILURE;
+ }
+
+ if(api_queue->size == API_Q_MAX_SIZE){
+ ReleaseMutex(api_queue->api_queue_mutex);
+ return API_Q_FULL;
+ }
+
+ element = malloc(sizeof(api_queue_element_t));
+ if(element == NULL){
+ ReleaseMutex(api_queue->api_queue_mutex);
+ return API_Q_MEM_ALLOC_FAILURE;
+ }
+
+ //now copy everything in to the element
+ memcpy(element->tx_rx_data.data, buffer, length);
+
+ element->tx_rx_data.api_header.data_length = length;
+ element->tx_rx_data.api_header.operation_status = SANG_STATUS_TX_TIMEOUT;
+
+ //insert element at the tail of the queue
+ element->previous = NULL;
+
+ if(api_queue->size == 0){
+ //special case of a previously empty queue
+ api_queue->head = element;
+ api_queue->tail = element;
+ }else{
+ api_queue->tail->previous = element;
+ api_queue->tail = element;
+ }
+ api_queue->size++;
+ ReleaseMutex(api_queue->api_queue_mutex);
+ return API_Q_SUCCESS;
+}
+
+static __inline int api_dequeue( api_queue_t* api_queue,
+ TX_RX_DATA_STRUCT* destination)
+{
+ api_queue_element_t *element;
+ DWORD mresult;
+
+ mresult = WaitForSingleObject(api_queue->api_queue_mutex, API_Q_MUTEX_TIMEOUT);
+ if (mresult != WAIT_OBJECT_0) {
+ return API_Q_GEN_FAILURE;
+ }
+
+ if(api_queue->size == 0){
+ //tx queue is empty
+ ReleaseMutex(api_queue->api_queue_mutex);
+ return API_Q_EMPTY;
+ }
+
+ //remove from the head of the queue
+ element = api_queue->head;
+ api_queue->head = element->previous;
+
+ //now copy everything in to the user buffer
+ memcpy(destination, &element->tx_rx_data, sizeof(TX_DATA_STRUCT));
+
+ free(element);
+ api_queue->size--;
+ if(api_queue->size == 0){
+ api_queue->head = NULL;
+ api_queue->tail = NULL;
+ }
+ ReleaseMutex(api_queue->api_queue_mutex);
+ return API_Q_SUCCESS;
+}
+
+//remove all elements from the queue
+static __inline void empty_api_queue(api_queue_t* api_queue)
+{
+ TX_DATA_STRUCT tx_rx_data;
+
+ while(api_dequeue(api_queue, &tx_rx_data) == 0){
+ ;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+#endif
+
+#endif /* _SANGOMA_TDM_API_H */