diff --git a/divastreaming/diva_segment_alloc_ifc.h b/divastreaming/diva_segment_alloc_ifc.h new file mode 100644 index 0000000..af8bb76 --- /dev/null +++ b/divastreaming/diva_segment_alloc_ifc.h @@ -0,0 +1,46 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __DIVA_SEGMENT_ALLOC_H__ +#define __DIVA_SEGMENT_ALLOC_H__ + +struct _diva_segment_alloc; +struct _diva_segment_alloc_access; + +typedef struct _diva_segment_alloc_access { + void (*release)(struct _diva_segment_alloc** ifc); + void* (*segment_alloc)(struct _diva_segment_alloc* ifc, dword* lo, dword* hi); + void (*segment_free)(struct _diva_segment_alloc* ifc, void* addr, dword lo, dword hi); + dword (*get_segment_length)(struct _diva_segment_alloc* ifc); + void* (*map_address)(struct _diva_segment_alloc* ifc, dword lo, dword hi); + void* (*umap_address)(struct _diva_segment_alloc* ifc, dword lo, dword hi, void* local); + int (*write_address)(struct _diva_segment_alloc* ifc, dword lo, dword hi, dword data); + void (*resource_removed)(struct _diva_segment_alloc* ifc); +} diva_segment_alloc_access_t; + +int diva_create_segment_alloc (void* os_context, struct _diva_segment_alloc** segment_alloc); +int diva_destroy_segment_alloc (struct _diva_segment_alloc** segment_alloc); +diva_segment_alloc_access_t* diva_get_segment_alloc_ifc (struct _diva_segment_alloc* segment_alloc); + +#endif diff --git a/divastreaming/diva_streaming_idi_host_ifc.h b/divastreaming/diva_streaming_idi_host_ifc.h new file mode 100644 index 0000000..0c5448b --- /dev/null +++ b/divastreaming/diva_streaming_idi_host_ifc.h @@ -0,0 +1,83 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __DIVA_STREAMING_IDI_HOST_IFC__ +#define __DIVA_STREAMING_IDI_HOST_IFC__ + +/* + Write data from host to remote side + */ +struct _diva_stream; +struct _diva_segment_alloc_ifc; +struct _diva_streaming_idi_host_ifc_w; +struct _diva_streaming_idi_host_ifc_w_access; +struct _diva_streaming_idi_host_ifc_r; +struct _diva_streaming_idi_host_ifc_r_access; + + +typedef struct _diva_streaming_idi_host_ifc_w_access { + int (*release)(struct _diva_streaming_idi_host_ifc_w* ifc); + diva_streaming_idi_result_t (*release_stream)(struct _diva_streaming_idi_host_ifc_w* ifc); + int (*write_message)(struct _diva_streaming_idi_host_ifc_w* ifc, + dword info, const void* data, dword data_length); + int (*ack)(struct _diva_streaming_idi_host_ifc_w* ifc, dword length); + int (*ack_rx)(struct _diva_streaming_idi_host_ifc_w* ifc, dword length, int flush_ack); + int (*write)(struct _diva_streaming_idi_host_ifc_w* ifc, const void* data, dword data_length); + int (*write_indirect)(struct _diva_streaming_idi_host_ifc_w* ifc, dword lo, dword hi, dword length); + int (*update_remote)(struct _diva_streaming_idi_host_ifc_w* ifc); + dword (*get_in_use)(struct _diva_streaming_idi_host_ifc_w* ifc); + dword (*get_free)(struct _diva_streaming_idi_host_ifc_w* ifc); + dword (*get_length)(struct _diva_streaming_idi_host_ifc_w* ifc); + byte (*description)(struct _diva_streaming_idi_host_ifc_w* ifc, byte* dst, byte max_length); + int (*init)(struct _diva_streaming_idi_host_ifc_w* ifc, dword version, dword counter); + diva_streaming_idi_result_t (*sync)(struct _diva_streaming_idi_host_ifc_w* ifc, dword ident); + diva_streaming_idi_result_t (*trace_ident)(struct _diva_streaming_idi_host_ifc_w* ifc); +} diva_streaming_idi_host_ifc_w_access_t; + +int diva_streaming_idi_host_ifc_create (struct _diva_streaming_idi_host_ifc_w** ifc, + dword number_segments, + struct _diva_segment_alloc* segment_alloc, + const char* trace_ident); +struct _diva_streaming_idi_host_ifc_w_access* diva_streaming_idi_host_ifc_get_access ( + struct _diva_streaming_idi_host_ifc_w* ifc); + +typedef struct _diva_streaming_idi_host_ifc_r_access { + int (*release)(struct _diva_streaming_idi_host_ifc_r* ifc); + int (*wakeup)(struct _diva_streaming_idi_host_ifc_r* ifc); + byte (*description)(struct _diva_streaming_idi_host_ifc_r* ifc, byte* dst, byte max_length); +} diva_streaming_idi_host_ifc_r_access_t; + +int diva_streaming_idi_host_rx_ifc_create (struct _diva_streaming_idi_host_ifc_r** ifc, + dword number_segments, + struct _diva_segment_alloc* segment_alloc, + struct _diva_streaming_idi_host_ifc_w* tx, + struct _diva_streaming_idi_host_ifc_w_access* tx_ifc, + diva_streaming_idi_rx_notify_user_proc_t notify_user_proc, + void* user_context, + struct _diva_stream* diva_streaming_manager_ifc, + const char* trace_ident); +struct _diva_streaming_idi_host_ifc_r_access* diva_streaming_idi_host_rx_ifc_get_access ( + struct _diva_streaming_idi_host_ifc_r* ifc); + +#endif diff --git a/divastreaming/diva_streaming_idi_host_ifc_impl.c b/divastreaming/diva_streaming_idi_host_ifc_impl.c new file mode 100644 index 0000000..33003c9 --- /dev/null +++ b/divastreaming/diva_streaming_idi_host_ifc_impl.c @@ -0,0 +1,427 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + * vim:ts=2: + */ +#include "platform.h" +#include "pc.h" +#include "diva_streaming_result.h" +#include "diva_streaming_vector.h" +#include "diva_streaming_messages.h" +#include "diva_streaming_manager.h" +#include "diva_streaming_result.h" +#include "diva_segment_alloc_ifc.h" +#include "diva_streaming_idi_host_ifc.h" +#include "diva_streaming_idi_host_ifc_impl.h" +#include "spi_descriptor.h" + +static int diva_streaming_idi_host_ifc_cleanup (struct _diva_streaming_idi_host_ifc_w* ifc); +static int write_message (struct _diva_streaming_idi_host_ifc_w* ifc, + dword info, + const void* data, + dword data_length); +static byte description (diva_streaming_idi_host_ifc_w_t* ifc, byte* dst, byte max_length); +static int init (struct _diva_streaming_idi_host_ifc_w* ifc, dword version, dword counter); +static diva_streaming_idi_result_t sync_req (struct _diva_streaming_idi_host_ifc_w* ifc, dword ident); +static int ack_data (struct _diva_streaming_idi_host_ifc_w* ifc, dword length); +static int ack_rx_data (struct _diva_streaming_idi_host_ifc_w* ifc, dword length, int flush_ack); +static int write_data (struct _diva_streaming_idi_host_ifc_w* ifc, const void* data, dword data_length); +static int write_indirect (struct _diva_streaming_idi_host_ifc_w* ifc, dword lo, dword hi, dword length); +static int update_remote (struct _diva_streaming_idi_host_ifc_w* ifc); +static dword get_in_use (struct _diva_streaming_idi_host_ifc_w* ifc); +static dword get_free (struct _diva_streaming_idi_host_ifc_w* ifc); +static dword get_length (struct _diva_streaming_idi_host_ifc_w* ifc); +static void write_buffer (diva_streaming_idi_host_ifc_w_t* ifc, const void* data, dword data_length); +static void update_write_buffer (diva_streaming_idi_host_ifc_w_t* ifc); +static diva_streaming_idi_result_t set_trace_ident (struct _diva_streaming_idi_host_ifc_w* ifc); +static diva_streaming_idi_result_t release_stream (struct _diva_streaming_idi_host_ifc_w* ifc); + + +int diva_streaming_idi_host_ifc_create (struct _diva_streaming_idi_host_ifc_w** ifc, + dword number_segments, + struct _diva_segment_alloc* segment_alloc, + const char* trace_ident) { + struct _diva_streaming_idi_host_ifc_w* ifc_w = *ifc; + diva_segment_alloc_access_t* segment_alloc_access = diva_get_segment_alloc_ifc (segment_alloc); + dword i; + int free_ifc = 0; + + if (ifc_w == 0) { + ifc_w = diva_os_malloc (0, sizeof(*ifc_w)); + free_ifc = 1; + } + + if (ifc_w == 0) { + DBG_ERR(("failed to create idi w interface [%s]", trace_ident)) + return (-1); + } + + memset (ifc_w, 0x00, sizeof(*ifc_w)); + memcpy(ifc_w->trace_ident, trace_ident, MIN(strlen(trace_ident), DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH)); + ifc_w->trace_ident[DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH] = 0; + + ifc_w->nr_segments = MIN(number_segments, DIVA_STREAMING_IDI_HOST_IFC_MAX_SEGMENTS); + ifc_w->segment_alloc = segment_alloc; + ifc_w->free_ifc = free_ifc; + + for (i = 0; i < ifc_w->nr_segments; i++) { + ifc_w->segments[i] = (*(segment_alloc_access->segment_alloc))(segment_alloc, + &ifc_w->segment_lo[i], + &ifc_w->segment_hi[i]); + if (ifc_w->segments[i] == 0) { + DBG_ERR(("failed to alloc segment [%s]", trace_ident)) + diva_streaming_idi_host_ifc_cleanup (ifc_w); + return (-1); + } + + DBG_TRC(("alloc %p %08x:%08x [%s]", ifc_w->segments[i], ifc_w->segment_lo[i], ifc_w->segment_hi[i], trace_ident)) + + ifc_w->segment_length[i] = (*(segment_alloc_access->get_segment_length))(segment_alloc); + + ifc_w->state.length += ifc_w->segment_length[i]; + } + + ifc_w->ack_rx = 0; + + ifc_w->state.used_length = 0; + ifc_w->state.free_length = ifc_w->state.length; + + ifc_w->state.write_buffer = 0; + ifc_w->state.write_buffer_position = 0; + ifc_w->state.write_buffer_free = ifc_w->segment_length[ifc_w->state.write_buffer]; + + ifc_w->state.acknowledge_buffer = 0; + ifc_w->state.acknowledge_buffer_position = 0; + + ifc_w->remote.written = 0; + + ifc_w->access.release = diva_streaming_idi_host_ifc_cleanup; + ifc_w->access.release_stream = release_stream; + ifc_w->access.write_message = write_message; + ifc_w->access.ack = ack_data; + ifc_w->access.ack_rx = ack_rx_data; + ifc_w->access.write = write_data; + ifc_w->access.write_indirect = write_indirect; + ifc_w->access.update_remote = update_remote; + ifc_w->access.get_in_use = get_in_use; + ifc_w->access.get_free = get_free; + ifc_w->access.get_length = get_length; + ifc_w->access.description = description; + ifc_w->access.init = init; + ifc_w->access.sync = sync_req; + ifc_w->access.trace_ident = set_trace_ident; + + *ifc = ifc_w; + + return (0); +} + +struct _diva_streaming_idi_host_ifc_w_access* diva_streaming_idi_host_ifc_get_access ( + struct _diva_streaming_idi_host_ifc_w* ifc) { + return (&ifc->access); +} + +static int diva_streaming_idi_host_ifc_cleanup (struct _diva_streaming_idi_host_ifc_w* ifc) { + diva_segment_alloc_access_t* segment_alloc_access = diva_get_segment_alloc_ifc (ifc->segment_alloc); + dword i; + + for (i = 0; i < ifc->nr_segments; i++) { + if (ifc->segments[i] != 0) { + (*(segment_alloc_access->segment_free))(ifc->segment_alloc, + ifc->segments[i], + ifc->segment_lo[i], + ifc->segment_hi[i]); + } + } + + if (ifc->remote_counter_mapped_base != 0) { + segment_alloc_access->umap_address (ifc->segment_alloc, ifc->remote_counter_base, 0, ifc->remote_counter_mapped_base); + } + + if (ifc->free_ifc != 0) { + diva_os_free (0, ifc); + } + + return (0); +} + +static void update_write_buffer (diva_streaming_idi_host_ifc_w_t* ifc) { + if (ifc->state.write_buffer_free == 0) { + ifc->state.write_buffer++; + if (ifc->state.write_buffer >= ifc->nr_segments) { + ifc->state.write_buffer = 0; + } + ifc->state.write_buffer_free = ifc->segment_length[ifc->state.write_buffer]; + ifc->state.write_buffer_position = 0; + } +} + +static void write_buffer (diva_streaming_idi_host_ifc_w_t* ifc, const void* data, dword data_length) { + const byte* src = (const byte*)data; + dword to_write = data_length; + + while (data_length != 0) { + dword to_copy = MIN(ifc->state.write_buffer_free, data_length); + memcpy (ifc->segments[ifc->state.write_buffer]+ifc->state.write_buffer_position, src, to_copy); + src += to_copy; + ifc->state.write_buffer_position += to_copy; + ifc->state.write_buffer_free -= to_copy; + data_length -= to_copy; + update_write_buffer (ifc); + } + + ifc->state.free_length -= to_write; + ifc->state.used_length += to_write; + ifc->remote.written += ((int32)to_write); +} + +static void align_write_buffer (diva_streaming_idi_host_ifc_w_t* ifc, dword data_length) { + dword to_write = data_length; + + while (data_length != 0) { + dword to_copy = MIN(ifc->state.write_buffer_free, data_length); + ifc->state.write_buffer_position += to_copy; + ifc->state.write_buffer_free -= to_copy; + data_length -= to_copy; + update_write_buffer (ifc); + } + + ifc->state.free_length -= to_write; + ifc->state.used_length += to_write; + ifc->remote.written += ((int32)to_write); +} + +static int write_message (struct _diva_streaming_idi_host_ifc_w* ifc, + dword info, + const void* data, + dword data_length) { + dword idi_header_length = ((info & 0xff) == DIVA_STREAM_MESSAGE_TX_IDI_REQUEST && (info & DIVA_STREAMING_IDI_SYSTEM_MESSAGE) == 0) ? (sizeof(diva_spi_msg_hdr_t)+1) : 0; + dword length = data_length + idi_header_length + 2 * sizeof(dword); /* data length + message length + info */ + dword required_length = (length + 31) & ~31; + byte tmp[sizeof(dword)+1]; + byte Req = 0; + + if (required_length > get_free (ifc)) { + return (0); + } + + WRITE_DWORD(tmp, data_length + idi_header_length + sizeof(dword)); /* Write message length without length dword */ + write_buffer (ifc, tmp, sizeof(dword)); + + if ((info & DIVA_STREAMING_IDI_SYSTEM_MESSAGE) == 0) { + switch (info & 0xff) { + case DIVA_STREAM_MESSAGE_TX_IDI_REQUEST: { + dword ack_info = (word)ifc->ack_rx; + Req = (byte)(info >> 8); + info = DIVA_STREAMING_IDI_TX_REQUEST | (ack_info << 8); + ifc->ack_rx -= ack_info; + } break; + } + } + + WRITE_DWORD(tmp, info); + write_buffer (ifc, tmp, sizeof(dword)); /* Write info */ + + if (idi_header_length != 0) { + diva_spi_msg_hdr_t* hdr = (diva_spi_msg_hdr_t*)tmp; + dword message_length = data_length + idi_header_length; + byte* message_data = (byte*)&hdr[1]; + + hdr->Id = 0; + hdr->Ind = Req; + hdr->length_lo = (byte)message_length; + hdr->length_hi = (byte)(message_length >> 8); + message_data[0] = 0; + + write_buffer (ifc, hdr, idi_header_length); + } + + write_buffer (ifc, data, data_length); /* Write data */ + + align_write_buffer (ifc, required_length - length); /* Move to next message */ + + return (data_length); +} + +static int ack_data (struct _diva_streaming_idi_host_ifc_w* ifc, dword length) { + if (length > get_in_use (ifc)) { + DBG_ERR(("ack error ack:%u in use:%u free:%u [%s]", length, get_in_use (ifc), ifc->state.free_length, ifc->trace_ident)) + return (-1); + } + + ifc->state.free_length += length; + ifc->state.used_length -= length; + + return (0); +} + +static int ack_rx_data (struct _diva_streaming_idi_host_ifc_w* ifc, dword length, int flush_ack) { + flush_ack |= (ifc->ack_rx != 0); + + ifc->ack_rx += length; + + while (flush_ack != 0 && ifc->ack_rx != 0 && get_free (ifc) > 128) { + dword info = (word)ifc->ack_rx; + + ifc->ack_rx -= info; + info = ((dword)DIVA_STREAMING_IDI_RX_ACK_MSG) | (info << 8) | DIVA_STREAMING_IDI_SYSTEM_MESSAGE; + + write_message (ifc, info, 0, 0); + update_remote (ifc); + } + + return (0); +} + +static byte description (diva_streaming_idi_host_ifc_w_t* ifc, byte* dst, byte max_length) { + byte length = 0; + dword i; + + DBG_TRC(("tx description %u segments [%s]", ifc->nr_segments, ifc->trace_ident)) + + dst[length++] = (byte)(ifc->nr_segments); + + for (i = 0; i < ifc->nr_segments; i++) { + DBG_TRC((" tx lo[%u] %08x [%s]", i, ifc->segment_lo[i], ifc->trace_ident)) + WRITE_DWORD(&dst[length], ifc->segment_lo[i]); + length += sizeof(dword); + } + for (i = 0; i < ifc->nr_segments; i++) { + DBG_TRC((" tx hi[%u] %08x [%s]", i, ifc->segment_hi[i], ifc->trace_ident)) + WRITE_DWORD(&dst[length], ifc->segment_hi[i]); + length += sizeof(dword); + } + for (i = 0; i < ifc->nr_segments; i++) { + DBG_TRC((" length[%u] %u [%s]", i, ifc->segment_length[i], ifc->trace_ident)) + WRITE_DWORD(&dst[length], ifc->segment_length[i]); + length += sizeof(dword); + } + + return (length); +} + +static int init (struct _diva_streaming_idi_host_ifc_w* ifc, dword version, dword counter) { + diva_segment_alloc_access_t* segment_alloc_access = diva_get_segment_alloc_ifc (ifc->segment_alloc); + + ifc->remote_counter_offset = counter % (4*1024); + ifc->remote_counter_base = counter - ifc->remote_counter_offset; + + ifc->remote_counter_mapped_base = segment_alloc_access->map_address (ifc->segment_alloc, ifc->remote_counter_base, 0); + if (ifc->remote_counter_mapped_base != 0) { + byte* p = ifc->remote_counter_mapped_base; + ifc->remote_counter_mapped = (dword*)&p[ifc->remote_counter_offset]; + } else { + DBG_TRC(("use system call [%s]", ifc->trace_ident)) + } + + return (0); +} + +static diva_streaming_idi_result_t sync_req (struct _diva_streaming_idi_host_ifc_w* ifc, dword ident) { + if (get_free (ifc) > 128) { + dword data[2]; + + DBG_TRC(("sync request %08x [%s]", ident, ifc->trace_ident)) + + data[0] = ident; + data[1] = 0; + + write_message (ifc, DIVA_STREAMING_IDI_SYNC_REQ|DIVA_STREAMING_IDI_SYSTEM_MESSAGE, data, sizeof(data)); + update_remote (ifc); + + return (DivaStreamingIdiResultOK); + } else { + return (DivaStreamingIdiResultBusy); + } +} + +static diva_streaming_idi_result_t set_trace_ident (struct _diva_streaming_idi_host_ifc_w* ifc) { + if (get_free (ifc) > 128) { + dword data[2]; + DBG_TRC(("set trace ident [%s]", ifc->trace_ident)) + + memcpy (data, ifc->trace_ident, sizeof(data[0])); + data[1] = 0; + + write_message (ifc, DIVA_STREAMING_IDI_SET_DEBUG_IDENT|DIVA_STREAMING_IDI_SYSTEM_MESSAGE, data, sizeof(data)); + update_remote (ifc); + + return (DivaStreamingIdiResultOK); + } else { + return (DivaStreamingIdiResultBusy); + } +} + +static diva_streaming_idi_result_t release_stream (struct _diva_streaming_idi_host_ifc_w* ifc) { + dword data[1]; + int ret; + + DBG_LOG(("stream release [%s]", ifc->trace_ident)) + + data[0] = 0; + + ret = write_message (ifc, DIVA_STREAMING_IDI_RELEASE|DIVA_STREAMING_IDI_SYSTEM_MESSAGE, data, sizeof(data)); + update_remote (ifc); + + return (ret != 0 ? DivaStreamingIdiResultOK : DivaStreamingIdiResultBusy); +} + +static int write_data (struct _diva_streaming_idi_host_ifc_w* ifc, const void* data, dword data_length) { + return (-1); +} + +static int write_indirect (struct _diva_streaming_idi_host_ifc_w* ifc, dword lo, dword hi, dword length) { + return (-1); +} + +static int update_remote (struct _diva_streaming_idi_host_ifc_w* ifc) { + int ret = 0; + + if (ifc->remote_counter_mapped != 0) { + ifc->remote_counter_mapped[0] = ifc->remote.written; + } else { + diva_segment_alloc_access_t* segment_alloc_access = diva_get_segment_alloc_ifc (ifc->segment_alloc); + + ret = segment_alloc_access->write_address (ifc->segment_alloc, + ifc->remote_counter_base + ifc->remote_counter_offset, + 0, + ifc->remote.written); + } + + return (ret); +} + +static dword get_in_use (struct _diva_streaming_idi_host_ifc_w* ifc) { + return (ifc->state.used_length); +} + +static dword get_free (struct _diva_streaming_idi_host_ifc_w* ifc) { + return (ifc->state.free_length); +} + +static dword get_length (struct _diva_streaming_idi_host_ifc_w* ifc) { + return (ifc->state.length); +} + diff --git a/divastreaming/diva_streaming_idi_host_ifc_impl.h b/divastreaming/diva_streaming_idi_host_ifc_impl.h new file mode 100644 index 0000000..74613b7 --- /dev/null +++ b/divastreaming/diva_streaming_idi_host_ifc_impl.h @@ -0,0 +1,75 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __DIVA_STREAMING_IDI_HOST_IFC_IMPL_H__ +#define __DIVA_STREAMING_IDI_HOST_IFC_IMPL_H__ + +struct _diva_segment_alloc_ifc; +struct _diva_streaming_idi_host_ifc_w_access; +struct _diva_streaming_idi_host_ifc_w; + +#define DIVA_STREAMING_IDI_HOST_IFC_MAX_SEGMENTS 8 +typedef struct _diva_streaming_idi_host_ifc_w { + struct _diva_streaming_idi_host_ifc_w_access access; + + byte* segments[DIVA_STREAMING_IDI_HOST_IFC_MAX_SEGMENTS]; /**< buffer segments */ + dword segment_length[DIVA_STREAMING_IDI_HOST_IFC_MAX_SEGMENTS]; /**< length of every segment */ + dword segment_lo[DIVA_STREAMING_IDI_HOST_IFC_MAX_SEGMENTS]; + dword segment_hi[DIVA_STREAMING_IDI_HOST_IFC_MAX_SEGMENTS]; + dword nr_segments; /**< number of available segments */ + + struct _diva_segment_alloc* segment_alloc; + + struct { + dword length; /**< overall length including all segments */ + dword used_length; /**< overall written and not acknowledged */ + dword free_length; /**< overall length available */ + + dword write_buffer; /**< current write segment buffer */ + dword write_buffer_position; /**< position in write segment */ + dword write_buffer_free; /**< free space in write segment */ + + dword acknowledge_buffer; /**< acknowledge segment */ + dword acknowledge_buffer_position; /**< position in acknowledge segment */ + dword acknowledge_buffer_free; + } state; + + struct { + int32 written; /**< incremented every time data written by amount of data written in the buffer and + written to opposite side */ + } remote; + + dword remote_counter_base; /* Remote counter page BUS address */ + dword remote_counter_offset; /* Remote counter offset from page start */ + void* remote_counter_mapped_base; /* Remote counter page BUS address mapped */ + volatile dword* remote_counter_mapped; /* Remote counter mapped */ + + dword ack_rx; + + int free_ifc; + + char trace_ident[DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH+1]; +} diva_streaming_idi_host_ifc_w_t; + +#endif diff --git a/divastreaming/diva_streaming_idi_host_rx_ifc_impl.c b/divastreaming/diva_streaming_idi_host_rx_ifc_impl.c new file mode 100644 index 0000000..9617c83 --- /dev/null +++ b/divastreaming/diva_streaming_idi_host_rx_ifc_impl.c @@ -0,0 +1,400 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + * vim:ts=2: + */ +#include "platform.h" +#include "pc.h" +#include "diva_streaming_vector.h" +#include "diva_streaming_messages.h" +#include "diva_streaming_result.h" +#include "diva_streaming_manager.h" +#include "diva_streaming_result.h" +#include "diva_segment_alloc_ifc.h" +#include "diva_streaming_idi_host_ifc.h" +#include "diva_streaming_idi_host_rx_ifc_impl.h" + +/* + * LOCALS + */ +static void update_buffer (struct _diva_streaming_idi_host_ifc_r* ifc); +static void align_buffer (struct _diva_streaming_idi_host_ifc_r* ifc, dword length, diva_streaming_vector_t* v, dword* nr_v); +static int diva_streaming_idi_host_rx_data (struct _diva_streaming_idi_host_ifc_r* ifc, dword length); +static dword copy_message_data (byte* dst, const diva_streaming_vector_t* v, dword nr_v); +static int diva_streaming_idi_host_rx_process_message (struct _diva_streaming_idi_host_ifc_r* ifc, + dword message, + dword data_length, + const diva_streaming_vector_t* v, dword nr_v); +static byte description (diva_streaming_idi_host_ifc_r_t* ifc, byte* dst, byte max_length); +static int diva_streaming_idi_host_rx_ifc_rx (struct _diva_streaming_idi_host_ifc_r* ifc); +static int diva_streaming_idi_host_rx_ifc_cleanup (struct _diva_streaming_idi_host_ifc_r* ifc); + +int diva_streaming_idi_host_rx_ifc_create (struct _diva_streaming_idi_host_ifc_r** ifc, + dword number_segments, + struct _diva_segment_alloc* segment_alloc, + struct _diva_streaming_idi_host_ifc_w* tx, + struct _diva_streaming_idi_host_ifc_w_access* tx_ifc, + diva_streaming_idi_rx_notify_user_proc_t notify_user_proc, + void* user_context, + struct _diva_stream* diva_streaming_manager_ifc, + const char* trace_ident) { + struct _diva_streaming_idi_host_ifc_r* ifc_r = *ifc; + diva_segment_alloc_access_t* segment_access = diva_get_segment_alloc_ifc (segment_alloc); + dword i; + int free_ifc = 0; + + if (ifc_r == 0) { + ifc_r = diva_os_malloc (0, sizeof(*ifc_r)); + free_ifc = 1; + } + + if (ifc_r == 0) { + DBG_ERR(("failed to create idi r interface [%s]", trace_ident)) + return (-1); + } + + memset (ifc_r, 0x00, sizeof(*ifc_r)); + memcpy(ifc_r->trace_ident, trace_ident, MIN(strlen(trace_ident), DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH)); + ifc_r->trace_ident[DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH] = 0; + + ifc_r->nr_segments = MIN(number_segments, DIVA_STREAMING_IDI_HOST_RX_IFC_MAX_SEGMENTS); + ifc_r->segment_alloc = segment_alloc; + ifc_r->free_ifc = free_ifc; + ifc_r->diva_streaming_manager_ifc = diva_streaming_manager_ifc; + + for (i = 0; i < ifc_r->nr_segments; i++) { + ifc_r->segments[i] = (*(segment_access->segment_alloc))(segment_alloc, + &ifc_r->segment_lo[i], + &ifc_r->segment_hi[i]); + if (ifc_r->segments[i] == 0) { + DBG_ERR(("failed to alloc segment [%s]", trace_ident)) + diva_streaming_idi_host_rx_ifc_cleanup (ifc_r); + return (-1); + } + + + DBG_TRC(("alloc %p %08x:%08x [%s]", ifc_r->segments[i], ifc_r->segment_lo[i], ifc_r->segment_hi[i], trace_ident)) + + ifc_r->segment_length[i] = (*(segment_access->get_segment_length))(segment_alloc); + + if (i == 0) { + ifc_r->remote_counter = (int32*)ifc_r->segments[i]; + ifc_r->segments[i] += sizeof(dword); + ifc_r->segment_length[i] -= sizeof(dword); + } + + ifc_r->state.length += ifc_r->segment_length[i]; + } + + ifc_r->remote_counter[0] = 0; + + ifc_r->tx = tx; + ifc_r->tx_ifc = tx_ifc; + ifc_r->notify_user_proc = notify_user_proc; + ifc_r->user_context = user_context; + + ifc_r->current_segment = 0; + ifc_r->current_pos = 0; + ifc_r->current_free = ifc_r->segment_length[ifc_r->current_segment]; + + ifc_r->access.release = diva_streaming_idi_host_rx_ifc_cleanup; + ifc_r->access.wakeup = diva_streaming_idi_host_rx_ifc_rx; + ifc_r->access.description = description; + + *ifc = ifc_r; + + return (0); +} + +struct _diva_streaming_idi_host_ifc_r_access* diva_streaming_idi_host_rx_ifc_get_access ( + struct _diva_streaming_idi_host_ifc_r* ifc) { + return (&ifc->access); +} + +static int diva_streaming_idi_host_rx_ifc_cleanup (struct _diva_streaming_idi_host_ifc_r* ifc) { + diva_segment_alloc_access_t* segment_access = diva_get_segment_alloc_ifc (ifc->segment_alloc); + dword i; + + for (i = 0; i < ifc->nr_segments; i++) { + if (ifc->segments[i] != 0) { + (*(segment_access->segment_free))(ifc->segment_alloc, + ifc->segments[i] - ((i == 0) ? sizeof(dword) : 0), + ifc->segment_lo[i], + ifc->segment_hi[i]); + } + } + + if (ifc->free_ifc != 0) { + diva_os_free (0, ifc); + } + + return (0); +} + +/* + * Receive data + */ +static int diva_streaming_idi_host_rx_ifc_rx (struct _diva_streaming_idi_host_ifc_r* ifc) { + int32 local_counter; + int32 length; + int ret = 0; + int msg_count = 0, ack_ret; + + do { + local_counter = ifc->remote_counter[0]; + length = local_counter - ifc->local_counter; + + if (length != 0) { + ret += length; + ifc->local_counter = local_counter; + ack_ret = diva_streaming_idi_host_rx_data (ifc, length); + if (ifc->released == DIVA_STREAM_MESSAGE_RELEASE_ACK || ifc->released == DIVA_STREAM_MESSAGE_INIT_ERROR) { + if (ifc->notify_user_proc (ifc->user_context, ((dword)ifc->released) << 8 | 0xffU, ifc->released_info, 0, 0) == 0) { + ifc->diva_streaming_manager_ifc->release(ifc->diva_streaming_manager_ifc); + } else { + ifc->released = DIVA_STREAM_MESSAGE_RELEASED; + } + return (0); + } + ifc->tx_ifc->ack_rx (ifc->tx, length, msg_count != 0 || ack_ret == 0); + msg_count++; + } + } while(length != 0); + + return (ret); +} + +static void update_buffer (struct _diva_streaming_idi_host_ifc_r* ifc) { + if (ifc->current_free == 0) { + ifc->current_segment++; + if (ifc->current_segment >= ifc->nr_segments) { + ifc->current_segment = 0; + } + ifc->current_free = ifc->segment_length[ifc->current_segment]; + ifc->current_pos = 0; + } +} + +static void align_buffer (struct _diva_streaming_idi_host_ifc_r* ifc, dword length, diva_streaming_vector_t* v, dword* nr_v) { + while (length != 0) { + dword to_copy = MIN(ifc->current_free, length); + + if (v != 0) { + v[*nr_v].data = ifc->segments[ifc->current_segment] + ifc->current_pos; + v[*nr_v].length = to_copy; + nr_v[0]++; + } + + ifc->current_pos += to_copy; + ifc->current_free -= to_copy; + length -= to_copy; + update_buffer (ifc); + } +} + +static dword copy_message_data (byte* dst, const diva_streaming_vector_t* v, dword nr_v) { + dword i, length; + + for (i = 0, length = 0; i < nr_v; i++) { + memcpy (&dst[length], v[i].data, v[i].length); + length += v[i].length; + } + + return (length); +} + +/* + Return one if processed DIVA_STREAMING_IDI_TX_ACK_MSG + */ +static int diva_streaming_idi_host_rx_process_message (struct _diva_streaming_idi_host_ifc_r* ifc, + dword message, + dword data_length, + const diva_streaming_vector_t* v, dword nr_v) { + int ret = 0; + + switch (message) { + case DIVA_STREAMING_IDI_TX_INIT_MSG: /* Initialization */ + if (data_length != (DIVA_STREAMING_IDI_TX_INIT_MSG_LENGTH - sizeof(dword) - sizeof(word))) { + DBG_ERR(("wrong message length %02x %u [%s]", DIVA_STREAMING_IDI_TX_INIT_MSG, data_length, ifc->trace_ident)) + return (0); + } + { + dword counter; + dword info; + byte version; + + copy_message_data (ifc->system_message, v, nr_v); + + version = ifc->system_message[0]; + counter = READ_DWORD(&ifc->system_message[1]); + info = READ_DWORD(&ifc->system_message[5]); + + DBG_TRC(("version:%u counter:%08x info:%08x [%s]", version, counter, info, ifc->trace_ident)) + + ifc->tx_ifc->init (ifc->tx, version, counter); + ifc->tx_ifc->trace_ident (ifc->tx); + ifc->notify_user_proc (ifc->user_context, DIVA_STREAM_MESSAGE_INIT << 8 | 0xffU, 0, 0, 0); + } + break; + + case DIVA_STREAMING_IDI_TX_ACK_MSG: + if (data_length < (DIVA_STREAMING_IDI_TX_ACK_MSG_LENGTH - sizeof(dword) - sizeof(word))) { + DBG_ERR(("wrong message length %02x %u [%s]", DIVA_STREAMING_IDI_TX_ACK_MSG, data_length, ifc->trace_ident)) + return (0); + } + copy_message_data (ifc->system_message, v, nr_v); + DBG_TRC(("Ind:%02x %u seq:%u [%s]", + DIVA_STREAMING_IDI_TX_ACK_MSG, + ((word)ifc->system_message[0]) | (((word)ifc->system_message[1]) << 8), + ifc->system_message[2], + ifc->trace_ident)) + ifc->tx_ifc->ack (ifc->tx, ((word)ifc->system_message[0]) | (((word)ifc->system_message[1]) << 8)); + ret = 1; + ifc->notify_user_proc (ifc->user_context, DIVA_STREAM_MESSAGE_RX_TX_ACK << 8 | 0xffU, 0, 0, 0); + break; + + case DIVA_STREAMING_IDI_TX_SYNC_ACK: + if (data_length != (DIVA_STREAMING_IDI_TX_SYNC_ACK_LENGTH - sizeof(dword) - sizeof(word))) { + DBG_ERR(("wrong message length %02x %u [%s]", DIVA_STREAMING_IDI_TX_SYNC_ACK, data_length, ifc->trace_ident)) + return (0); + } + copy_message_data (ifc->system_message, v, nr_v); + { + dword ident = READ_DWORD(&ifc->system_message[0]); + DBG_TRC(("sync ack %08x [%s]", ident, ifc->trace_ident)) + + ifc->notify_user_proc (ifc->user_context, DIVA_STREAM_MESSAGE_SYNC_ACK << 8 | 0xffU, ident, 0, 0); + } + break; + + case DIVA_STREAMING_IDI_RELEASE_ACK: + if (data_length != (DIVA_STREAMING_IDI_RELEASE_ACK_LENGTH - sizeof(dword) - sizeof(word))) { + DBG_ERR(("wrong message length %02x %u [%s]", DIVA_STREAMING_IDI_RELEASE_ACK, data_length, ifc->trace_ident)) + return (0); + } + DBG_LOG(("stream release ack [%s]", ifc->trace_ident)) + ifc->released = DIVA_STREAM_MESSAGE_RELEASE_ACK; + ifc->released_info = 0; + break; + + case DIVA_STREAMING_IDI_TX_INIT_ERROR: + if (data_length < DIVA_STREAMING_IDI_TX_INIT_ERROR_LENGTH - sizeof(dword) - sizeof(word) || data_length >= sizeof(ifc->system_message)) { + DBG_ERR(("wrong message length %02x %u [%s]", DIVA_STREAMING_IDI_TX_INIT_ERROR, data_length, ifc->trace_ident)) + } + copy_message_data (ifc->system_message, v, nr_v); + { + dword error = READ_DWORD(&ifc->system_message[0]); + DBG_LOG(("stream init error %08x [%s]", error, ifc->trace_ident)) + ifc->released = DIVA_STREAM_MESSAGE_INIT_ERROR; + ifc->released_info = error; + } + break; + + default: + DBG_ERR(("unknown message %08x %u [%s]", message, data_length, ifc->trace_ident)) + break; + } + + return (ret); +} + +/* + Return one of only one system ack tx message was processed + */ +static int diva_streaming_idi_host_rx_data (struct _diva_streaming_idi_host_ifc_r* ifc, dword length) { + diva_streaming_vector_t v[DIVA_STREAMING_IDI_HOST_RX_IFC_MAX_SEGMENTS+2]; + dword nr_v; + int msg_count = 0, ack_msg = 0; + + + while (length != 0) { + dword hdr = *(dword*)(ifc->segments[ifc->current_segment] + ifc->current_pos); + dword data_length_lo = hdr & 0xffU; + dword data_length_hi = (hdr >> 8) & 0xffU; + dword data_length = data_length_lo | (data_length_hi << 8); + dword message_length = ((data_length + (sizeof(dword)-1)) & ~(sizeof(dword)-1)); + dword message_type = (hdr >> 16) & 0xff; + dword message = (hdr >> 24) & 0xff; + + length -= (message_length + sizeof(dword)-1) & ~(sizeof(dword)-1); + + nr_v = 0; + if (message_type != 0xff && (message & 0x0f) == 0x0f) { + /* + Tx ack sent as part of IDI N_COMBI_IND message + */ + byte tmp[sizeof(dword)+sizeof(word)]; + dword tx_ack; + + align_buffer (ifc, sizeof(dword)+sizeof(word), v, &nr_v); /* Header */ + copy_message_data (tmp, v, nr_v); + tx_ack = ((dword)tmp[4]) | (((dword)tmp[5]) << 8); + + if (tx_ack != 0) { + ifc->tx_ifc->ack (ifc->tx, tx_ack); + ifc->notify_user_proc (ifc->user_context, DIVA_STREAM_MESSAGE_RX_TX_ACK << 8 | 0xffU, 0, 0, 0); + } + + nr_v = 0; + } else { + align_buffer (ifc, sizeof(dword)+sizeof(word), 0, 0); /* Header */ + } + align_buffer (ifc, data_length - sizeof(dword) - sizeof(word), v, &nr_v); + + if (message_type == 0xff) { + ack_msg |= diva_streaming_idi_host_rx_process_message (ifc, message, data_length - sizeof(dword) - sizeof(word), v, nr_v); + if (ifc->released != 0) + return (1); + } else if (nr_v != 0) { + ifc->notify_user_proc (ifc->user_context, message << 8, data_length - sizeof(dword) - sizeof(word), v, nr_v); + } + align_buffer (ifc, message_length - data_length, 0, 0); + msg_count++; + } + + return (msg_count == 1 && ack_msg != 0); +} + +static byte description (diva_streaming_idi_host_ifc_r_t* ifc, byte* dst, byte max_length) { + byte length = 0; + dword i; + + DBG_TRC(("rx description %u segments [%s]", ifc->nr_segments, ifc->trace_ident)) + + for (i = 0; i < ifc->nr_segments; i++) { + DBG_TRC((" rx lo[%u] %08x [%s]", i, ifc->segment_lo[i], ifc->trace_ident)) + WRITE_DWORD(&dst[length], ifc->segment_lo[i]); + length += sizeof(dword); + } + for (i = 0; i < ifc->nr_segments; i++) { + DBG_TRC((" rx hi[%u] %08x [%s]", i, ifc->segment_hi[i], ifc->trace_ident)) + WRITE_DWORD(&dst[length], ifc->segment_hi[i]); + length += sizeof(dword); + } + + return (length); +} + + diff --git a/divastreaming/diva_streaming_idi_host_rx_ifc_impl.h b/divastreaming/diva_streaming_idi_host_rx_ifc_impl.h new file mode 100644 index 0000000..3e0ff8d --- /dev/null +++ b/divastreaming/diva_streaming_idi_host_rx_ifc_impl.h @@ -0,0 +1,76 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __DIVA_STREAMING_IDI_HOST_RX_IFC_IMPL_H__ +#define __DIVA_STREAMING_IDI_HOST_RX_IFC_IMPL_H__ + + +struct _diva_segment_alloc_ifc; +struct _diva_streaming_idi_host_ifc_r_access; +struct _diva_streaming_idi_host_ifc_r; + + +#define DIVA_STREAMING_IDI_HOST_RX_IFC_MAX_SEGMENTS 8 +typedef struct _diva_streaming_idi_host_ifc_r { + struct _diva_streaming_idi_host_ifc_r_access access; + + byte* segments[DIVA_STREAMING_IDI_HOST_RX_IFC_MAX_SEGMENTS]; /**< buffer segments */ + dword segment_length[DIVA_STREAMING_IDI_HOST_RX_IFC_MAX_SEGMENTS]; /**< length of every segment */ + dword segment_lo[DIVA_STREAMING_IDI_HOST_RX_IFC_MAX_SEGMENTS]; + dword segment_hi[DIVA_STREAMING_IDI_HOST_RX_IFC_MAX_SEGMENTS]; + dword nr_segments; /**< number of available segments */ + + volatile int32* remote_counter; /**< updated by remote side, located at begin of first segment */ + volatile int32 local_counter; + + dword current_segment; + dword current_pos; + dword current_free; + + struct _diva_segment_alloc* segment_alloc; + + struct _diva_streaming_idi_host_ifc_w* tx; + struct _diva_streaming_idi_host_ifc_w_access* tx_ifc; + diva_streaming_idi_rx_notify_user_proc_t notify_user_proc; + void* user_context; + + byte system_message[512]; + + int free_ifc; + + struct { + dword length; /**< overall length including all segments */ + } state; + + struct _diva_stream* diva_streaming_manager_ifc; + dword released; + dword released_info; + + char trace_ident[DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH+1]; +} diva_streaming_idi_host_ifc_r_t; + + + + +#endif diff --git a/divastreaming/diva_streaming_manager.c b/divastreaming/diva_streaming_manager.c new file mode 100644 index 0000000..6e675be --- /dev/null +++ b/divastreaming/diva_streaming_manager.c @@ -0,0 +1,355 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include "platform.h" +#include "pc.h" +#include "diva_streaming_result.h" +#include "diva_streaming_vector.h" +#include "diva_streaming_manager.h" +#include "diva_streaming_messages.h" +#include "diva_segment_alloc_ifc.h" +#include "diva_streaming_idi_host_ifc.h" + + +typedef struct _diva_stream_manager { + diva_stream_t ifc; + int user_segment_alloc; + struct _diva_segment_alloc* segment_alloc; + diva_segment_alloc_access_t* segment_alloc_ifc; + struct _diva_streaming_idi_host_ifc_w* tx; + struct _diva_streaming_idi_host_ifc_w_access* tx_ifc; + struct _diva_streaming_idi_host_ifc_r* rx; + struct _diva_streaming_idi_host_ifc_r_access* rx_ifc; + diva_streaming_idi_rx_notify_user_proc_t rx_proc; + void* rx_proc_context; + + byte description[0xff-32]; + + char trace_ident[DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH+1]; +} diva_stream_manager_t; + +/* + * LOCALS + */ +static int message_input_proc (void* user_context, dword message, dword length, const diva_streaming_vector_t* v, dword nr_v); +static diva_streaming_idi_result_t diva_stream_manager_release (struct _diva_stream* ifc); +static diva_streaming_idi_result_t diva_stream_manager_release_stream (struct _diva_stream* ifc); +static diva_streaming_idi_result_t diva_stream_manager_write (struct _diva_stream* ifc, dword message, const void* data, dword length); +static diva_streaming_idi_result_t diva_stream_manager_wakeup (struct _diva_stream* ifc); +static const byte* diva_stream_manager_description (struct _diva_stream* ifc); +static diva_streaming_idi_result_t diva_stream_manager_sync_req (struct _diva_stream* ifc, dword ident); +static diva_streaming_idi_result_t diva_stream_flush (struct _diva_stream* ifc); +static dword diva_stream_get_tx_free (struct _diva_stream* ifc); +static dword diva_stream_get_tx_in_use (struct _diva_stream* ifc); +static void diva_notify_os_resource_removed (struct _diva_stream* ifc); + +diva_streaming_idi_result_t diva_stream_create (struct _diva_stream** ifc, + void* os_context, + dword length, + diva_streaming_idi_rx_notify_user_proc_t rx, + void* rx_context, + const char* trace_ident) { + return (diva_stream_create_with_user_segment_alloc (ifc, os_context, length, rx, rx_context, trace_ident, 0)); +} + +diva_streaming_idi_result_t diva_stream_create_with_user_segment_alloc (struct _diva_stream** ifc, + void* os_context, + dword length, + diva_streaming_idi_rx_notify_user_proc_t rx, + void* rx_context, + const char* trace_ident, + struct _diva_segment_alloc* user_segment_alloc) { + diva_stream_manager_t* pI; + diva_streaming_idi_result_t ret = DivaStreamingIdiResultError; + +#ifdef DIVA_USERMODE + dbg_init ("DIVA STREAM", "109-1", 0); +#endif + + pI = diva_os_malloc (0, sizeof(*pI)); + + if (pI != 0) { + memset (pI, 0x00, sizeof(*pI)); + memcpy(pI->trace_ident, trace_ident, MIN(strlen(trace_ident), DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH)); + pI->trace_ident[DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH] = 0; + + if (user_segment_alloc != 0) { + pI->segment_alloc = user_segment_alloc; + pI->user_segment_alloc = 1; + ret = 0; + } else { + ret = diva_create_segment_alloc (os_context, &pI->segment_alloc); + pI->user_segment_alloc = 0; + } + + if (ret == 0) { + dword number_segments = length/4096 + ((length%4096) != 0); + + pI->segment_alloc_ifc = diva_get_segment_alloc_ifc (pI->segment_alloc); + + ret = diva_streaming_idi_host_ifc_create (&pI->tx, number_segments, pI->segment_alloc, trace_ident); + if (ret == 0) { + pI->tx_ifc = diva_streaming_idi_host_ifc_get_access (pI->tx); + + ret = diva_streaming_idi_host_rx_ifc_create (&pI->rx, number_segments, pI->segment_alloc, pI->tx, pI->tx_ifc, message_input_proc, pI, &pI->ifc, trace_ident); + if (ret == 0) { + pI->rx_ifc = diva_streaming_idi_host_rx_ifc_get_access (pI->rx); + + pI->ifc.release = diva_stream_manager_release; + pI->ifc.release_stream = diva_stream_manager_release_stream; + pI->ifc.write = diva_stream_manager_write; + pI->ifc.wakeup = diva_stream_manager_wakeup; + pI->ifc.description = diva_stream_manager_description; + pI->ifc.sync = diva_stream_manager_sync_req; + pI->ifc.flush_stream = diva_stream_flush; + pI->ifc.get_tx_free = diva_stream_get_tx_free; + pI->ifc.get_tx_in_use = diva_stream_get_tx_in_use; + pI->ifc.notify_os_resource_removed = diva_notify_os_resource_removed; + + pI->rx_proc = rx; + pI->rx_proc_context = rx_context; + + *ifc = &pI->ifc; + ret = DivaStreamingIdiResultOK; + } else { + DBG_ERR(("failed to create rx stream [%s]", trace_ident)) + } + } else { + DBG_ERR(("failed to create tx stream [%s]", trace_ident)) + } + } else { + DBG_ERR(("failed to create segment alloc [%s]", trace_ident)) + } + } + + if (ret != 0) + diva_stream_manager_release (&pI->ifc); + + return (ret); +} + +static int message_input_proc (void* user_context, dword message, dword length, const diva_streaming_vector_t* v, dword nr_v) { + diva_stream_manager_t* pI = (diva_stream_manager_t*)user_context; + + return (pI->rx_proc (pI->rx_proc_context, message, length, v, nr_v)); +} + +static diva_streaming_idi_result_t diva_stream_manager_release (struct _diva_stream* ifc) { + if (ifc != 0) { + diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); + + if (pI->rx != 0) + pI->rx_ifc->release (pI->rx); + if (pI->tx != 0) + pI->tx_ifc->release (pI->tx); + if (pI->segment_alloc != 0 && pI->user_segment_alloc == 0) + pI->segment_alloc_ifc->release (&pI->segment_alloc); + diva_os_free (0, pI); + } + + return (DivaStreamingIdiResultOK); +} + +static diva_streaming_idi_result_t diva_stream_manager_release_stream (struct _diva_stream* ifc) { + if (ifc != 0) { + diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); + + return (pI->tx_ifc->release_stream (pI->tx)); + } + + return (DivaStreamingIdiResultError); +} + +static diva_streaming_idi_result_t diva_stream_manager_write (struct _diva_stream* ifc, dword message, const void* data, dword length) { + diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); + + return (pI->tx_ifc->write_message (pI->tx, message, data, length)); +} + +static diva_streaming_idi_result_t diva_stream_manager_wakeup (struct _diva_stream* ifc) { + diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); + + return (pI->rx_ifc->wakeup (pI->rx)); +} + +const byte* diva_stream_manager_description (struct _diva_stream* ifc) { + diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); + byte length = 4, len_tx, len_rx; + + len_tx = pI->tx_ifc->description (pI->tx, &pI->description[length], sizeof(pI->description)-length); + + if (len_tx != 0) { + length += len_tx; + len_rx = pI->rx_ifc->description (pI->rx, &pI->description[length], sizeof(pI->description)-length); + if (len_rx != 0) { + length += len_rx; + pI->description[0] = length-1; /* Structure length */ + pI->description[1] = 0; /* Request */ + pI->description[2] = len_rx+len_tx+1; /* Structure length */ + pI->description[3] = 0; /* Version */ + + DBG_TRC(("description length %u [%s]", length, pI->trace_ident)) + DBG_BLK(((void*)pI->description, length)) + + return (&pI->description[0]); + } + } + + return (0); +} + +static diva_streaming_idi_result_t diva_stream_manager_sync_req (struct _diva_stream* ifc, dword ident) { + diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); + + return (pI->tx_ifc->sync (pI->tx, ident)); +} + +static diva_streaming_idi_result_t diva_stream_flush (struct _diva_stream* ifc) { + diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); + + return (pI->tx_ifc->update_remote (pI->tx) == 0 ? DivaStreamingIdiResultOK : DivaStreamingIdiResultError); +} + +static dword diva_stream_get_tx_free (struct _diva_stream* ifc) { + diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); + + return (pI->tx_ifc->get_free (pI->tx)); +} + +static dword diva_stream_get_tx_in_use (struct _diva_stream* ifc) { + diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); + + return (pI->tx_ifc->get_in_use (pI->tx)); +} + +static void diva_notify_os_resource_removed (struct _diva_stream* ifc) { + diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); + + if (pI->segment_alloc != 0) { + pI->segment_alloc_ifc->resource_removed (pI->segment_alloc); + } +} + +dword diva_streaming_read_vector_data (const diva_streaming_vector_t* v, int nr_v, dword *vector_offset, dword *vector_position, byte* dst, dword length) { + dword to_copy; + dword count; + + for (count = 0; vector_offset[0] < ((dword)nr_v) && length != 0;) { + to_copy = MIN((v[vector_offset[0]].length - vector_position[0]), length); + if (dst != 0) { + const byte* tmp = v[vector_offset[0]].data; + memcpy (dst, &tmp[vector_position[0]], to_copy); + dst += to_copy; + } + length -= to_copy; + count += to_copy; + if (v[vector_offset[0]].length == vector_position[0]+to_copy) { + vector_offset[0]++; + vector_position[0]=0; + } else { + vector_position[0] += to_copy; + } + } + + return (count); +} + + +dword diva_streaming_get_indication_data (dword handle, dword message, dword length, const diva_streaming_vector_t* v, int nr_v, byte* pInd, diva_streaming_vector_t* vind, int *pvind_nr) { + dword vector_offset = (byte)handle; + dword vector_position = handle >> 8; + byte Ind = (byte)(message >> 8); + byte header[4]; + dword indication_data_length; + int dst_nr_v = *pvind_nr; + int i; + + if ((Ind & 0x0f) == 8 /* N_DATA */) { + *pInd = Ind; + for (i = 0; i < nr_v; i++) { + vind[i] = v[i]; + } + *pvind_nr = nr_v; + return (0); + } + +/* + Combined indication + data[0] = Ind; + data[1] = IndCh; + data[2] = (byte)length; + data[3] = (byte)(length >> 8); + */ + if (vector_offset >= ((dword)nr_v) || vector_position >= v[vector_offset].length) { + DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__)) + *pInd = 0; + return (0); + } + { + const byte* tmp = v[vector_offset].data; + if (tmp[vector_position] == 0) { + DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__)) + *pInd = 0; + return (0); + } + } + if (diva_streaming_read_vector_data (v, nr_v, &vector_offset, &vector_position, header, sizeof(header)) != sizeof(header)) { + DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__)) + *pInd = 0; + return (0); + } + indication_data_length = ((word)header[2] | (word)header[3] << 8); + + for (i = 0; i < dst_nr_v && indication_data_length != 0; i++) { + const byte* tmp = v[vector_offset].data; + vind[i].data = &tmp[vector_position]; + vind[i].length = MIN((v[vector_offset].length - vector_position), indication_data_length); + *pvind_nr = i + 1; + + indication_data_length -= vind[i].length; + + if (diva_streaming_read_vector_data (v, nr_v, &vector_offset, &vector_position, 0, vind[i].length) != vind[i].length) { + DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__)) + *pInd = 0; + return (0); + } + } + if (indication_data_length != 0) { + DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__)) + *pInd = 0; + return (0); + } + + *pInd = header[0]; + + { + const byte* tmp = v[vector_offset].data; + if (tmp[vector_position] == 0) { + return (0); + } + } + + return (vector_offset | (vector_position << 8)); +} + diff --git a/divastreaming/diva_streaming_manager.h b/divastreaming/diva_streaming_manager.h new file mode 100644 index 0000000..9243df0 --- /dev/null +++ b/divastreaming/diva_streaming_manager.h @@ -0,0 +1,82 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __DIVA_STREAMING_MANAGER_H__ +#define __DIVA_STREAMING_MANAGER_H__ + +struct _diva_streaming_vector; +struct _diva_segment_alloc; + +typedef struct _diva_stream { + diva_streaming_idi_result_t (*release)(struct _diva_stream* ifc); /**< destroy stream */ + diva_streaming_idi_result_t (*release_stream)(struct _diva_stream* ifc); /**< destroy stream */ + diva_streaming_idi_result_t (*write)(struct _diva_stream* ifc, dword message, const void* data, dword length); /**< write data to stream */ + diva_streaming_idi_result_t (*wakeup)(struct _diva_stream* ifc); + const byte* (*description)(struct _diva_stream* ifc); + diva_streaming_idi_result_t (*sync)(struct _diva_stream* ifc, dword ident); + diva_streaming_idi_result_t (*flush_stream)(struct _diva_stream* ifc); + dword (*get_tx_free)(struct _diva_stream* ifc); + dword (*get_tx_in_use)(struct _diva_stream* ifc); + void (*notify_os_resource_removed)(struct _diva_stream* ifc); +} diva_stream_t; + +/* + Message field length one byte + */ +#define DIVA_STREAM_MESSAGE_TX_DATA 0x00000000 /** Tx data */ +#define DIVA_STREAM_MESSAGE_TX_DATA_ACK 0x00000001 /** Tx data with ack */ +#define DIVA_STREAM_MESSAGE_TX_IDI_REQUEST 0x00000002 /** Tx IDI request, request is passed in bits 8...15 */ + +#define DIVA_STREAM_MESSAGE_RX_DATA 0x00000000 /** Received data */ +#define DIVA_STREAM_MESSAGE_RX_TX_FREE 0x00000001 /** Tx space available */ +#define DIVA_STREAM_MESSAGE_RX_TX_ACK 0x00000002 /** Received Tx Ack message */ +#define DIVA_STREAM_MESSAGE_INIT 0x00000003 /** Stream init complete */ +#define DIVA_STREAM_MESSAGE_SYNC_ACK 0x00000004 /** Received stream sync ack */ +#define DIVA_STREAM_MESSAGE_RELEASE_ACK 0x00000005 /** Received stream release acknowledge */ +#define DIVA_STREAM_MESSAGE_INIT_ERROR 0x00000007 /** Stream init error */ +#define DIVA_STREAM_MESSAGE_RELEASED 0x00000008 /** Not message, used internally */ + + +diva_streaming_idi_result_t diva_stream_create_with_user_segment_alloc (struct _diva_stream** ifc, + void* os_context, + dword length, + diva_streaming_idi_rx_notify_user_proc_t rx, + void* rx_context, + const char* trace_ident, + struct _diva_segment_alloc* user_segment_alloc); +diva_streaming_idi_result_t diva_stream_create (struct _diva_stream** ifc, + void* os_context, + dword length, + diva_streaming_idi_rx_notify_user_proc_t rx, + void* rx_context, + const char* trace_ident); + +dword diva_streaming_read_vector_data (const diva_streaming_vector_t* v, int nr_v, dword *vector_offset, dword *vector_position, byte* dst, dword length); +dword diva_streaming_get_indication_data (dword handle, dword message, dword length, const diva_streaming_vector_t* v, int nr_v, byte* pInd, diva_streaming_vector_t* vind, int *pvind_nr); + + + + + +#endif diff --git a/divastreaming/diva_streaming_messages.c b/divastreaming/diva_streaming_messages.c new file mode 100644 index 0000000..9686231 --- /dev/null +++ b/divastreaming/diva_streaming_messages.c @@ -0,0 +1,71 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include "platform.h" +#include "pc.h" +#include "diva_streaming_messages.h" + +int diva_streaming_idi_supported_ind (byte idiInd, dword length, const byte* data) { + byte Ind = idiInd & 0x0f; + + if (likely(Ind == N_DATA)) + return (1); + + if (Ind == N_UDATA && length != 0) { + switch (*data) { + case UDATA_INDICATION_DTMF_DIGITS_SENT: + case UDATA_INDICATION_DTMF_DIGITS_RECEIVED: + case UDATA_INDICATION_MIXER_TAP_DATA: + case UDATA_INDICATION_RTCP_PACKET: + case UDATA_INDICATION_RTCP_GENERATED: + case UDATA_INDICATION_RTCP_ACCEPTED: + case UDATA_INDICATION_FEC_PACKET: + return (1); + } + } + + return (0); +} + +int diva_streaming_idi_supported_req (byte idiReq, dword length, const byte* data) { + byte Req = idiReq & 0x0f; + + if (likely(Req == N_DATA)) + return (1); + + if (Req == N_UDATA && length != 0) { + switch (*data) { + case UDATA_REQUEST_SEND_DTMF_DIGITS: + case UDATA_REQUEST_MIXER_TAP_DATA: + case UDATA_REQUEST_RTCP_PACKET: + case UDATA_REQUEST_RTCP_GENERATE: + case UDATA_REQUEST_RTCP_ACCEPT: + case UDATA_REQUEST_FEC_PACKET: + return (1); + } + } + + return (0); +} + diff --git a/divastreaming/diva_streaming_messages.h b/divastreaming/diva_streaming_messages.h new file mode 100644 index 0000000..5fd8318 --- /dev/null +++ b/divastreaming/diva_streaming_messages.h @@ -0,0 +1,101 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __DIVA_STREAMING_MESSAGES_H__ +#define __DIVA_STREAMING_MESSAGES_H__ + +/* + * Tx direction (to IDI) + */ +#define DIVA_STREAMING_IDI_SYSTEM_MESSAGE 0x80000000U +#define DIVA_STREAMING_IDI_RX_ACK_MSG 0x02 /* Ack processed by host data */ +#define DIVA_STREAMING_IDI_SYNC_REQ 0x03 /* Sync request */ +#define DIVA_STREAMING_IDI_RELEASE 0x04 /* Release stream */ +#define DIVA_STREAMING_IDI_SET_DEBUG_IDENT 0x05 /* Set debug ident */ +#define DIVA_STREAMING_IDI_TX_REQUEST 0x07 + + +/* + * Rx direction (to host) + */ +#define DIVA_STREAMING_IDI_TX_INIT_MSG 0x01 /* Init message, created version, counter address */ +#define DIVA_STREAMING_IDI_TX_INIT_MSG_LENGTH 15 +#define DIVA_STREAMING_IDI_TX_ACK_MSG 0x02 /* Ack processed by tx data */ +#define DIVA_STREAMING_IDI_TX_ACK_MSG_LENGTH 0x09 +#define DIVA_STREAMING_IDI_TX_SYNC_ACK 0x03 /* Sync request acknowledge */ +#define DIVA_STREAMING_IDI_TX_SYNC_ACK_LENGTH 0x0a +#define DIVA_STREAMING_IDI_RELEASE_ACK 0x04 +#define DIVA_STREAMING_IDI_RELEASE_ACK_LENGTH 0x08 +#define DIVA_STREAMING_IDI_TX_INIT_ERROR 0x05 +#define DIVA_STREAMING_IDI_TX_INIT_ERROR_LENGTH 0x0a + + +#ifndef UDATA_REQUEST_SEND_DTMF_DIGITS +#define UDATA_REQUEST_SEND_DTMF_DIGITS 16 +#endif +#ifndef UDATA_INDICATION_DTMF_DIGITS_SENT +#define UDATA_INDICATION_DTMF_DIGITS_SENT 16 +#endif +#ifndef UDATA_INDICATION_DTMF_DIGITS_RECEIVED +#define UDATA_INDICATION_DTMF_DIGITS_RECEIVED 17 +#endif + +#ifndef UDATA_REQUEST_MIXER_TAP_DATA +#define UDATA_REQUEST_MIXER_TAP_DATA 27 +#endif +#ifndef UDATA_INDICATION_MIXER_TAP_DATA +#define UDATA_INDICATION_MIXER_TAP_DATA 27 +#endif + +#ifndef UDATA_REQUEST_RTCP_PACKET +#define UDATA_REQUEST_RTCP_PACKET 67 +#endif +#ifndef UDATA_INDICATION_RTCP_PACKET +#define UDATA_INDICATION_RTCP_PACKET 67 +#endif + +#ifndef UDATA_REQUEST_RTCP_GENERATE +#define UDATA_REQUEST_RTCP_GENERATE 68 +#endif +#ifndef UDATA_INDICATION_RTCP_GENERATED +#define UDATA_INDICATION_RTCP_GENERATED 68 +#endif +#ifndef UDATA_REQUEST_RTCP_ACCEPT +#define UDATA_REQUEST_RTCP_ACCEPT 69 +#endif +#ifndef UDATA_INDICATION_RTCP_ACCEPTED +#define UDATA_INDICATION_RTCP_ACCEPTED 69 +#endif + +#ifndef UDATA_REQUEST_FEC_PACKET +#define UDATA_REQUEST_FEC_PACKET 70 +#endif +#ifndef UDATA_INDICATION_FEC_PACKET +#define UDATA_INDICATION_FEC_PACKET 70 +#endif + +int diva_streaming_idi_supported_ind (byte idiInd, dword length, const byte* data); +int diva_streaming_idi_supported_req (byte idiReq, dword length, const byte* data); + +#endif diff --git a/divastreaming/diva_streaming_result.h b/divastreaming/diva_streaming_result.h new file mode 100644 index 0000000..0a06886 --- /dev/null +++ b/divastreaming/diva_streaming_result.h @@ -0,0 +1,36 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __DIVA_STREAMING_RESULT_H__ +#define __DIVA_STREAMING_RESULT_H__ + +typedef enum { + DivaStreamingIdiResultOK = 0, + DivaStreamingIdiResultError = -1, + DivaStreamingIdiResultBusy = -2 +} diva_streaming_idi_result_t; + + +#endif + diff --git a/divastreaming/diva_streaming_vector.h b/divastreaming/diva_streaming_vector.h new file mode 100644 index 0000000..ddb502c --- /dev/null +++ b/divastreaming/diva_streaming_vector.h @@ -0,0 +1,36 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __DIVA_STREAMING_VECTOR_H__ +#define __DIVA_STREAMING_VECTOR_H__ + +typedef struct _diva_streaming_vector { + const void* data; + dword length; +} diva_streaming_vector_t; + +typedef int (*diva_streaming_idi_rx_notify_user_proc_t)(void* user_context, dword message, dword length, const struct _diva_streaming_vector* v, dword nr_v); + +#endif + diff --git a/divastreaming/segment_alloc.c b/divastreaming/segment_alloc.c new file mode 100644 index 0000000..137a994 --- /dev/null +++ b/divastreaming/segment_alloc.c @@ -0,0 +1,382 @@ +/* + * + Copyright (c) Dialogic (R) 2009 - 2010 + * + This source file is supplied for the use with + Eicon Networks range of DIVA Server Adapters. + * + Dialogic (R) File Revision : 1.9 + * + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + * + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + * + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + * vim:ts=2: + */ +#include "platform.h" +#include "dlist.h" +#include "diva_segment_alloc_ifc.h" +#ifdef DIVA_USERMODE +#include "xdi_msg.h" +#else +#include "pc.h" +#include "di_defs.h" +#include "divasync.h" +#endif +#include "debuglib.h" + +#if defined(LINUX) && defined(DIVA_USERMODE) +#include +#include +#include +#include +#include +#endif + +typedef struct _diva_map_entry { + diva_entity_link_t link; + int entry_nr; + dword dma_lo; + dword dma_hi; + void* mem; +} diva_map_entry_t; + +typedef struct _diva_segment_alloc { + diva_segment_alloc_access_t ifc; +#if defined(DIVA_USERMODE) +#if defined(LINUX) + int fd; + int fd_mem; +#endif +#else + DESCRIPTOR* d; +#endif + diva_entity_queue_t free_q; + diva_entity_queue_t busy_q; + IDI_SYNC_REQ syncReq; +} diva_segment_alloc_t; + +/* + * LOCALS + */ +static void release_proc(struct _diva_segment_alloc**); +static void* segment_alloc_proc(struct _diva_segment_alloc*, dword* lo, dword* hi); +static void segment_free_proc(struct _diva_segment_alloc*, void* addr, dword lo, dword hi); +static dword get_segment_length_proc(struct _diva_segment_alloc*); +#if defined(DIVA_USERMODE) +static int map_entry (struct _diva_segment_alloc* pI, diva_map_entry_t* pE); +#endif +static void* map_address (struct _diva_segment_alloc* ifc, dword lo, dword hi); +static void* umap_address (struct _diva_segment_alloc* ifc, dword lo, dword hi, void* local); +static int write_address (struct _diva_segment_alloc* ifc, dword lo, dword hi, dword data); +static void resource_removed (struct _diva_segment_alloc* ifc); + +#if !defined(DIVA_USERMODE) +static void diva_segment_allloc_resource_removed_request(ENTITY* e) { } +static DESCRIPTOR diva_segment_alloc_resource_removed_descriptor = + { 0, 0, 0, diva_segment_allloc_resource_removed_request }; +#endif + +static diva_segment_alloc_access_t ifc_ref = { + release_proc, + segment_alloc_proc, + segment_free_proc, + get_segment_length_proc, + map_address, + umap_address, + write_address, + resource_removed +}; + +int diva_create_segment_alloc (void* os_context, struct _diva_segment_alloc** segment_alloc) +{ + diva_segment_alloc_t* pI = diva_os_malloc(0, sizeof(*pI)); + + if (pI != 0) { + memset (pI, 0x00, sizeof(*pI)); + + pI->ifc = ifc_ref; + + diva_q_init (&pI->free_q); + diva_q_init (&pI->busy_q); + +#if defined(DIVA_USERMODE) /* { */ +#if defined(LINUX) /* { */ + pI->fd = open ("/dev/DivasMAP", O_RDWR | O_NONBLOCK); /** \todo use hardware related DMA entry, needs update of XDI driver */ + pI->fd_mem = open ("/dev/mem", O_RDWR | O_NONBLOCK); + + if (pI->fd >= 0 && pI->fd_mem >= 0) { + *segment_alloc = pI; + } else { + diva_destroy_segment_alloc (&pI); + pI = 0; + } +#endif /* } */ +#else /* } { */ + pI->d = (DESCRIPTOR*)os_context; + *segment_alloc = pI; +#endif /* } */ + } + + if (pI != 0) { + DBG_LOG(("created segment alloc [%p]", pI)) + } + + return ((pI != 0) ? 0 : -1); +} + +int diva_destroy_segment_alloc (struct _diva_segment_alloc** segment_alloc) { + diva_segment_alloc_t* pI = (segment_alloc != 0) ? *segment_alloc : 0; + + DBG_TRC(("destroy segment alloc [%p]", segment_alloc)) + + if (pI != 0) { + diva_entity_link_t* link; + + while ((link = diva_q_get_head (&pI->busy_q)) != 0) { + diva_q_remove (&pI->busy_q, link); + diva_q_add_tail (&pI->free_q, link); + } + + while ((link = diva_q_get_head (&pI->free_q)) != 0) { + diva_map_entry_t* pE = DIVAS_CONTAINING_RECORD(link, diva_map_entry_t, link); +#if defined(DIVA_USERMODE) +#if defined(LINUX) + munmap (pE->mem, 4*1024); +#endif +#else + pI->syncReq.diva_xdi_streaming_mapping_req.Req = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.Rc = IDI_SYNC_REQ_PROCESS_STREAMING_MAPPING; + pI->syncReq.diva_xdi_streaming_mapping_req.info.request = IDI_SYNC_REQ_PROCESS_STREAMING_MAPPING_FREE_COMMAND; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_lo = pE->dma_lo; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_hi = pE->dma_hi; + pI->syncReq.diva_xdi_streaming_mapping_req.info.addr = pE->mem; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_handle = pE->entry_nr; + pI->d->request((ENTITY*)&pI->syncReq); +#endif + diva_q_remove (&pI->free_q, link); + diva_os_free (0, pE); + } + +#if defined(DIVA_USERMODE) +#if defined(LINUX) + if (pI->fd >= 0) + close (pI->fd); + if (pI->fd_mem == 0) + close (pI->fd_mem); +#endif +#else + +#endif + + + diva_os_free (0, pI); + + *segment_alloc = 0; + } + + return (0); +} + +void release_proc(struct _diva_segment_alloc** pI) { + diva_destroy_segment_alloc (pI); +} + +void* segment_alloc_proc(struct _diva_segment_alloc* pI, dword* lo, dword* hi) { + diva_entity_link_t* link = diva_q_get_head(&pI->free_q); + void* addr = 0; + + if (link != 0) { + diva_map_entry_t* pE = DIVAS_CONTAINING_RECORD(link, diva_map_entry_t, link); + + diva_q_remove (&pI->free_q, link); + diva_q_add_tail (&pI->busy_q, link); + + *lo = pE->dma_lo; + *hi = pE->dma_hi; + + return (pE->mem); + } else if ((link = diva_os_malloc (0, sizeof(diva_map_entry_t))) != 0) { + diva_map_entry_t* pE = (diva_map_entry_t*)link; +#if defined(DIVA_USERMODE) +#if defined(LINUX) + dword data[5]; + int ret; + + data[0] = DIVA_XDI_UM_CMD_CREATE_XDI_DESCRIPTORS; + data[1] = 1; + + write (pI->fd, data, 2*sizeof(dword)); + ret = read (pI->fd, data, sizeof(data)); + if (ret == sizeof(data) || ret == (sizeof(data)-sizeof(data[0]))) { + if (data[0] == DIVA_XDI_UM_CMD_CREATE_XDI_DESCRIPTORS && data[1] == 1) { + pE->dma_lo = data[3]; + pE->dma_hi = (data[2] == 8) ? data[4] : 0; + if (map_entry(pI, pE) == 0) { + diva_q_add_tail (&pI->busy_q, &pE->link); + *lo = pE->dma_lo; + *hi = pE->dma_hi; + addr = pE->mem; + } else { + diva_os_free (0, pE); + } + } + } +#endif +#else + pI->syncReq.diva_xdi_streaming_mapping_req.Req = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.Rc = IDI_SYNC_REQ_PROCESS_STREAMING_MAPPING; + pI->syncReq.diva_xdi_streaming_mapping_req.info.request = IDI_SYNC_REQ_PROCESS_STREAMING_MAPPING_ALLOC_COMMAND; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_lo = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_hi = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.info.addr = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_handle = -1; + pI->d->request((ENTITY*)&pI->syncReq); + if (pI->syncReq.diva_xdi_streaming_mapping_req.info.request == IDI_SYNC_REQ_PROCESS_STREAMING_COMMAND_OK && + pI->syncReq.diva_xdi_streaming_mapping_req.info.addr != 0) { + pE->entry_nr = pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_handle; + pE->dma_lo = pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_lo; + pE->dma_hi = pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_hi; + pE->mem = pI->syncReq.diva_xdi_streaming_mapping_req.info.addr; + + *lo = pE->dma_lo; + *hi = pE->dma_hi; + addr = pE->mem; + + memset (addr, 0x00, 4*1024); + + diva_q_add_tail (&pI->busy_q, &pE->link); + } else { + diva_os_free (0, pE); + } +#endif + } + + return (addr); +} + +#if defined(DIVA_USERMODE) +static int map_entry (struct _diva_segment_alloc* pI, diva_map_entry_t* pE) { + void* addr; + + if (pE->dma_hi != 0) { + qword i = ((qword)pE->dma_lo) | (((qword)pE->dma_hi) << 32); +#if defined(LINUX) + addr = mmap (0, 4*1024, PROT_READ|PROT_WRITE, MAP_SHARED, pI->fd, i); +#endif + } else { +#if defined(LINUX) + addr = mmap (0, 4*1024, PROT_READ|PROT_WRITE, MAP_SHARED, pI->fd, pE->dma_lo); +#endif + } + if (addr == 0 || addr == ((void*)-1)) { + DBG_ERR(("failed to map %08x:%08x [%p]", pE->dma_lo, pE->dma_hi, pI)) + + return (-1); + } + + pE->mem = addr; + + return (0); +} +#endif + +static void* map_address (struct _diva_segment_alloc* pI, dword lo, dword hi) { + void* ret = 0; + +#if defined(DIVA_USERMODE) +#if defined(LINUX) + qword addr = ((qword)lo) | (((qword)hi) << 32); + + ret = mmap (0, 4*1024, PROT_READ|PROT_WRITE, MAP_SHARED, pI->fd_mem, addr); + if (ret == ((void*)-1)) { + ret = 0; + } +#endif +#else + pI->syncReq.diva_xdi_streaming_mapping_req.Req = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.Rc = IDI_SYNC_REQ_PROCESS_STREAMING_MAPPING; + pI->syncReq.diva_xdi_streaming_mapping_req.info.request = IDI_SYNC_REQ_PROCESS_STREAMING_SYSTEM_MAP_COMMAND; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_lo = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_hi = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.info.addr = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_handle = -1; + pI->d->request((ENTITY*)&pI->syncReq); + if (pI->syncReq.diva_xdi_streaming_mapping_req.info.request == IDI_SYNC_REQ_PROCESS_STREAMING_COMMAND_OK) { + byte* p = pI->syncReq.diva_xdi_streaming_mapping_req.info.addr; + dword offset = lo - pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_lo; + + pI->syncReq.diva_xdi_streaming_mapping_req.info.addr = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_lo = 0; + pI->syncReq.diva_xdi_streaming_mapping_req.info.dma_hi = 0; + + ret = p + offset; + } +#endif + + return (ret); +} + +static void* umap_address (struct _diva_segment_alloc* ifc, dword lo, dword hi, void* local) { +#if defined(DIVA_USERMODE) +#if defined(LINUX) + munmap (local, 4*1024); +#endif +#else + +#endif + + return (0); +} + +static int write_address (struct _diva_segment_alloc* ifc, dword lo, dword hi, dword data) { + DBG_ERR(("%s %s at %d", __FILE__, "write_address", __LINE__)) + + return (-1); +} + +static void resource_removed (struct _diva_segment_alloc* pI) { +#if defined(DIVA_USERMODE) + +#else + pI->d = &diva_segment_alloc_resource_removed_descriptor; +#endif +} + +void segment_free_proc(struct _diva_segment_alloc* pI, void* addr, dword lo, dword hi) { + diva_entity_link_t* link; + + for (link = diva_q_get_head(&pI->busy_q); link != 0; link = diva_q_get_next(link)) { + diva_map_entry_t* pE = DIVAS_CONTAINING_RECORD(link, diva_map_entry_t, link); + + if (pE->mem == addr && pE->dma_lo == lo && pE->dma_hi == hi) { + diva_q_remove (&pI->busy_q, link); + diva_q_add_tail (&pI->free_q, link); + return; + } + } + + DBG_ERR(("segment not found: %p %08x:%08x [%p]", addr, lo, hi, pI)) +} + +dword get_segment_length_proc(struct _diva_segment_alloc* pI) { + return (4*1024); +} + +diva_segment_alloc_access_t* diva_get_segment_alloc_ifc (struct _diva_segment_alloc* segment_alloc) { + return ((segment_alloc != 0) ? &segment_alloc->ifc : 0); +} + +