Modules/UDI - Attributes, PIO, CB allocation and channel_spawn
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / channels.c
index c5ad096..6e59594 100644 (file)
 #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 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;
 };
 
@@ -27,6 +33,7 @@ typedef struct sUDI_Channel
        tUDI_MetaLang   *MetaLang;
        bool    Locked;
        struct sUDI_ChannelSide  Side[2];
+       struct sUDI_Channel     *SpawnBinds[MAX_SPAWN_IDX];
 } tUDI_Channel;
 
 // === CODE ===
@@ -41,6 +48,24 @@ udi_channel_t UDI_CreateChannel_Blank(tUDI_MetaLang *metalang)
        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;
@@ -55,17 +80,18 @@ struct sUDI_ChannelSide *UDI_int_ChannelGetSide(udi_channel_t channel, bool othe
        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;
        
@@ -84,31 +110,45 @@ int UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance
                return 3;
        }
 
-       void *context;
-       if( ops->chan_context_size ) {
+       if( context ) {
+               // Use provided context pointer
+       }
+       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 = malloc( 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;
+               
+               // 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;
        }
        
-       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

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