3 * - By John Hodge (thePowersGang)
11 #include "udi_internal.h"
12 #define LOCK_CHANNELS 1
14 struct sUDI_ChannelSide {
15 struct sUDI_Channel *BackPtr;
16 udi_index_t MetaOpsNum;
21 typedef struct sUDI_Channel
23 tUDI_MetaLang *MetaLang;
25 struct sUDI_ChannelSide Side[2];
29 udi_channel_t UDI_CreateChannel_Blank(tUDI_MetaLang *metalang)
31 tUDI_Channel *ret = NEW(tUDI_Channel,);
33 ret->MetaLang = metalang;
34 ret->Side[0].BackPtr = ret;
35 ret->Side[1].BackPtr = ret;
37 return (udi_channel_t)&ret->Side[0].BackPtr;
40 struct sUDI_ChannelSide *UDI_int_ChannelGetSide(udi_channel_t channel, bool other_side)
42 tUDI_Channel *ch = *(tUDI_Channel**)channel;
45 int side_idx = (channel == (udi_channel_t)&ch->Side[0].BackPtr) != other_side;
47 return &ch->Side[side_idx];
50 int UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, udi_index_t meta_ops_num, void *context, const void *ops)
52 struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(channel, other_side);
53 side->Context = context;
54 side->MetaOpsNum = meta_ops_num;
59 int UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t ops_idx, udi_index_t region)
61 tUDI_Channel *ch = *(tUDI_Channel**)channel;
63 tUDI_DriverRegion *rgn = inst->Regions[region];
65 udi_ops_init_t *ops = UDI_int_GetOps(inst, ops_idx);
67 Log_Warning("UDI", "Ops ID invalid for '%s' (%i)", inst->Module, ops_idx);
71 tUDI_MetaLang *ops_ml = UDI_int_GetMetaLang(inst, ops->meta_idx);
72 if( ops_ml != ch->MetaLang ) {
73 Log_Warning("UDI", "Attempt by %s to bind with mismatched channel '%s' op '%s' channel",
74 inst->Module, ops_ml->Name, ch->MetaLang->Name);
79 if( ops->chan_context_size ) {
80 context = malloc( ops->chan_context_size );
81 ((udi_chan_context_t*)context)->rdata = rgn->InitContext;
84 context = rgn->InitContext;
87 UDI_BindChannel_Raw(channel, other_side, ops->meta_ops_num, context, ops->ops_vector);
92 * \brief Prepare a cb for a channel call
93 * \param gcb Generic control block for this request
94 * \param metalang UDI metalanguage (used for validation)
95 * \return Pointer to ops list
96 * \retval NULL Metalangage validation failed
98 * Updates the channel and context fields of the gcb, checks the metalanguage and returns
99 * the handler list for the other end of the channel.
101 const void *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, tUDI_MetaLang *metalang, udi_index_t meta_ops_num)
104 ASSERT(gcb->channel);
105 tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
108 // TODO: Allow calls without auto-lock
111 Log_Warning("UDI", "Channel %s:%i used while blocked (before handler was fired)",
112 ch->MetaLang->Name, meta_ops_num);
118 struct sUDI_ChannelSide *newside = UDI_int_ChannelGetSide(gcb->channel, true);
119 if( metalang == NULL )
121 if( ch->MetaLang == &cMetaLang_Management ) {
122 Log_Warning("UDI", "Invalid udi_channel_event_ind on Management metalang");
128 if( ch->MetaLang != metalang || newside->MetaOpsNum != meta_ops_num ) {
129 Log_Warning("UDI", "Metalanguage mismatch %s:%i req != %s:%i ch",
130 metalang->Name, meta_ops_num,
131 ch->MetaLang->Name, newside->MetaOpsNum);
136 gcb->channel = (udi_channel_t)&newside->BackPtr;
137 gcb->context = newside->Context;
138 if( !newside->Ops ) {
139 Log_Warning("UDI", "Target end of %p(%s:%i) is unbound",
140 ch, ch->MetaLang->Name, newside->MetaOpsNum);
145 void UDI_int_ChannelReleaseFromCall(udi_cb_t *gcb)
149 ASSERT(gcb->channel);
150 tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);