3 * - By John Hodge (thePowersGang)
11 #include "udi_internal.h"
13 * LOCK_CHANNELS - Prevents
15 #define LOCK_CHANNELS 1
17 struct sUDI_ChannelSide {
18 struct sUDI_Channel *BackPtr;
19 tUDI_DriverInstance *Instance;
20 udi_index_t MetaOpsNum;
25 typedef struct sUDI_Channel
27 tUDI_MetaLang *MetaLang;
29 struct sUDI_ChannelSide Side[2];
33 udi_channel_t UDI_CreateChannel_Blank(tUDI_MetaLang *metalang)
35 tUDI_Channel *ret = NEW(tUDI_Channel,);
37 ret->MetaLang = metalang;
38 ret->Side[0].BackPtr = ret;
39 ret->Side[1].BackPtr = ret;
41 return (udi_channel_t)&ret->Side[0].BackPtr;
44 struct sUDI_ChannelSide *UDI_int_ChannelGetSide(udi_channel_t channel, bool other_side)
46 tUDI_Channel *ch = *(tUDI_Channel**)channel;
49 int side_idx = (channel == (udi_channel_t)&ch->Side[0].BackPtr) ? 0 : 1;
51 side_idx = 1 - side_idx;
53 LOG("side_idx = %i, other_side=%b", side_idx, other_side);
55 return &ch->Side[side_idx];
58 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)
60 struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(channel, other_side);
61 side->Instance = inst;
62 side->Context = context;
63 side->MetaOpsNum = meta_ops_num;
68 int UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t ops_idx, udi_index_t region)
70 tUDI_Channel *ch = *(tUDI_Channel**)channel;
72 tUDI_DriverRegion *rgn = inst->Regions[region];
74 udi_ops_init_t *ops = UDI_int_GetOps(inst, ops_idx);
76 Log_Warning("UDI", "Ops ID invalid for '%s' (%i)", inst->Module, ops_idx);
80 tUDI_MetaLang *ops_ml = UDI_int_GetMetaLang(inst, ops->meta_idx);
81 if( ops_ml != ch->MetaLang ) {
82 Log_Warning("UDI", "Attempt by %s to bind with mismatched channel '%s' op '%s' channel",
83 inst->Module, ops_ml->Name, ch->MetaLang->Name);
88 if( ops->chan_context_size ) {
89 context = malloc( ops->chan_context_size );
90 ((udi_chan_context_t*)context)->rdata = rgn->InitContext;
93 context = rgn->InitContext;
96 UDI_BindChannel_Raw(channel, other_side, inst, ops->meta_ops_num, context, ops->ops_vector);
100 tUDI_DriverInstance *UDI_int_ChannelGetInstance(udi_cb_t *gcb, bool other_side)
103 ASSERT(gcb->channel);
104 tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
107 struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(gcb->channel, other_side);
109 return side->Instance;
113 * \brief Prepare a cb for a channel call
114 * \param gcb Generic control block for this request
115 * \param metalang UDI metalanguage (used for validation)
116 * \return Pointer to ops list
117 * \retval NULL Metalangage validation failed
119 * Updates the channel and context fields of the gcb, checks the metalanguage and returns
120 * the handler list for the other end of the channel.
122 const void *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, tUDI_MetaLang *metalang, udi_index_t meta_ops_num)
125 ASSERT(gcb->channel);
126 tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
129 // TODO: Allow calls without auto-lock
132 Log_Warning("UDI", "Channel %s:%i used while blocked (before handler was fired)",
133 ch->MetaLang->Name, meta_ops_num);
139 struct sUDI_ChannelSide *newside = UDI_int_ChannelGetSide(gcb->channel, true);
140 if( metalang == NULL )
142 if( ch->MetaLang == &cMetaLang_Management ) {
143 Log_Warning("UDI", "Invalid udi_channel_event_ind on Management metalang");
149 if( ch->MetaLang != metalang || newside->MetaOpsNum != meta_ops_num ) {
150 Log_Warning("UDI", "Metalanguage mismatch %s:%i req != %s:%i ch",
151 metalang->Name, meta_ops_num,
152 ch->MetaLang->Name, newside->MetaOpsNum);
157 gcb->channel = (udi_channel_t)&newside->BackPtr;
158 gcb->context = newside->Context;
159 if( !newside->Ops ) {
160 Log_Warning("UDI", "Target end of %p(%s:%i) is unbound",
161 ch, ch->MetaLang->Name, newside->MetaOpsNum);
166 void UDI_int_ChannelFlip(udi_cb_t *gcb)
169 ASSERT(gcb->channel);
170 tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
173 struct sUDI_ChannelSide *newside = UDI_int_ChannelGetSide(gcb->channel, true);
175 gcb->channel = (udi_channel_t)&newside->BackPtr;
176 gcb->context = newside->Context;
179 void UDI_int_ChannelReleaseFromCall(udi_cb_t *gcb)
183 ASSERT(gcb->channel);
184 tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
186 Log_Error("UDI", "Channel pointer of cb %p is NULL", gcb);