Diva streaming library

This commit is contained in:
MelwareDE 2010-04-06 14:42:45 +00:00
parent aa71b0c410
commit a3c2bd09b2
13 changed files with 2170 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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));
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#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);
}