parent
aa71b0c410
commit
a3c2bd09b2
@ -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 |
@ -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 |
@ -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); |
||||
} |
||||
|
@ -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 |
@ -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); |
||||
} |
||||
|
||||
|
@ -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 |
@ -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) { |
||||