+struct sUDI_ChannelSide *UDI_int_ChannelGetSide(udi_channel_t channel, bool other_side)
+{
+ tUDI_Channel *ch = *(tUDI_Channel**)channel;
+ if(!ch) return NULL;
+
+ int side_idx = (channel == (udi_channel_t)&ch->Side[0].BackPtr) != other_side;
+
+ return &ch->Side[side_idx];
+}
+
+int UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, udi_index_t meta_ops_num, void *context, const void *ops)
+{
+ struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(channel, other_side);
+ 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)
+{
+ tUDI_Channel *ch = *(tUDI_Channel**)channel;
+
+ tUDI_DriverRegion *rgn = inst->Regions[region];
+
+ udi_ops_init_t *ops = UDI_int_GetOps(inst, ops_idx);
+ if( !ops ) {
+ Log_Warning("UDI", "Ops ID invalid for '%s' (%i)", inst->Module, ops_idx);
+ return 1;
+ }
+
+ tUDI_MetaLang *ops_ml = UDI_int_GetMetaLang(inst, 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 );
+ ((udi_chan_context_t*)context)->rdata = rgn->InitContext;
+ }
+ else {
+ context = rgn->InitContext;
+ }
+
+ UDI_BindChannel_Raw(channel, other_side, ops->meta_ops_num, context, ops->ops_vector);
+ return 0;
+}
+