#include <udi.h>
#include "udi_internal.h"
/*
- * LOCK_CHANNELS - Prevents
+ * LOCK_CHANNELS
+ * - Prevents multiple non-dispatched operations on one channel
+ * TODO: This should actually lock the GCB, not the channel
*/
-#define LOCK_CHANNELS 1
+#define LOCK_CHANNELS 0
+/*
+ * TRACE_ENDPOINTS
+ * - Emit a log message with names/indexes of both endpoints
+ */
+#define TRACE_ENDPOINTS 1
+
+#define MAX_SPAWN_IDX 6
struct sUDI_ChannelSide {
struct sUDI_Channel *BackPtr;
tUDI_DriverInstance *Instance;
+ udi_index_t RegionIdx;
udi_index_t MetaOpsNum;
const void *Ops;
+ void *AllocatedContext;
void *Context;
};
tUDI_MetaLang *MetaLang;
bool Locked;
struct sUDI_ChannelSide Side[2];
+ struct sUDI_Channel *SpawnBinds[MAX_SPAWN_IDX];
} tUDI_Channel;
// === CODE ===
return (udi_channel_t)&ret->Side[0].BackPtr;
}
+udi_channel_t UDI_CreateChannel_Linked(udi_channel_t orig, udi_ubit8_t spawn_idx)
+{
+ tUDI_Channel *ch = *(tUDI_Channel**)orig;
+ ASSERT(ch);
+ ASSERTC(spawn_idx, <, MAX_SPAWN_IDX);
+ // TODO: mutex
+ if( ch->SpawnBinds[spawn_idx] ) {
+ tUDI_Channel *ret = ch->SpawnBinds[spawn_idx];
+ ch->SpawnBinds[spawn_idx] = NULL;
+ // TODO: mutex
+ return (udi_channel_t)&ret->Side[1].BackPtr;
+ }
+ udi_channel_t ret = UDI_CreateChannel_Blank( ch->MetaLang );
+ ch->SpawnBinds[spawn_idx] = *(tUDI_Channel**)ret;
+ // TODO: Mutex
+ return ret;
+}
+
struct sUDI_ChannelSide *UDI_int_ChannelGetSide(udi_channel_t channel, bool other_side)
{
tUDI_Channel *ch = *(tUDI_Channel**)channel;
if( other_side )
side_idx = 1 - side_idx;
- LOG("side_idx = %i, other_side=%b", side_idx, other_side);
-
return &ch->Side[side_idx];
}
-int UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t meta_ops_num, void *context, const void *ops)
+int UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t region_idx, udi_index_t meta_ops_num, void *context, const void *ops)
{
struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(channel, other_side);
side->Instance = inst;
+ side->RegionIdx = region_idx;
side->Context = context;
side->MetaOpsNum = meta_ops_num;
side->Ops = ops;
return 0;
}
-int UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t ops_idx, udi_index_t region)
+int UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t ops_idx, udi_index_t region, void *context, bool is_child_bind, udi_ubit32_t child_ID)
{
tUDI_Channel *ch = *(tUDI_Channel**)channel;
return 1;
}
- tUDI_MetaLang *ops_ml = UDI_int_GetMetaLang(inst, ops->meta_idx);
+ tUDI_MetaLang *ops_ml = UDI_int_GetMetaLang(inst->Module, ops->meta_idx);
if( ops_ml != ch->MetaLang ) {
Log_Warning("UDI", "Attempt by %s to bind with mismatched channel '%s' op '%s' channel",
inst->Module, ops_ml->Name, ch->MetaLang->Name);
return 3;
}
- void *context;
- if( ops->chan_context_size ) {
- context = malloc( ops->chan_context_size );
+ if( context ) {
+ // Use provided context pointer
+ LOG("context = provided %p", context);
+ }
+ else if( ops->chan_context_size )
+ {
+ if( is_child_bind )
+ ASSERTCR( ops->chan_context_size, >=, sizeof(udi_child_chan_context_t), 4 );
+ else
+ ASSERTCR( ops->chan_context_size, >=, sizeof(udi_chan_context_t), 4 );
+ context = calloc( 1, ops->chan_context_size );
((udi_chan_context_t*)context)->rdata = rgn->InitContext;
+ if( is_child_bind )
+ ((udi_child_chan_context_t*)context)->child_ID = child_ID;
+ LOG("context = allocated %p", context);
+
+ // TODO: The driver may change the channel context, but this must be freed by the environment
+ UDI_int_ChannelGetSide(channel, other_side)->AllocatedContext = context;
}
else {
context = rgn->InitContext;
+ LOG("context = region %p", context);
}
- UDI_BindChannel_Raw(channel, other_side, inst, ops->meta_ops_num, context, ops->ops_vector);
+ UDI_BindChannel_Raw(channel, other_side, inst, region, ops->meta_ops_num, context, ops->ops_vector);
return 0;
}
-tUDI_DriverInstance *UDI_int_ChannelGetInstance(udi_cb_t *gcb, bool other_side)
+tUDI_DriverInstance *UDI_int_ChannelGetInstance(udi_cb_t *gcb, bool other_side, udi_index_t *region_idx)
{
- ASSERT(gcb);
- ASSERT(gcb->channel);
- tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
- ASSERT(ch);
-
struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(gcb->channel, other_side);
-
+ if(region_idx)
+ *region_idx = side->RegionIdx;
return side->Instance;
}
+void UDI_int_ChannelSetContext(udi_channel_t channel, void *context)
+{
+ struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(channel, false);
+ side->Context = context;
+}
+
/**
* \brief Prepare a cb for a channel call
* \param gcb Generic control block for this request
}
}
+ #if TRACE_ENDPOINTS
+ struct sUDI_ChannelSide *thisside = UDI_int_ChannelGetSide(gcb->channel, false);
+ Log("%s:%i -> %s:%i",
+ (thisside->Instance ? thisside->Instance->Module->ModuleName : "MA"), thisside->RegionIdx,
+ (newside->Instance ? newside->Instance->Module->ModuleName : "MA"), newside->RegionIdx);
+ #endif
+
gcb->channel = (udi_channel_t)&newside->BackPtr;
gcb->context = newside->Context;
if( !newside->Ops ) {