Modules/UDI - Working on more framework and PCI bus
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / channels.c
index d232e03..8f96d34 100644 (file)
@@ -9,57 +9,85 @@
 #include <acess.h>
 #include <udi.h>
 #include "udi_internal.h"
+#define LOCK_CHANNELS  1
 
 struct sUDI_ChannelSide {
        struct sUDI_Channel     *BackPtr;
+       udi_index_t     MetaOpsNum;
        const void      *Ops;
        void    *Context;
 };
 
 typedef struct sUDI_Channel
 {
-       enum eUDI_MetaLang      MetaLang;
-       udi_index_t     MetaOpsNum;
+       tUDI_MetaLang   *MetaLang;
+       bool    Locked;
        struct sUDI_ChannelSide  Side[2];
 } tUDI_Channel;
 
 // === CODE ===
-udi_channel_t UDI_CreateChannel(enum eUDI_MetaLang metalang, udi_index_t meta_ops_num,
-       tUDI_DriverInstance *ThisEnd, udi_index_t ThisOpsIndex,
-       tUDI_DriverInstance *OtherEnd, udi_index_t OtherOpsIndex)
+udi_channel_t UDI_CreateChannel_Blank(tUDI_MetaLang *metalang)
 {
        tUDI_Channel    *ret = NEW(tUDI_Channel,);
-       struct {
-               tUDI_DriverInstance     *inst;
-               udi_index_t     ops_index;
-       } ends[2] = {
-               {ThisEnd, ThisOpsIndex},
-               {OtherEnd, OtherOpsIndex}
-       };
+
        ret->MetaLang = metalang;
-       ret->MetaOpsNum = meta_ops_num;
-       for( int i = 0; i < 2; i ++ )
-       {
-               if( !ends[i].inst ) {
-                       continue ;
-               }
-               tUDI_DriverModule       *mod = ends[i].inst->Module;
-               ret->Side[i].BackPtr = ret;
-               udi_ops_init_t  *ops = mod->InitInfo->ops_init_list;;
-               while( ops->ops_idx && ops->ops_idx != ends[i].ops_index )
-                       ops++;
-               ASSERTR(ops->ops_idx, NULL);    // TODO: Pretty error
-               ASSERTCR(ops->meta_idx, <, mod->nMetaLangs, NULL);
-               ASSERTCR(mod->MetaLangs[ops->meta_idx], ==, metalang, NULL);
-               ASSERTCR(ops->meta_ops_num, ==, meta_ops_num, NULL);
-               if( ops->chan_context_size ) {
-                       ret->Side[i].Context = malloc(ops->chan_context_size);
-               }
-               ret->Side[i].Ops = ops->ops_vector;
-       }
+       ret->Side[0].BackPtr = ret;     
+       ret->Side[1].BackPtr = ret;     
+
        return (udi_channel_t)&ret->Side[0].BackPtr;
 }
 
+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;
+}
+
 /**
  * \brief Prepare a cb for a channel call
  * \param gcb  Generic control block for this request
@@ -70,16 +98,59 @@ udi_channel_t UDI_CreateChannel(enum eUDI_MetaLang metalang, udi_index_t meta_op
  * Updates the channel and context fields of the gcb, checks the metalanguage and returns
  * the handler list for the other end of the channel.
  */
-const void *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, enum eUDI_MetaLang metalang, udi_index_t meta_ops_num)
+const void *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, tUDI_MetaLang *metalang, udi_index_t meta_ops_num)
 {
+       ASSERT(gcb);
+       ASSERT(gcb->channel);
        tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
-       ASSERTCR(ch->MetaLang, ==, metalang, NULL);
+       ASSERT(ch);
 
-       struct sUDI_ChannelSide *newside = (gcb->channel == (udi_channel_t)&ch->Side[0].BackPtr ? &ch->Side[1] : &ch->Side[0]);
+       // TODO: Allow calls without auto-lock
+       #if LOCK_CHANNELS
+       if( ch->Locked ) {
+               Log_Warning("UDI", "Channel %s:%i used while blocked (before handler was fired)",
+                       ch->MetaLang->Name, meta_ops_num);
+               return NULL;
+       }       
+       ch->Locked = true;
+       #endif
+       
+       struct sUDI_ChannelSide *newside = UDI_int_ChannelGetSide(gcb->channel, true);
+       if( metalang == NULL )
+       {
+               if( ch->MetaLang == &cMetaLang_Management ) {
+                       Log_Warning("UDI", "Invalid udi_channel_event_ind on Management metalang");
+                       return NULL;
+               }
+       }
+       else
+       {
+               if( ch->MetaLang != metalang || newside->MetaOpsNum != meta_ops_num ) {
+                       Log_Warning("UDI", "Metalanguage mismatch %s:%i req != %s:%i ch",
+                               metalang->Name, meta_ops_num,
+                               ch->MetaLang->Name, newside->MetaOpsNum);
+                       return NULL;
+               }
+       }
 
-//     gcb->initiator_context = gcb->context;
        gcb->channel = (udi_channel_t)&newside->BackPtr;
        gcb->context = newside->Context;
+       if( !newside->Ops ) {
+               Log_Warning("UDI", "Target end of %p(%s:%i) is unbound",
+                       ch, ch->MetaLang->Name, newside->MetaOpsNum);
+       }
        return newside->Ops;
 }
 
+void UDI_int_ChannelReleaseFromCall(udi_cb_t *gcb)
+{
+       #if LOCK_CHANNELS
+       ASSERT(gcb);
+       ASSERT(gcb->channel);
+       tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
+       ASSERT(ch);
+       
+       ch->Locked = false;
+       #endif
+}
+

UCC git Repository :: git.ucc.asn.au